Unravel Engine C++ Reference
Loading...
Searching...
No Matches
gizmo_entity.cpp
Go to the documentation of this file.
1#include "gizmo_entity.h"
2#include "gizmos.h"
3#include "glm/ext.hpp"
4
6
12
16#include <hpp/type_name.hpp>
17#include <hpp/utility.hpp>
18
19namespace unravel
20{
21namespace
22{
23auto to_bx(const math::vec3& data) -> bx::Vec3
24{
25 return {data.x, data.y, data.z};
26}
27
28auto from_bx(const bx::Vec3& data) -> math::vec3
29{
30 return {data.x, data.y, data.z};
31}
32
33} // namespace
34
35void gizmo_entity::draw(rtti::context& ctx, entt::meta_any& var, const camera& cam, gfx::dd_raii& dd1)
36{
37 auto e = var.cast<entt::handle>();
38
39 if(!e || !e.all_of<transform_component>())
40 return;
41
42 auto& transform_comp = e.get<transform_component>();
43 const auto& world_transform = transform_comp.get_transform_global();
44
45 gfx::dd_raii dd(dd1.view);
46 if(e.all_of<camera_component>())
47 {
48 auto& selected_camera_comp = e.get<camera_component>();
49 auto& selected_camera = selected_camera_comp.get_camera();
50 const auto view_proj = selected_camera.get_view_projection();
51 const auto bounds = selected_camera.get_local_bounding_box();
53 dd.encoder.setColor(0xffffffff);
54 dd.encoder.setWireframe(true);
56 {
57 dd.encoder.drawFrustum(&view_proj);
58 }
59 else
60 {
61 bx::Aabb aabb;
62 aabb.min = to_bx(bounds.min);
63 aabb.max = to_bx(bounds.max);
64 dd.encoder.pushTransform((const float*)world_transform);
65 dd.encoder.draw(aabb);
67 }
68 }
69
70 if(e.all_of<light_component>())
71 {
72 const auto& light_comp = e.get<light_component>();
73 const auto& light = light_comp.get_light();
74
76 {
77 auto adjacent = light.spot_data.get_range();
78 {
79 auto tan_angle = math::tan(math::radians(light.spot_data.get_outer_angle() * 0.5f));
80 // oposite = tan * adjacent
81 auto oposite = tan_angle * adjacent;
83 dd.encoder.setColor(0xff00ff00);
84 dd.encoder.setWireframe(true);
85 dd.encoder.setLod(3);
86 math::vec3 from = transform_comp.get_position_global();
87 math::vec3 to = from + transform_comp.get_z_axis_local() * adjacent;
88 dd.encoder.drawCone(to_bx(to), to_bx(from), oposite);
89 }
90 {
91 auto tan_angle = math::tan(math::radians(light.spot_data.get_inner_angle() * 0.5f));
92 // oposite = tan * adjacent
93 auto oposite = tan_angle * adjacent;
95 dd.encoder.setColor(0xff00ffff);
96 dd.encoder.setWireframe(true);
97 dd.encoder.setLod(3);
98 math::vec3 from = transform_comp.get_position_global();
99 math::vec3 to = from + transform_comp.get_z_axis_local() * adjacent;
100 dd.encoder.drawCone(to_bx(to), to_bx(from), oposite);
101 }
102 }
103 else if(light.type == light_type::point)
104 {
105 auto radius = light.point_data.range;
107 dd.encoder.setColor(0xff00ff00);
108 dd.encoder.setWireframe(true);
109 math::vec3 center = transform_comp.get_position_global();
110 dd.encoder.drawCircle(Axis::X, center.x, center.y, center.z, radius);
111 dd.encoder.drawCircle(Axis::Y, center.x, center.y, center.z, radius);
112 dd.encoder.drawCircle(Axis::Z, center.x, center.y, center.z, radius);
113 }
115 {
117 dd.encoder.setLod(255);
118 dd.encoder.setColor(0xff00ff00);
119 dd.encoder.setWireframe(true);
120 math::vec3 from1 = transform_comp.get_position_global();
121 math::vec3 to1 = from1 + transform_comp.get_z_axis_local() * 1.0f;
122
123 bx::Cylinder cylinder = {to_bx(from1), to_bx(to1), 0.1f};
124
125 dd.encoder.draw(cylinder);
126 math::vec3 from2 = to1;
127 math::vec3 to2 = from2 + transform_comp.get_z_axis_local() * 0.5f;
128
129 bx::Cone cone = {to_bx(from2), to_bx(to2), 0.25f};
130 dd.encoder.draw(cone);
131 }
132 }
133
134 if(e.all_of<reflection_probe_component>())
135 {
136 const auto& probe_comp = e.get<reflection_probe_component>();
137 const auto& probe = probe_comp.get_probe();
138 if(probe.type == probe_type::box)
139 {
141 dd.encoder.setColor(0xff00ff00);
142 dd.encoder.setWireframe(true);
143 dd.encoder.pushTransform((const float*)world_transform);
144 bx::Aabb aabb;
145 aabb.min = to_bx(-probe.box_data.extents);
146 aabb.max = to_bx(probe.box_data.extents);
147
148 dd.encoder.draw(aabb);
150 }
151 else
152 {
153 auto radius = probe.get_face_extents(0, world_transform);
154 auto transform = world_transform;
155 transform.reset_scale();
156
158 dd.encoder.setColor(0xff00ff00);
159 dd.encoder.setWireframe(true);
160 dd.encoder.pushTransform((const float*)transform);
161 math::vec3 center{};
162 dd.encoder.drawCircle(Axis::X, center.x, center.y, center.z, radius);
163 dd.encoder.drawCircle(Axis::Y, center.x, center.y, center.z, radius);
164 dd.encoder.drawCircle(Axis::Z, center.x, center.y, center.z, radius);
165 }
166 }
167
168 // if(e.all_of<model_component>())
169 // {
170 // const auto& frustum = cam.get_frustum();
171 // const auto& model_comp = e.get<model_component>();
172
173 // // world bounds
174 // {
175 // auto world_bounds = model_comp.get_world_bounds();
176
177 // if(frustum.test_aabb(world_bounds))
178 // {
179 // DebugDrawEncoderScopePush scope(dd.encoder);
180 // dd.encoder.setColor(0xff00ffff);
181 // dd.encoder.setWireframe(true);
182 // bx::Aabb aabb;
183 // aabb.min = to_bx(world_bounds.min);
184 // aabb.max = to_bx(world_bounds.max);
185 // dd.encoder.draw(aabb);
186 // }
187 // }
188
189 // // local bounds
190 // {
191 // const auto& model = model_comp.get_model();
192 // if(!model.is_valid())
193 // {
194 // return;
195 // }
196
197 // const auto lod = model.get_lod(0);
198 // if(!lod)
199 // {
200 // return;
201 // }
202 // const auto& mesh = lod.get();
203 // const auto& bounds = mesh->get_bounds();
204 // // Test the bounding box of the mesh
205 // if(frustum.test_obb(bounds, world_transform))
206 // {
207 // DebugDrawEncoderScopePush scope(dd.encoder);
208 // dd.encoder.setColor(0xffffffff);
209 // dd.encoder.setWireframe(true);
210 // dd.encoder.pushTransform((const float*)world_transform);
211 // bx::Aabb aabb;
212 // aabb.min = to_bx(bounds.min);
213 // aabb.max = to_bx(bounds.max);
214 // dd.encoder.draw(aabb);
215 // dd.encoder.popTransform();
216 // }
217
218 // const auto& submeshes = model_comp.get_armature_entities();
219 // for(const auto& submesh : submeshes)
220 // {
221 // const auto& submesh_comp = submesh.try_get<submesh_component>();
222 // if(!submesh_comp)
223 // {
224 // continue;
225 // }
226 // const auto& submesh_transform_comp = submesh.get<transform_component>();
227 // const auto& submesh_transform = submesh_transform_comp.get_transform_global();
228 // DebugDrawEncoderScopePush scope(dd.encoder);
229 // dd.encoder.setColor(0xffaaaaaa);
230 // dd.encoder.setWireframe(true);
231 // for(const auto submesh_id : submesh_comp->submeshes)
232 // {
233 // const auto& submesh = mesh->get_submesh(submesh_id);
234
235 // if(frustum.test_obb(submesh.bbox, submesh_transform))
236 // {
237 // dd.encoder.pushTransform((const float*)submesh_transform);
238 // bx::Aabb aabb;
239 // aabb.min = to_bx(submesh.bbox.min);
240 // aabb.max = to_bx(submesh.bbox.max);
241 // dd.encoder.draw(aabb);
242 // dd.encoder.popTransform();
243 // }
244 // }
245 // }
246 // }
247 // }
248
249 if(e.all_of<text_component>())
250 {
251 const auto& frustum = cam.get_frustum();
252 const auto& text_comp = e.get<text_component>();
253
254 // world bounds
255 {
256 auto bbox = text_comp.get_bounds();
257
258 if(frustum.test_obb(bbox, world_transform))
259 {
261 dd.encoder.setColor(0xff00ffff);
262 dd.encoder.setWireframe(true);
263 dd.encoder.pushTransform((const float*)world_transform);
264 bx::Aabb aabb;
265 aabb.min = to_bx(bbox.min);
266 aabb.max = to_bx(bbox.max);
267 dd.encoder.draw(aabb);
269 }
270 }
271 }
272
273 if(e.all_of<particle_emitter_component>())
274 {
275 const auto& frustum = cam.get_frustum();
276 const auto& particle_emitter_comp = e.get<particle_emitter_component>();
277
278 // Draw world bounds
279 const auto& bounds = particle_emitter_comp.get_world_bounds();
280 if(frustum.test_aabb(bounds))
281 {
283 dd.encoder.setColor(0xff00ffff);
284 dd.encoder.setWireframe(true);
285 bx::Aabb aabb;
286 aabb.min = to_bx(bounds.min);
287 aabb.max = to_bx(bounds.max);
288 dd.encoder.draw(aabb);
289 }
290
291 // Draw emission shape
292 {
294 dd.encoder.setColor(0xffff8000); // Orange color for emission shape
295 dd.encoder.setWireframe(true);
296 dd.encoder.pushTransform((const float*)world_transform);
297
298 const auto shape = particle_emitter_comp.get_shape();
299 const auto scale = particle_emitter_comp.get_emission_shape_scale();
300 const auto direction = particle_emitter_comp.get_direction();
301 const float shape_size = 1.0f; // Base size for visualization
302
303 switch(shape)
304 {
306 {
307 auto transform = math::scale(math::mat4(1.0f), scale);
308 dd.encoder.pushTransform(math::value_ptr(transform));
309
310 // Draw a wireframe sphere
311 math::vec3 center{0.0f, 0.0f, 0.0f};
312 dd.encoder.drawCircle(Axis::X, center.x, center.y, center.z, shape_size);
313 dd.encoder.drawCircle(Axis::Y, center.x, center.y, center.z, shape_size);
314 dd.encoder.drawCircle(Axis::Z, center.x, center.y, center.z, shape_size);
315
317 break;
318 }
320 {
321 auto transform = math::scale(math::mat4(1.0f), scale);
322 dd.encoder.pushTransform(math::value_ptr(transform));
323
324 // Draw hemisphere (half sphere facing up)
325 math::vec3 center{0.0f, 0.0f, 0.0f};
326
327 // Draw the base circle (full circle at Y=0)
328 dd.encoder.drawCircle(Axis::Y, center.x, center.y, center.z, shape_size);
329
330 // Draw vertical arcs to form the hemisphere dome
331 // Each arc goes from one side of the base circle, over the top, to the other side
332 const int num_arcs = 8; // Number of vertical arcs around the hemisphere
333 for(int i = 0; i < num_arcs; ++i)
334 {
335 const float angle = (3.14159265f * static_cast<float>(i)) / static_cast<float>(num_arcs);
336 const float cos_a = math::cos(angle);
337 const float sin_a = math::sin(angle);
338
339 // Position each arc at a different point around the base circle
340 // and draw a 180-degree arc that goes up and over
341 const float x_pos = cos_a * shape_size;
342 const float z_pos = sin_a * shape_size;
343
344 // Draw arc in the plane that contains the Y axis and the radial direction
345 // We need to use moveTo/lineTo to manually create the hemisphere arcs
346 const int arc_segments = 16;
347 bool first_point = true;
348
349 for(int j = 0; j <= arc_segments; ++j)
350 {
351 const float arc_angle = (3.14159265f * static_cast<float>(j)) / static_cast<float>(arc_segments);
352 const float y = shape_size * math::sin(arc_angle);
353 const float radius_at_height = shape_size * math::cos(arc_angle);
354
355 const float x = cos_a * radius_at_height;
356 const float z = sin_a * radius_at_height;
357
358 if(first_point)
359 {
360 dd.encoder.moveTo(x, y, z);
361 first_point = false;
362 }
363 else
364 {
365 dd.encoder.lineTo(x, y, z);
366 }
367 }
368 }
369
370 // Draw horizontal circles at different heights to show the hemisphere shape
371 const int num_horizontal_circles = 2;
372 for(int i = 1; i <= num_horizontal_circles; ++i)
373 {
374 const float height_ratio = static_cast<float>(i) / static_cast<float>(num_horizontal_circles + 1);
375 const float y_pos = shape_size * height_ratio;
376 const float radius_at_height = shape_size * math::sqrt(1.0f - height_ratio * height_ratio);
377
378 // Draw circles at different heights
379 dd.encoder.drawCircle(Axis::Y, center.x, y_pos, center.z, radius_at_height);
380 }
381
383 break;
384 }
386 {
387 auto transform = math::scale(math::mat4(1.0f), scale);
388 dd.encoder.pushTransform(math::value_ptr(transform));
389
390 // Draw a circle in the XZ plane
391 math::vec3 center{0.0f, 0.0f, 0.0f};
392 dd.encoder.drawCircle(Axis::Y, center.x, center.y, center.z, shape_size);
393
395 break;
396 }
398 {
399 // Draw a box
400 const float half_size = shape_size;
401 bx::Aabb box_aabb;
402 box_aabb.min = {-half_size * scale.x, -half_size * scale.y, -half_size * scale.z};
403 box_aabb.max = {half_size * scale.x, half_size * scale.y, half_size * scale.z};
404 dd.encoder.draw(box_aabb);
405 break;
406 }
408 {
409 // Draw a rectangle in the XZ plane
410 const float half_size = shape_size;
411 bx::Aabb rect_aabb;
412 rect_aabb.min = {-half_size * scale.x, -0.01f, -half_size * scale.z};
413 rect_aabb.max = {half_size * scale.x, 0.01f, half_size * scale.z};
414 dd.encoder.draw(rect_aabb);
415 break;
416 }
417 default:
418 break;
419 }
420
421 // Draw direction indicators
422 dd.encoder.setColor(0xff00ff00); // Green color for direction
423 const float arrow_length = shape_size * 0.5f;
424 const float arrow_head_size = arrow_length * 0.2f;
425
426 switch(direction)
427 {
429 {
430 // Draw upward arrows
431 dd.encoder.moveTo(0.0f, 0.0f, 0.0f);
432 dd.encoder.lineTo(0.0f, arrow_length, 0.0f);
433 // Arrow head
434 dd.encoder.moveTo(0.0f, arrow_length, 0.0f);
435 dd.encoder.lineTo(-arrow_head_size, arrow_length - arrow_head_size, 0.0f);
436 dd.encoder.moveTo(0.0f, arrow_length, 0.0f);
437 dd.encoder.lineTo(arrow_head_size, arrow_length - arrow_head_size, 0.0f);
438 dd.encoder.moveTo(0.0f, arrow_length, 0.0f);
439 dd.encoder.lineTo(0.0f, arrow_length - arrow_head_size, -arrow_head_size);
440 dd.encoder.moveTo(0.0f, arrow_length, 0.0f);
441 dd.encoder.lineTo(0.0f, arrow_length - arrow_head_size, arrow_head_size);
442 break;
443 }
445 {
446 // Draw multiple outward arrows
447 const int num_arrows = 6;
448 for(int i = 0; i < num_arrows; ++i)
449 {
450 const float angle = (2.0f * 3.14159265f * static_cast<float>(i)) / static_cast<float>(num_arrows);
451 const float cos_a = math::cos(angle);
452 const float sin_a = math::sin(angle);
453
454 // Arrow shaft
455 dd.encoder.moveTo(cos_a * shape_size * 0.3f, 0.0f, sin_a * shape_size * 0.3f);
456 dd.encoder.lineTo(cos_a * arrow_length, 0.0f, sin_a * arrow_length);
457
458 // Arrow head
459 const float head_x = cos_a * arrow_length;
460 const float head_z = sin_a * arrow_length;
461 const float back_x = cos_a * (arrow_length - arrow_head_size);
462 const float back_z = sin_a * (arrow_length - arrow_head_size);
463
464 dd.encoder.moveTo(head_x, 0.0f, head_z);
465 dd.encoder.lineTo(back_x - sin_a * arrow_head_size * 0.5f, 0.0f, back_z + cos_a * arrow_head_size * 0.5f);
466 dd.encoder.moveTo(head_x, 0.0f, head_z);
467 dd.encoder.lineTo(back_x + sin_a * arrow_head_size * 0.5f, 0.0f, back_z - cos_a * arrow_head_size * 0.5f);
468 dd.encoder.moveTo(head_x, 0.0f, head_z);
469 dd.encoder.lineTo(back_x, arrow_head_size * 0.5f, back_z);
470 }
471 break;
472 }
473 default:
474 break;
475 }
476
478 }
479 }
480
481 hpp::for_each_tuple_type<all_inspectable_components>(
482 [&](auto index)
483 {
484 using ctype = std::tuple_element_t<decltype(index)::value, all_inspectable_components>;
485 auto component = e.try_get<ctype>();
486
487 if(!component)
488 {
489 return;
490 }
491
492 auto var_comp = entt::forward_as_meta(*component);
493 ::unravel::draw_gizmo_var(ctx, var_comp, cam, dd);
494 });
495}
496
497
498
499void gizmo_entity::draw_billboard(rtti::context& ctx, entt::meta_any& var, const camera& cam, gfx::dd_raii& dd)
500{
501 auto e = var.cast<entt::handle>();
502
503 if(!e || !e.all_of<transform_component>())
504 return;
505
506
507 auto& tm = ctx.get_cached<thumbnail_manager>();
508
509 auto& em = ctx.get_cached<editing_manager>();
510
511 auto& transform_comp = e.get<transform_component>();
512 const auto& world_transform = transform_comp.get_transform_global();
513
514 constexpr float MIN_VISIBLE_DISTANCE = 1.0f;
515 constexpr float MIN_FADE_RANGE = 0.5f;
516
517 constexpr float MAX_VISIBLE_DISTANCE = 50.0f;
518 constexpr float MAX_FADE_RANGE = 25.0f;
519
520 auto dist = math::distance(world_transform.get_position(), cam.get_position());
521
522 // Calculate distance-based alpha: full visibility in range (MIN_VISIBLE_DISTANCE - MAX_VISIBLE_DISTANCE), fade outside
523 float distance_alpha = 1.0f;
524 if(dist < MIN_VISIBLE_DISTANCE)
525 {
526 // Fade from 0 to 1 as distance goes from (MIN_VISIBLE_DISTANCE - MIN_FADE_RANGE) to MIN_VISIBLE_DISTANCE
527 float fade_start = MIN_VISIBLE_DISTANCE - MIN_FADE_RANGE;
528 distance_alpha = math::clamp((dist - fade_start) / MIN_FADE_RANGE, 0.0f, 1.0f);
529 }
530 else if(dist > MAX_VISIBLE_DISTANCE)
531 {
532 // Fade from 1 to 0 as distance goes from MAX_VISIBLE_DISTANCE to (MAX_VISIBLE_DISTANCE + MAX_FADE_RANGE)
533 distance_alpha = math::clamp(1.0f - (dist - MAX_VISIBLE_DISTANCE) / MAX_FADE_RANGE, 0.0f, 1.0f);
534 }
535 // else: dist is in range [MIN_VISIBLE_DISTANCE, MAX_VISIBLE_DISTANCE], keep distance_alpha = 1.0f
536
537 auto alpha = em.billboard_data.opacity * distance_alpha;
538
539 // Early return if completely transparent
540 if(alpha <= 0.0f)
541 return;
542
543 auto col = math::color::white();
544
545 float tint = 1.0f;
546 if(!transform_comp.is_active_global())
547 {
548 tint *= 0.5f;
549 }
550
551 auto icon = tm.get_gizmo_icon(e);
552
553 if(e.all_of<light_component>())
554 {
555 const auto& light_comp = e.get<light_component>();
556 const auto& light = light_comp.get_light();
557 col = light.color;
558 }
559
560 if(!cam.test_billboard(em.billboard_data.size, world_transform))
561 return; // completely outside → skip draw
562
563 if(icon)
564 {
565 dd.encoder.setState(em.billboard_data.depth_aware, false, false);
566
567 col.value.a = alpha;
568 col.value *= tint;
569 dd.encoder.setColor(col);
570
572 icon->native_handle(),
573 to_bx(world_transform.get_position()),
574 to_bx(cam.get_position()),
575 to_bx(cam.z_unit_axis()),
576 em.billboard_data.size);
577 dd.encoder.setColor(0xffffffff);
578
579 dd.encoder.setState(true, true, false);
580 }
581}
582} // namespace unravel
Class that contains core camera data, used for rendering and other purposes.
auto get_projection_mode() const -> projection_mode
Gets the projection mode.
auto get_camera() -> camera &
Gets the camera object.
Class representing a camera. Contains functionality for manipulating and updating a camera....
Definition camera.h:35
auto test_billboard(float size, const math::transform &t) const -> bool
Definition camera.cpp:453
auto z_unit_axis() const -> math::vec3
Retrieves the z-axis unit vector of the camera's local coordinate system.
Definition camera.cpp:360
auto get_position() const -> const math::vec3 &
Retrieves the current position of the camera.
Definition camera.cpp:346
auto get_frustum() const -> const math::frustum &
Retrieves the current camera object frustum.
Definition camera.cpp:365
Class that contains core light data, used for rendering and other purposes.
Component that wraps particle system emitter functionality.
Class that contains core reflection probe data, used for rendering and other purposes.
auto get_probe() const -> const reflection_probe &
Gets the reflection probe object.
Component that handles transformations (position, rotation, scale, etc.) in the ACE framework.
auto get_transform_global() const noexcept -> const math::transform &
Gets the global transform.
float scale
Definition hub.cpp:25
const char * icon
void draw_billboard(DebugDrawEncoder &dd, bgfx::TextureHandle icon_texture, const bx::Vec3 &icon_center, const bx::Vec3 &camera_pos, const bx::Vec3 &camera_look_dir, float half_size)
Definition debugdraw.cpp:25
std::tuple< tag_component, layer_component, prefab_component, prefab_id_component, transform_component, test_component, model_component, animation_component, bone_component, submesh_component, camera_component, assao_component, tonemapping_component, fxaa_component, ssr_component, light_component, skylight_component, reflection_probe_component, physics_component, audio_source_component, audio_listener_component, text_component, particle_emitter_component, ui_document_component > all_inspectable_components
@ box
Box type reflection probe.
void draw_gizmo_var(rtti::context &ctx, entt::meta_any &var, const camera &cam, gfx::dd_raii &dd)
Definition gizmos.cpp:39
auto to_bx(const glm::vec3 &data) -> bx::Vec3
Definition gizmos.cpp:8
float y
float x
float z
@ X
Definition debugdraw.h:17
@ Y
Definition debugdraw.h:18
@ Z
Definition debugdraw.h:19
void draw(const bx::Aabb &_aabb)
void lineTo(float _x, float _y, float _z=0.0f)
void drawCone(const bx::Vec3 &_from, const bx::Vec3 &_to, float _radius)
void setColor(uint32_t _abgr)
void setWireframe(bool _wireframe)
void setState(bool _depthTest, bool _depthWrite, bool _clockwise, bool _alphaWrite=false, bool _alphaBlend=true)
void pushTransform(const void *_mtx)
void drawFrustum(const void *_viewProj)
void moveTo(float _x, float _y, float _z=0.0f)
void drawCircle(const bx::Vec3 &_normal, const bx::Vec3 &_center, float _radius, float _weight=0.0f)
void setLod(uint8_t _lod)
DebugDrawEncoder encoder
Definition debugdraw.h:15
view_id view
Definition debugdraw.h:16
static color white()
Definition color.h:13
auto get_cached() -> T &
Definition context.hpp:49
void draw_billboard(rtti::context &ctx, entt::meta_any &var, const camera &cam, gfx::dd_raii &dd) override
void draw(rtti::context &ctx, entt::meta_any &var, const camera &cam, gfx::dd_raii &dd) override
float range
The range of the point light.
Definition light.h:162
float get_range() const
Gets the range of the spot light.
Definition light.h:106
float get_outer_angle() const
Gets the outer angle of the spot light.
Definition light.h:121
float get_inner_angle() const
Gets the inner angle of the spot light.
Definition light.h:136
Struct representing a light.
Definition light.h:87
light_type type
The type of the light.
Definition light.h:89
math::color color
The color of the light.
Definition light.h:207
point point_data
Data specific to point lights.
Definition light.h:203
spot spot_data
Data specific to spot lights.
Definition light.h:201