1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "myGL.h"
4 #include "LightHandler.h"
5 #include "Game/GlobalUnsynced.h"
6 #include "Rendering/Shaders/Shader.h"
7 #include "Sim/Misc/GlobalSynced.h"
8 #include "Sim/Misc/LosHandler.h"
9
10 static const float4 ZeroVector4 = float4(0.0f, 0.0f, 0.0f, 0.0f);
11
Init(unsigned int cfgBaseLight,unsigned int cfgMaxLights)12 void GL::LightHandler::Init(unsigned int cfgBaseLight, unsigned int cfgMaxLights) {
13 glGetIntegerv(GL_MAX_LIGHTS, reinterpret_cast<int*>(&maxLights));
14
15 baseLight = cfgBaseLight;
16 maxLights -= baseLight;
17 maxLights = std::min(maxLights, cfgMaxLights);
18
19 for (unsigned int i = 0; i < maxLights; i++) {
20 const unsigned int lightID = GL_LIGHT0 + baseLight + i;
21
22 glEnable(lightID);
23 glLightfv(lightID, GL_POSITION, &ZeroVector4.x);
24 glLightfv(lightID, GL_AMBIENT, &ZeroVector4.x);
25 glLightfv(lightID, GL_DIFFUSE, &ZeroVector4.x);
26 glLightfv(lightID, GL_SPECULAR, &ZeroVector4.x);
27 glLightfv(lightID, GL_SPOT_DIRECTION, &ZeroVector4.x);
28 glLightf(lightID, GL_SPOT_CUTOFF, 180.0f);
29 glLightf(lightID, GL_CONSTANT_ATTENUATION, 1.0f);
30 glLightf(lightID, GL_LINEAR_ATTENUATION, 0.0f);
31 glLightf(lightID, GL_QUADRATIC_ATTENUATION, 0.0f);
32 glDisable(lightID);
33
34 // reserve free light ID's
35 lightIDs.push_back(lightID);
36 }
37 }
38
39
AddLight(const GL::Light & light)40 unsigned int GL::LightHandler::AddLight(const GL::Light& light) {
41 if (light.GetTTL() == 0 || light.GetRadius() <= 0.0f) { return -1U; }
42 if (light.GetIntensityWeight().SqLength() <= 0.01f) { return -1U; }
43
44 if (lights.size() >= maxLights || lightIDs.empty()) {
45 unsigned int minPriorityValue = light.GetPriority();
46 unsigned int minPriorityHandle = -1U;
47
48 for (std::map<unsigned int, GL::Light>::const_iterator it = lights.begin(); it != lights.end(); ++it) {
49 const GL::Light& lgt = it->second;
50
51 if (lgt.GetPriority() < minPriorityValue) {
52 minPriorityValue = lgt.GetPriority();
53 minPriorityHandle = it->first;
54 }
55 }
56
57 if (minPriorityHandle != -1U) {
58 lightIntensityWeight -= lights[minPriorityHandle].GetIntensityWeight();
59 lightIDs.push_back(lights[minPriorityHandle].GetID());
60 lights.erase(minPriorityHandle);
61 } else {
62 // no available light to replace
63 return -1U;
64 }
65 }
66
67 lights[lightHandle] = light;
68 lights[lightHandle].SetID(lightIDs.front());
69 lights[lightHandle].SetRelativeTime(0);
70 lights[lightHandle].SetAbsoluteTime(gs->frameNum);
71
72 lightIntensityWeight += light.GetIntensityWeight();
73 lightIDs.pop_front();
74
75 return (lightHandle++);
76 }
77
GetLight(unsigned int _lightHandle)78 GL::Light* GL::LightHandler::GetLight(unsigned int _lightHandle) {
79 const std::map<unsigned int, GL::Light>::iterator it = lights.find(_lightHandle);
80
81 if (it != lights.end()) {
82 return &(it->second);
83 }
84
85 return NULL;
86 }
87
88
Update(Shader::IProgramObject * shader)89 void GL::LightHandler::Update(Shader::IProgramObject* shader) {
90 if (lights.size() != numLights) {
91 numLights = lights.size();
92
93 // update the active light-count (note: unused, number of lights
94 // to iterate over needs to be known at shader compilation-time)
95 // shader->SetUniform1i(uniformIndex, numLights);
96 }
97
98 if (numLights == 0) {
99 return;
100 }
101
102 for (std::map<unsigned int, GL::Light>::iterator it = lights.begin(); it != lights.end(); ) {
103 GL::Light& light = it->second;
104
105 if (light.GetAbsoluteTime() != gs->frameNum) {
106 light.SetRelativeTime(light.GetRelativeTime() + 1);
107 light.SetAbsoluteTime(gs->frameNum);
108 light.DecayColors();
109 light.ClampColors();
110 }
111
112 const unsigned int lightID = light.GetID();
113 const unsigned int lightHndle = it->first;
114
115 const float4 weightedAmbientCol = (light.GetAmbientColor() * light.GetIntensityWeight().x) / lightIntensityWeight.x;
116 const float4 weightedDiffuseCol = (light.GetDiffuseColor() * light.GetIntensityWeight().y) / lightIntensityWeight.y;
117 const float4 weightedSpecularCol = (light.GetSpecularColor() * light.GetIntensityWeight().z) / lightIntensityWeight.z;
118 const float3* lightTrackPos = light.GetTrackPosition();
119 const float3* lightTrackDir = light.GetTrackDirection();
120 const float4& lightPos = (lightTrackPos != NULL)? float4(*lightTrackPos, 1.0f): light.GetPosition();
121 const float3& lightDir = (lightTrackDir != NULL)? float3(*lightTrackDir ): light.GetDirection();
122 const bool lightVisible = (gu->spectatingFullView || light.GetIgnoreLOS() || losHandler->InLos(lightPos, gu->myAllyTeam));
123
124 ++it;
125
126 if (light.GetRelativeTime() > light.GetTTL()) {
127 lightIntensityWeight -= light.GetIntensityWeight();
128 lightIDs.push_back(lightID);
129 lights.erase(lightHndle);
130
131 // kill the contribution from this light
132 glEnable(lightID);
133 glLightfv(lightID, GL_AMBIENT, &ZeroVector4.x);
134 glLightfv(lightID, GL_DIFFUSE, &ZeroVector4.x);
135 glLightfv(lightID, GL_SPECULAR, &ZeroVector4.x);
136 glDisable(lightID);
137 } else {
138 // communicate properties via the FFP to save uniforms
139 // note: we want MV to be identity here
140 glEnable(lightID);
141 glLightfv(lightID, GL_POSITION, &lightPos.x);
142
143 if (lightVisible) {
144 glLightfv(lightID, GL_AMBIENT, &weightedAmbientCol.x);
145 glLightfv(lightID, GL_DIFFUSE, &weightedDiffuseCol.x);
146 glLightfv(lightID, GL_SPECULAR, &weightedSpecularCol.x);
147 } else {
148 // zero contribution from this light if not in LOS
149 // (whether or not camera can see it is irrelevant
150 // since the light always takes up a slot anyway)
151 glLightfv(lightID, GL_AMBIENT, &ZeroVector4.x);
152 glLightfv(lightID, GL_DIFFUSE, &ZeroVector4.x);
153 glLightfv(lightID, GL_SPECULAR, &ZeroVector4.x);
154 }
155
156 glLightfv(lightID, GL_SPOT_DIRECTION, &lightDir.x);
157 glLightf(lightID, GL_SPOT_CUTOFF, light.GetFOV());
158 glLightf(lightID, GL_CONSTANT_ATTENUATION, light.GetRadius()); //!
159 #if (OGL_SPEC_ATTENUATION == 1)
160 glLightf(lightID, GL_CONSTANT_ATTENUATION, light.GetAttenuation().x);
161 glLightf(lightID, GL_LINEAR_ATTENUATION, light.GetAttenuation().y);
162 glLightf(lightID, GL_QUADRATIC_ATTENUATION, light.GetAttenuation().z);
163 #endif
164 glDisable(lightID);
165 }
166 }
167 }
168