1 module re.gfx.lighting.scene_lights; 2 3 import re.core; 4 import re.ecs; 5 import re.ng.manager; 6 import re.ng.scene3d; 7 import re.gfx; 8 import re.math; 9 import std.algorithm; 10 import std.container.array; 11 static import raylib; 12 import rlights = re.gfx.lighting.rlights; 13 14 /// acts as a manager for Light3D components 15 class SceneLightManager : Manager, Updatable { 16 alias max_lights = rlights.MAX_LIGHTS; 17 private Array!(rlights.Light) _lights; 18 private Array!Light3D _comps; 19 private int light_count; 20 public Shader shader; 21 22 this() { 23 // load the shader 24 shader = Core.content.load_shader("shader/basic_lighting.vert", 25 "shader/basic_lighting.frag"); 26 // get some shader locations 27 shader.locs[raylib.ShaderLocationIndex.LOC_MATRIX_MODEL] = raylib.GetShaderLocation(shader, 28 "matModel"); 29 shader.locs[raylib.ShaderLocationIndex.LOC_VECTOR_VIEW] = raylib.GetShaderLocation(shader, 30 "viewPos"); 31 32 // ambient light level 33 auto ambient_loc = raylib.GetShaderLocation(shader, "ambient"); 34 auto col_ambient = 0.4; 35 float[4] ambient_val = [col_ambient, col_ambient, col_ambient, 1]; 36 raylib.SetShaderValue(shader, ambient_loc, &ambient_val, 37 raylib.ShaderUniformDataType.UNIFORM_VEC4); 38 39 _lights.reserve(max_lights); 40 _comps.reserve(max_lights); 41 } 42 43 override void update() { 44 // update camera view pos in light shader 45 float[3] camera_pos = [ 46 (cast(Scene3D) scene).cam.transform.position.x, (cast(Scene3D) scene) 47 .cam.transform.position.y, (cast(Scene3D) scene).cam.transform.position.z 48 ]; 49 raylib.SetShaderValue(shader, shader.locs[raylib.ShaderLocationIndex.LOC_VECTOR_VIEW], 50 &camera_pos, raylib.ShaderUniformDataType.UNIFORM_VEC3); 51 52 // update lights 53 for (int i = 0; i < light_count; i++) { 54 // sync fields 55 _lights[i].position = _comps[i].transform.position; 56 _lights[i].color = _comps[i].color; 57 _lights[i].enabled = _comps[i].light_enabled; 58 59 // update shader values 60 rlights.UpdateLightValues(shader, _lights[i]); 61 } 62 } 63 64 override void destroy() { 65 while (light_count > 0) { 66 unregister(_comps[0]); 67 } 68 } 69 70 private void register(Light3D light_comp) { 71 assert(light_count < max_lights, "maximum light count exceeded."); 72 // add a light 73 _lights.insertBack(rlights.set_light(light_count, rlights.LightType.LIGHT_POINT, 74 light_comp.transform.position, Vector3Zero, light_comp.color, shader)); 75 _comps.insertBack(light_comp); 76 // set internal light reference 77 light_comp._light = _lights[light_count]; 78 light_count++; 79 } 80 81 private void unregister(Light3D light_comp) { 82 import std.range : dropExactly, takeOne; 83 84 auto removed_index = cast(int) _comps[].countUntil(light_comp); 85 // clear all lights 86 for (int i = 0; i < light_count; i++) { 87 rlights.clear_light(i, shader); 88 } 89 _comps.linearRemove(_comps[].dropExactly(removed_index).takeOne); 90 _lights.linearRemove(_lights[].dropExactly(removed_index).takeOne); 91 light_count--; // we're removing a light 92 // ensure our lengths match 93 assert(_lights.length == light_count); 94 assert(_lights.length == _comps.length); 95 // reactivate the lights 96 for (int i = 0; i < light_count; i++) { 97 // update shader 98 _lights[i] = rlights.set_light(i, rlights.LightType.LIGHT_POINT, 99 _comps[i].transform.position, Vector3Zero, _comps[i].color, shader); 100 // set associated light 101 _comps[i]._light = _lights[i]; 102 } 103 } 104 } 105 106 /// represents a 3D light 107 class Light3D : Component, Renderable3D { 108 private SceneLightManager _mgr; 109 private enum phys_size = 0.2; 110 private rlights.Light _light; 111 112 /// the color of the light 113 public Color color; 114 115 /// whether the light is enabled 116 public bool light_enabled = true; 117 118 /// creates a new light with a given color 119 this(Color color = Colors.WHITE) { 120 this.color = color; 121 } 122 123 override void setup() { 124 // register the light in the manager 125 auto mgr = entity.scene.get_manager!SceneLightManager(); 126 assert(!mgr.isNull, "scene did not have SceneLightManager registered." 127 ~ "please add that to the scene before creating this component."); 128 _mgr = mgr.get; 129 _mgr.register(this); 130 } 131 132 override void destroy() { 133 _mgr.unregister(this); 134 } 135 136 @property BoundingBox bounds() { 137 auto size = Vector3(phys_size, phys_size, phys_size); 138 return BoundingBox(entity.position - size, entity.position + size); 139 } 140 141 void render() { 142 } 143 144 void debug_render() { 145 import re.ng.diag.render; 146 147 raylib.DrawSphereEx(entity.position, phys_size, 8, 8, color); 148 raylib.DrawSphereWires(entity.position, phys_size * 1.5, 2, 2, DebugRender.debug_color); 149 } 150 }