]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/entity/light.cpp
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / plugins / entity / light.cpp
1 \r
2 #include "plugin.h"\r
3 #include "entity.h"\r
4 #include "light.h"\r
5 \r
6 void DrawSphere(vec3_t center, float radius, int sides, int nGLState)\r
7 {\r
8   int i, j;\r
9   float dt = (float) (2 * Q_PI / (float) sides);\r
10   float dp = (float) (Q_PI / (float) sides);\r
11   float t, p;\r
12   vec3_t v;\r
13 \r
14   if (radius <= 0)\r
15     return;\r
16 \r
17   g_QglTable.m_pfn_qglBegin(GL_TRIANGLES);\r
18   for (i = 0; i <= sides - 1; i++) {\r
19     for (j = 0; j <= sides - 2; j++) {\r
20       t = i * dt;\r
21       p = (float) ((j * dp) - (Q_PI / 2));\r
22 \r
23       VectorPolar(v, radius, t, p);\r
24       VectorAdd(v, center, v);\r
25       g_QglTable.m_pfn_qglVertex3fv(v);\r
26 \r
27       VectorPolar(v, radius, t, p + dp);\r
28       VectorAdd(v, center, v);\r
29       g_QglTable.m_pfn_qglVertex3fv(v);\r
30 \r
31       VectorPolar(v, radius, t + dt, p + dp);\r
32       VectorAdd(v, center, v);\r
33       g_QglTable.m_pfn_qglVertex3fv(v);\r
34 \r
35       VectorPolar(v, radius, t, p);\r
36       VectorAdd(v, center, v);\r
37       g_QglTable.m_pfn_qglVertex3fv(v);\r
38 \r
39       VectorPolar(v, radius, t + dt, p + dp);\r
40       VectorAdd(v, center, v);\r
41       g_QglTable.m_pfn_qglVertex3fv(v);\r
42 \r
43       VectorPolar(v, radius, t + dt, p);\r
44       VectorAdd(v, center, v);\r
45       g_QglTable.m_pfn_qglVertex3fv(v);\r
46     }\r
47   }\r
48 \r
49   p = (float) ((sides - 1) * dp - (Q_PI / 2));\r
50   for (i = 0; i <= sides - 1; i++) {\r
51     t = i * dt;\r
52 \r
53     VectorPolar(v, radius, t, p);\r
54     VectorAdd(v, center, v);\r
55     g_QglTable.m_pfn_qglVertex3fv(v);\r
56 \r
57     VectorPolar(v, radius, t + dt, p + dp);\r
58     VectorAdd(v, center, v);\r
59     g_QglTable.m_pfn_qglVertex3fv(v);\r
60 \r
61     VectorPolar(v, radius, t + dt, p);\r
62     VectorAdd(v, center, v);\r
63     g_QglTable.m_pfn_qglVertex3fv(v);\r
64   }\r
65   g_QglTable.m_pfn_qglEnd();\r
66 }\r
67 \r
68 #define LIGHT_ATTEN_LINEAR      1\r
69 #define LIGHT_ATTEN_ANGLE               2\r
70 #define LIGHT_ATTEN_DISTANCE    4\r
71 \r
72 #define LIGHT_Q3A_DEFAULT               (LIGHT_ATTEN_ANGLE | LIGHT_ATTEN_DISTANCE)\r
73 #define LIGHT_WOLF_DEFAULT      (LIGHT_ATTEN_LINEAR | LIGHT_ATTEN_DISTANCE)\r
74 \r
75 float CalculateEnvelopeForLight(entity_t * e, float fFalloffTolerance)\r
76 {\r
77   float fEnvelope = 0.f;\r
78   int iSpawnFlags = atoi(ValueForKey(e, "spawnflags"));\r
79   int iLightFlags = 0;\r
80   float fFade = 1.f;\r
81   float fIntensity, fPhotons;\r
82   float fScale;\r
83   const char *gameFile = g_FuncTable.m_pfnGetGameFile();\r
84 \r
85   // These variables are tweakable on the q3map2 console, setting to q3map2\r
86   // default here as there is no way to find out what the user actually uses\r
87   // right now. Maybe move them to worldspawn?\r
88   float fPointScale = 7500.f;\r
89   float fLinearScale = 1.f / 8000.f;\r
90   //float fFalloffTolerance = 1.f;  // Need it as parameter\r
91 \r
92   // Arnout: HACK for per-game radii - really need to move this to a per-game module?\r
93   if( !strcmp( gameFile, "wolf.game" ) || !strcmp( gameFile, "et.game" ) ) {\r
94     // Spawnflags :\r
95     // 1: nonlinear\r
96     // 2: angle\r
97 \r
98     // set default flags\r
99     iLightFlags = LIGHT_WOLF_DEFAULT;\r
100 \r
101     // inverse distance squared attenuation?\r
102     if (iSpawnFlags & 1) {\r
103       iLightFlags &= ~LIGHT_ATTEN_LINEAR;\r
104       iLightFlags |= LIGHT_ATTEN_ANGLE;\r
105     }\r
106     // angle attenuate\r
107     if (iSpawnFlags & 2)\r
108       iLightFlags |= LIGHT_ATTEN_ANGLE;\r
109   } else {\r
110     // Spawnflags :\r
111     // 1: linear\r
112     // 2: no angle\r
113 \r
114     // set default flags\r
115     iLightFlags = LIGHT_Q3A_DEFAULT;\r
116 \r
117     // linear attenuation?\r
118     if (iSpawnFlags & 1) {\r
119       iLightFlags |= LIGHT_ATTEN_LINEAR;\r
120       iLightFlags &= ~LIGHT_ATTEN_ANGLE;\r
121     }\r
122     // no angle attenuate?\r
123     if (iSpawnFlags & 2)\r
124       iLightFlags &= ~LIGHT_ATTEN_ANGLE;\r
125   }\r
126 \r
127   // set fade key (from wolf)\r
128   if (iLightFlags & LIGHT_ATTEN_LINEAR) {\r
129     fFade = FloatForKey(e, "fade");\r
130     if (fFade <= 0.f)\r
131       fFade = 1.f;\r
132   }\r
133   // set light intensity\r
134   fIntensity = FloatForKey(e, "_light");\r
135   if (fIntensity == 0.f)\r
136     fIntensity = FloatForKey(e, "light");\r
137   if (fIntensity == 0.f)\r
138     fIntensity = 300.f;\r
139 \r
140   // set light scale (sof2)\r
141   fScale = FloatForKey(e, "scale");\r
142   if (fScale <= 0.f)\r
143     fScale = 1.f;\r
144   fIntensity *= fScale;\r
145 \r
146   // amount of photons\r
147   fPhotons = fIntensity * fPointScale;\r
148 \r
149   // calculate envelope\r
150 \r
151   // solve distance for non-distance lights\r
152   if (!(iLightFlags & LIGHT_ATTEN_DISTANCE))\r
153     //!\todo (spog) can't access global objects in a module - globals are EVIL - solution: API for querying global settings.\r
154     fEnvelope = 131072/*g_MaxWorldCoord * 2.f*/;\r
155   // solve distance for linear lights\r
156   else if (iLightFlags & LIGHT_ATTEN_LINEAR)\r
157     fEnvelope = ((fPhotons * fLinearScale) - fFalloffTolerance) / fFade;\r
158   // solve for inverse square falloff\r
159   else\r
160     fEnvelope = sqrt(fPhotons / fFalloffTolerance) /* + fRadius */ ;  // Arnout radius is always 0, only for area lights\r
161 \r
162   return fEnvelope;\r
163 }\r
164 \r
165 float CalculateLightRadius(entity_t * e, bool outer)\r
166 {\r
167   float fEnvelope = 0.f;\r
168   int iSpawnFlags = atoi(ValueForKey(e, "spawnflags"));\r
169   float fIntensity;\r
170   float fScale;\r
171   const char *gameFile = g_FuncTable.m_pfnGetGameFile();\r
172 \r
173   fIntensity = FloatForKey(e, "light");\r
174   if (fIntensity == 0.f)\r
175     fIntensity = 300.f;\r
176 \r
177   // Arnout: HACK for per-game radii - really need to move this to a per-game module\r
178   if( !strcmp( gameFile, "sof2.game" ) || !strcmp( gameFile, "jk2.game" ) || !strcmp( gameFile, "ja.game" )) {\r
179     // Spawnflags :\r
180     // 1: linear\r
181     // 2: noincidence\r
182 \r
183     if (!outer) {\r
184       if (iSpawnFlags & 2)\r
185         fIntensity *= .9;\r
186       else\r
187         fIntensity *= .25f;\r
188     }\r
189     // set light scale (sof2)\r
190     fScale = FloatForKey(e, "scale");\r
191     if (fScale <= 0.f)\r
192       fScale = 1.f;\r
193     fIntensity *= fScale;\r
194 \r
195     fEnvelope = fIntensity;\r
196   } else {\r
197     float fPointScale = 7500.f;\r
198 \r
199     if (outer)\r
200       fEnvelope = sqrt(fIntensity * fPointScale / 48.f);\r
201     else\r
202       fEnvelope = sqrt(fIntensity * fPointScale / 255.f);\r
203   }\r
204 \r
205   return fEnvelope;\r
206 }\r
207 \r
208 void Light_OnIntensityChanged(entity_t* e)\r
209 {\r
210   e->fLightEnvelope1[0] = CalculateEnvelopeForLight(e, 1.f);\r
211   e->fLightEnvelope1[1] = CalculateEnvelopeForLight(e, 48.f);\r
212   e->fLightEnvelope1[2] = CalculateEnvelopeForLight(e, 255.f);\r
213 \r
214   e->fLightEnvelope2[0] = CalculateLightRadius(e, TRUE);\r
215   e->fLightEnvelope2[1] = CalculateLightRadius(e, FALSE);\r
216 }\r
217 \r
218 void Light_OnKeyValueChanged(entity_t *e, const char *key, const char* value)\r
219 {\r
220   if(strcmp(key,"_color") == 0)\r
221   {\r
222     if (sscanf(ValueForKey(e, "_color"),"%f %f %f",\r
223       &e->color[0], &e->color[1], &e->color[2]) != 3)\r
224       VectorSet(e->color, 1, 1, 1);\r
225   }\r
226   else if(strcmp(key,"spawnflags") == 0 ||\r
227           strcmp(key,"fade") == 0 ||\r
228           strcmp(key,"_light") == 0 ||\r
229           strcmp(key,"light") == 0 ||\r
230           strcmp(key,"scale") == 0)\r
231   {\r
232     Light_OnIntensityChanged(e);\r
233   }\r
234 }\r
235 \r
236 bool Entity_IsLight(entity_t *e)\r
237 {\r
238   return e->eclass != NULL && e->eclass->nShowFlags & ECLASS_LIGHT;//strncmp(ValueforKey(e, "classname"), "light") == 0\r
239 }\r
240 \r
241 static void DrawLightSphere(entity_t * e, int nGLState, int pref)\r
242 {\r
243   const char *target = ValueForKey(e, "target");\r
244   bool bIsSpotLight = !!target[0];\r
245   //!\todo Write an API for modules to register preference settings, and make this preference module-specific.\r
246   int nPasses = pref == 1 ? 3 : 2;\r
247 \r
248   g_QglTable.m_pfn_qglPushAttrib(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);\r
249   g_QglTable.m_pfn_qglDepthMask(GL_FALSE);\r
250   g_QglTable.m_pfn_qglEnable(GL_BLEND);\r
251   g_QglTable.m_pfn_qglBlendFunc(GL_ONE, GL_ONE);\r
252 \r
253   // Arnout: TODO: spotlight rendering\r
254   if (!(bIsSpotLight))\r
255   {\r
256     switch(pref)\r
257     {\r
258     case 1:\r
259       g_QglTable.m_pfn_qglColor3f(e->color[0] * .05f,\r
260         e->color[1] * .05f,\r
261         e->color[2] * .05f);\r
262       DrawSphere(e->origin, e->fLightEnvelope1[0], 16, nGLState);\r
263       DrawSphere(e->origin, e->fLightEnvelope1[1], 16, nGLState);\r
264       DrawSphere(e->origin, e->fLightEnvelope1[2], 16, nGLState);\r
265       break;\r
266     case 2:\r
267       g_QglTable.m_pfn_qglColor3f(e->color[0] * .15f * .95f,\r
268         e->color[1] * .15f * .95f,\r
269         e->color[2] * .15f * .95f);\r
270       DrawSphere(e->origin, e->fLightEnvelope2[0], 16, nGLState);\r
271       DrawSphere(e->origin, e->fLightEnvelope2[1], 16, nGLState);\r
272       break;\r
273 \r
274     }\r
275   }\r
276 \r
277   g_QglTable.m_pfn_qglPopAttrib();\r
278 }\r
279 \r
280 float F = 0.70710678f;\r
281 // North, East, South, West\r
282 vec3_t normals[8] = { { 0, F, F }, { F, 0, F }, { 0,-F, F }, {-F, 0, F },\r
283                                                                                         { 0, F,-F }, { F, 0,-F }, { 0,-F,-F }, {-F, 0,-F } };\r
284 \r
285 unsigned short indices[24] = { 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 2,\r
286                                1, 2, 5, 1, 5, 4, 1, 4, 3, 1, 3, 2 };\r
287 \r
288 void DrawLight(entity_t* e, int nGLState, int pref, int nViewType)\r
289 {\r
290   int i;\r
291   // top, bottom, tleft, tright, bright, bleft\r
292   vec3_t points[6];\r
293   vec3_t vMid, vMin, vMax;\r
294   VectorAdd(e->origin, e->eclass->mins, vMin);\r
295   VectorAdd(e->origin, e->eclass->maxs, vMax);\r
296   vMid[0] = (vMin[0] + vMax[0]) * 0.5;\r
297   vMid[1] = (vMin[1] + vMax[1]) * 0.5;\r
298   vMid[2] = (vMin[2] + vMax[2]) * 0.5;\r
299 \r
300   VectorSet(points[0], vMid[0], vMid[1], vMax[2]);\r
301   VectorSet(points[1], vMid[0], vMid[1], vMin[2]);\r
302   VectorSet(points[2], vMin[0], vMax[1], vMid[2]);\r
303   VectorSet(points[3], vMax[0], vMax[1], vMid[2]);\r
304   VectorSet(points[4], vMax[0], vMin[1], vMid[2]);\r
305   VectorSet(points[5], vMin[0], vMin[1], vMid[2]);\r
306 \r
307   if (nGLState & DRAW_GL_LIGHTING)// && g_PrefsDlg.m_bGLLighting)\r
308   {\r
309     g_QglTable.m_pfn_qglBegin(GL_TRIANGLES);// NOTE: comment to use gl_triangle_fan instead\r
310           //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN);\r
311     g_QglTable.m_pfn_qglVertex3fv(points[0]);\r
312     g_QglTable.m_pfn_qglVertex3fv(points[2]);\r
313           g_QglTable.m_pfn_qglNormal3fv(normals[0]);\r
314           g_QglTable.m_pfn_qglVertex3fv(points[3]);\r
315 \r
316           g_QglTable.m_pfn_qglVertex3fv(points[0]);//\r
317     g_QglTable.m_pfn_qglVertex3fv(points[3]);//\r
318           g_QglTable.m_pfn_qglNormal3fv(normals[1]);\r
319           g_QglTable.m_pfn_qglVertex3fv(points[4]);\r
320 \r
321           g_QglTable.m_pfn_qglVertex3fv(points[0]);//\r
322     g_QglTable.m_pfn_qglVertex3fv(points[4]);//\r
323           g_QglTable.m_pfn_qglNormal3fv(normals[2]);\r
324           g_QglTable.m_pfn_qglVertex3fv(points[5]);\r
325 \r
326           g_QglTable.m_pfn_qglVertex3fv(points[0]);//\r
327     g_QglTable.m_pfn_qglVertex3fv(points[5]);//\r
328           g_QglTable.m_pfn_qglNormal3fv(normals[3]);\r
329           g_QglTable.m_pfn_qglVertex3fv(points[2]);\r
330 \r
331           //g_QglTable.m_pfn_qglEnd();\r
332           //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN);\r
333 \r
334           g_QglTable.m_pfn_qglVertex3fv(points[1]);\r
335           g_QglTable.m_pfn_qglVertex3fv(points[2]);\r
336     g_QglTable.m_pfn_qglNormal3fv(normals[7]);\r
337           g_QglTable.m_pfn_qglVertex3fv(points[5]);\r
338 \r
339           g_QglTable.m_pfn_qglVertex3fv(points[1]);//\r
340           g_QglTable.m_pfn_qglVertex3fv(points[5]);//\r
341     g_QglTable.m_pfn_qglNormal3fv(normals[6]);\r
342           g_QglTable.m_pfn_qglVertex3fv(points[4]);\r
343 \r
344           g_QglTable.m_pfn_qglVertex3fv(points[1]);//\r
345           g_QglTable.m_pfn_qglVertex3fv(points[4]);//\r
346     g_QglTable.m_pfn_qglNormal3fv(normals[5]);\r
347           g_QglTable.m_pfn_qglVertex3fv(points[3]);\r
348 \r
349           g_QglTable.m_pfn_qglVertex3fv(points[1]);//\r
350           g_QglTable.m_pfn_qglVertex3fv(points[3]);//\r
351     g_QglTable.m_pfn_qglNormal3fv(normals[4]);\r
352           g_QglTable.m_pfn_qglVertex3fv(points[2]);\r
353 \r
354     g_QglTable.m_pfn_qglEnd();\r
355   }\r
356   else if (nGLState & DRAW_GL_FILL)\r
357   {\r
358     vec3_t colors[4];\r
359     VectorScale(e->color, 0.95, colors[0]);\r
360     VectorScale(colors[0], 0.95, colors[1]);\r
361     VectorScale(colors[1], 0.95, colors[2]);\r
362     VectorScale(colors[2], 0.95, colors[3]);\r
363     g_QglTable.m_pfn_qglBegin(GL_TRIANGLES);// NOTE: comment to use gl_triangle_fan instead\r
364           //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN);\r
365     g_QglTable.m_pfn_qglColor3fv(colors[0]);\r
366     g_QglTable.m_pfn_qglVertex3fv(points[0]);\r
367     g_QglTable.m_pfn_qglVertex3fv(points[2]);\r
368           g_QglTable.m_pfn_qglVertex3fv(points[3]);\r
369 \r
370     g_QglTable.m_pfn_qglColor3fv(colors[1]);\r
371           g_QglTable.m_pfn_qglVertex3fv(points[0]);//\r
372     g_QglTable.m_pfn_qglVertex3fv(points[3]);//\r
373           g_QglTable.m_pfn_qglVertex3fv(points[4]);\r
374 \r
375     g_QglTable.m_pfn_qglColor3fv(colors[2]);\r
376           g_QglTable.m_pfn_qglVertex3fv(points[0]);//\r
377     g_QglTable.m_pfn_qglVertex3fv(points[4]);//\r
378           g_QglTable.m_pfn_qglVertex3fv(points[5]);\r
379 \r
380     g_QglTable.m_pfn_qglColor3fv(colors[3]);\r
381           g_QglTable.m_pfn_qglVertex3fv(points[0]);//\r
382     g_QglTable.m_pfn_qglVertex3fv(points[5]);//\r
383           g_QglTable.m_pfn_qglVertex3fv(points[2]);\r
384 \r
385           //g_QglTable.m_pfn_qglEnd();\r
386           //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN);\r
387 \r
388     g_QglTable.m_pfn_qglColor3fv(colors[0]);\r
389           g_QglTable.m_pfn_qglVertex3fv(points[1]);\r
390           g_QglTable.m_pfn_qglVertex3fv(points[2]);\r
391           g_QglTable.m_pfn_qglVertex3fv(points[5]);\r
392 \r
393     g_QglTable.m_pfn_qglColor3fv(colors[1]);\r
394           g_QglTable.m_pfn_qglVertex3fv(points[1]);//\r
395           g_QglTable.m_pfn_qglVertex3fv(points[5]);//\r
396           g_QglTable.m_pfn_qglVertex3fv(points[4]);\r
397 \r
398     g_QglTable.m_pfn_qglColor3fv(colors[2]);\r
399           g_QglTable.m_pfn_qglVertex3fv(points[1]);//\r
400           g_QglTable.m_pfn_qglVertex3fv(points[4]);//\r
401           g_QglTable.m_pfn_qglVertex3fv(points[3]);\r
402 \r
403     g_QglTable.m_pfn_qglColor3fv(colors[3]);\r
404           g_QglTable.m_pfn_qglVertex3fv(points[1]);//\r
405           g_QglTable.m_pfn_qglVertex3fv(points[3]);//\r
406           g_QglTable.m_pfn_qglVertex3fv(points[2]);\r
407 \r
408     g_QglTable.m_pfn_qglEnd();\r
409   }\r
410   else\r
411   {\r
412           g_QglTable.m_pfn_qglVertexPointer(3, GL_FLOAT, 0, points);\r
413           g_QglTable.m_pfn_qglDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_SHORT, indices);\r
414   }\r
415 \r
416 \r
417   // NOTE: prolly not relevant until some time..\r
418   // check for DOOM lights\r
419   if (strlen(ValueForKey(e, "light_right")) > 0) {\r
420     vec3_t vRight, vUp, vTarget, vTemp;\r
421     GetVectorForKey (e, "light_right", vRight);\r
422     GetVectorForKey (e, "light_up", vUp);\r
423     GetVectorForKey (e, "light_target", vTarget);\r
424 \r
425     g_QglTable.m_pfn_qglColor3f(0, 1, 0);\r
426                 g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP);\r
427     VectorAdd(vTarget, e->origin, vTemp);\r
428     VectorAdd(vTemp, vRight, vTemp);\r
429     VectorAdd(vTemp, vUp, vTemp);\r
430     g_QglTable.m_pfn_qglVertex3fv(e->origin);\r
431     g_QglTable.m_pfn_qglVertex3fv(vTemp);\r
432     VectorAdd(vTarget, e->origin, vTemp);\r
433     VectorAdd(vTemp, vUp, vTemp);\r
434     VectorSubtract(vTemp, vRight, vTemp);\r
435     g_QglTable.m_pfn_qglVertex3fv(e->origin);\r
436     g_QglTable.m_pfn_qglVertex3fv(vTemp);\r
437     VectorAdd(vTarget, e->origin, vTemp);\r
438     VectorAdd(vTemp, vRight, vTemp);\r
439     VectorSubtract(vTemp, vUp, vTemp);\r
440     g_QglTable.m_pfn_qglVertex3fv(e->origin);\r
441     g_QglTable.m_pfn_qglVertex3fv(vTemp);\r
442     VectorAdd(vTarget, e->origin, vTemp);\r
443     VectorSubtract(vTemp, vUp, vTemp);\r
444     VectorSubtract(vTemp, vRight, vTemp);\r
445     g_QglTable.m_pfn_qglVertex3fv(e->origin);\r
446     g_QglTable.m_pfn_qglVertex3fv(vTemp);\r
447     g_QglTable.m_pfn_qglEnd();\r
448 \r
449   }\r
450 \r
451   if(nGLState & DRAW_GL_FILL)\r
452   {\r
453     DrawLightSphere(e, nGLState, pref);\r
454   }\r
455   else\r
456   {\r
457     // Arnout: FIXME: clean this up a bit\r
458     // now draw lighting radius stuff...\r
459     if (pref)\r
460     {\r
461       bool bDrawSpotlightArc = false;\r
462       int nPasses = pref == 1 ? 3 : 2;\r
463 \r
464       const char *target = ValueForKey(e, "target");\r
465       bool bIsSpotLight = !!target[0];\r
466 \r
467       /*!\todo Spotlight..\r
468       if (bIsSpotLight)\r
469       {\r
470         // find the origin of the target...\r
471         entity_t *e = FindEntity("targetname", target);\r
472 \r
473         if (e)\r
474           bDrawSpotlightArc = true;\r
475       }\r
476       */\r
477 \r
478       g_QglTable.m_pfn_qglPushAttrib(GL_LINE_BIT);\r
479       g_QglTable.m_pfn_qglLineStipple(8, 0xAAAA);\r
480       g_QglTable.m_pfn_qglEnable(GL_LINE_STIPPLE);\r
481 \r
482       float* envelope = (pref == 1) ? e->fLightEnvelope1 : e->fLightEnvelope2; \r
483       for (int iPass = 0; iPass < nPasses; iPass++)\r
484       {\r
485         float fRadius = envelope[iPass];\r
486 \r
487         g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP);\r
488 \r
489         if (bIsSpotLight)\r
490         {\r
491           if (bDrawSpotlightArc)\r
492           {\r
493             // I give up on this, it's beyond me\r
494           }\r
495         }\r
496         else\r
497         {\r
498           if (fRadius > 0)\r
499           {\r
500             int i;\r
501             float ds, dc;\r
502 \r
503             for (i = 0; i <= 24; i++)\r
504             {\r
505               ds = sin((i * 2 * Q_PI) / 24);\r
506               dc = cos((i * 2 * Q_PI) / 24);\r
507 \r
508               switch (nViewType)\r
509               {\r
510               case 2:\r
511                 g_QglTable.m_pfn_qglVertex3f(e->origin[0] + fRadius * dc,\r
512                   e->origin[1] + fRadius * ds,\r
513                   e->origin[2]);\r
514                 break;\r
515               case 1:\r
516                 g_QglTable.m_pfn_qglVertex3f(e->origin[0] + fRadius * dc,\r
517                    e->origin[1],\r
518                   e->origin[2] + fRadius * ds);\r
519                 break;\r
520               case 0:\r
521                 g_QglTable.m_pfn_qglVertex3f(e->origin[0],\r
522                   e->origin[1] + fRadius * dc,\r
523                   e->origin[2] + fRadius * ds);\r
524                 break;\r
525               }\r
526             }\r
527           }\r
528         }\r
529         g_QglTable.m_pfn_qglEnd();\r
530       }\r
531       g_QglTable.m_pfn_qglPopAttrib();\r
532     }\r
533   }\r
534 }\r
535 \r
536 \r