Line data Source code
1 : /* dynlight.cpp: handling of changing lights
2 : *
3 : * while the lighting system is dynamic, the changing state of the light entities
4 : * for the renderer to handle must be updated with new values that reflect the type
5 : * of light to be drawn
6 : *
7 : * this includes pulsating lights (which change in radius dynamically)
8 : * and multicolored lights (which change hue dynamically)
9 : */
10 : #include "../libprimis-headers/cube.h"
11 : #include "../../shared/geomexts.h"
12 :
13 : #include "dynlight.h"
14 : #include "physics.h"
15 :
16 : #include "interface/control.h"
17 :
18 : #include "render/rendergl.h"
19 : #include "render/renderva.h"
20 :
21 : //internally relevant functionality
22 : namespace
23 : {
24 : VARNP(dynlights, usedynlights, 0, 1, 1); //toggle using dynamic lights
25 : VARP(dynlightdist, 0, 1024, 10000); //distance after which dynamic lights are not rendered (1024 = 128m)
26 :
27 : class dynlight
28 : {
29 : public:
30 :
31 : vec o;
32 : float curradius, dist;
33 : int expire;
34 : const physent *owner;
35 :
36 0 : dynlight(vec o, int expire, physent *owner, float radius, float initradius, vec color, vec initcolor, int fade, int peak, int flags, vec dir, int spot) :
37 0 : o(o), expire(expire), owner(owner), radius(radius), initradius(initradius), color(color), initcolor(initcolor), fade(fade), peak(peak), flags(flags), dir(dir), spot(spot)
38 : {
39 0 : }
40 :
41 0 : void calcradius()
42 : {
43 0 : if(fade + peak > 0)
44 : {
45 0 : int remaining = expire - lastmillis;
46 0 : if(flags&DynLight_Expand)
47 : {
48 0 : curradius = initradius + (radius - initradius) * (1.0f - remaining/static_cast<float>(fade + peak));
49 : }
50 0 : else if(!(flags&DynLight_Flash) && remaining > fade)
51 : {
52 0 : curradius = initradius + (radius - initradius) * (1.0f - static_cast<float>(remaining - fade)/peak);
53 : }
54 0 : else if(flags&DynLight_Shrink)
55 : {
56 0 : curradius = (radius*remaining)/fade;
57 : }
58 : else
59 : {
60 0 : curradius = radius;
61 : }
62 : }
63 : else
64 : {
65 0 : curradius = radius;
66 : }
67 0 : }
68 :
69 0 : void calccolor()
70 : {
71 0 : if(flags&DynLight_Flash || peak <= 0)
72 : {
73 0 : curcolor = color;
74 : }
75 : else
76 : {
77 0 : int peaking = expire - lastmillis - fade;
78 0 : if(peaking <= 0)
79 : {
80 0 : curcolor = color;
81 : }
82 : else
83 : {
84 0 : curcolor.lerp(initcolor, color, 1.0f - static_cast<float>(peaking)/peak);
85 : }
86 : }
87 0 : float intensity = 1.0f;
88 0 : if(fade > 0)
89 : {
90 0 : int fading = expire - lastmillis;
91 0 : if(fading < fade)
92 : {
93 0 : intensity = static_cast<float>(fading)/fade;
94 : }
95 : }
96 0 : curcolor.mul(intensity);
97 0 : }
98 :
99 : /* dynlightinfo: gets information about this dynlight
100 : *
101 : * Parameters:
102 : * n: the nth closest dynamic light
103 : * o: a reference to set as the location of the specified dynlight
104 : * radius: a reference to set as the radius of the specified dynlight
105 : * color: a reference to set as the color of the specifeid dynlight
106 : * spot: a reference to the spotlight information of the dynlight
107 : * dir: a reference to set as the direction the dynlight is pointing
108 : * flags: a reference to the flag bitmap for the dynlight
109 : */
110 0 : void dynlightinfo(vec &origin, float &radius, vec &color, vec &direction, int &spotlight, int &flagmask) const
111 : {
112 0 : origin = o;
113 0 : radius = curradius;
114 0 : color = curcolor;
115 0 : spotlight = spot;
116 0 : direction = dir;
117 0 : flagmask = flags & 0xFF;
118 0 : }
119 : private:
120 : float radius, initradius;
121 : vec color, initcolor, curcolor;
122 : int fade, peak, flags;
123 : vec dir;
124 : int spot;
125 : };
126 :
127 : std::vector<dynlight> dynlights;
128 : std::vector<const dynlight *> closedynlights;
129 :
130 : //cleans up dynlights, deletes dynlights contents once none have expire field
131 0 : void cleardynlights()
132 : {
133 0 : int faded = -1;
134 0 : for(uint i = 0; i < dynlights.size(); i++)
135 : {
136 0 : if(lastmillis<dynlights[i].expire)
137 : {
138 0 : faded = i;
139 0 : break;
140 : }
141 : }
142 0 : if(faded<0) //if any light has lastmillis > expire field
143 : {
144 0 : dynlights.clear();
145 : }
146 0 : else if(faded>0)
147 : {
148 0 : dynlights.erase(dynlights.begin(), dynlights.begin() + faded);
149 : }
150 0 : }
151 : }
152 : //externally relevant functionality
153 :
154 : //adds a dynamic light object to the dynlights vector with the attributes indicated (radius, color, fade, peak, flags, etc..)
155 0 : void adddynlight(const vec &o, float radius, const vec &color, int fade, int peak, int flags, float initradius, const vec &initcolor, physent *owner, const vec &dir, int spot)
156 : {
157 0 : if(!usedynlights)
158 : {
159 0 : return;
160 : }
161 0 : if(o.dist(camera1->o) > dynlightdist || radius <= 0)
162 : {
163 0 : return;
164 : }
165 0 : int insert = 0,
166 0 : expire = fade + peak + lastmillis;
167 0 : for(int i = dynlights.size(); --i >=0;) //note reverse iteration
168 : {
169 0 : if(expire>=dynlights[i].expire)
170 : {
171 0 : insert = i+1;
172 0 : break;
173 : }
174 : }
175 0 : dynlight d(o, expire, owner, radius, initradius, color, initcolor, fade, peak, flags, dir, spot);
176 0 : dynlights.insert(dynlights.begin() + insert, d);
177 : }
178 :
179 0 : void removetrackeddynlights(const physent *owner)
180 : {
181 0 : for(int i = dynlights.size(); --i >=0;) //note reverse iteration
182 : {
183 0 : if(owner ? dynlights[i].owner == owner : dynlights[i].owner != nullptr)
184 : {
185 0 : dynlights.erase(dynlights.begin() + i);
186 : }
187 : }
188 0 : }
189 :
190 : //finds which dynamic lights are near enough and are visible to the player
191 : //returns the number of lights (and sets `closedynlights` vector contents to the appropriate nearby light ents)
192 0 : size_t finddynlights()
193 : {
194 0 : closedynlights.clear();
195 0 : if(!usedynlights)
196 : {
197 0 : return 0;
198 : }
199 0 : physent e;
200 0 : e.type = physent::PhysEnt_Camera;
201 0 : for(dynlight &d : dynlights)
202 : {
203 0 : if(d.curradius <= 0)
204 : {
205 0 : continue;
206 : }
207 0 : d.dist = camera1->o.dist(d.o) - d.curradius;
208 0 : if(d.dist > dynlightdist || view.isfoggedsphere(d.curradius, d.o))
209 : {
210 0 : continue;
211 : }
212 0 : e.o = d.o;
213 0 : e.radius = e.xradius = e.yradius = e.eyeheight = e.aboveeye = d.curradius;
214 0 : if(!collide(&e, vec(0, 0, 0), 0, false))
215 : {
216 0 : continue;
217 : }
218 0 : int insert = 0;
219 0 : for(int i = closedynlights.size(); --i >=0;) //note reverse iteration
220 : {
221 0 : if(d.dist >= closedynlights[i]->dist)
222 : {
223 0 : insert = i+1;
224 0 : break;
225 : }
226 : }
227 0 : closedynlights.insert(closedynlights.begin() + insert, &d);
228 : }
229 0 : return closedynlights.size();
230 : }
231 :
232 : /* getdynlight: gets the nth dynlight near camera and sets references to its values
233 : *
234 : * Parameters:
235 : * n: the nth closest dynamic light
236 : * o: a reference to set as the location of the specified dynlight
237 : * radius: a reference to set as the radius of the specified dynlight
238 : * color: a reference to set as the color of the specifeid dynlight
239 : * spot: a reference to the spotlight information of the dynlight
240 : * dir: a reference to set as the direction the dynlight is pointing
241 : * flags: a reference to the flag bitmap for the dynlight
242 : * Returns:
243 : * bool: true if light at position n was found, false otherwise
244 : *
245 : */
246 0 : bool getdynlight(size_t n, vec &o, float &radius, vec &color, vec &dir, int &spot, int &flags)
247 : {
248 0 : if(!(closedynlights.size() > n))
249 : {
250 0 : return false;
251 : }
252 0 : const dynlight &d = *closedynlights[n];
253 0 : d.dynlightinfo(o, radius, color, dir, spot, flags);
254 0 : return true;
255 : }
256 :
257 0 : void updatedynlights()
258 : {
259 0 : cleardynlights();
260 0 : for(dynlight &d : dynlights)
261 : {
262 0 : d.calcradius();
263 0 : d.calccolor();
264 : }
265 0 : }
|