3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
161 // lights are reloaded when this changes
162 char r_shadow_mapname[MAX_QPATH];
164 // used only for light filters (cubemaps)
165 rtexturepool_t *r_shadow_filters_texturepool;
167 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
168 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
169 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
170 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
171 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
172 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
173 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
174 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
175 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
176 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
177 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
178 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
179 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
180 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
181 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
182 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
183 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
184 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
185 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
186 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
187 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
188 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
189 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
190 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
191 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
192 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
193 cvar_t r_editlights = {0, "r_editlights", "0"};
194 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
195 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
196 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
197 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
198 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
199 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
200 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
202 float r_shadow_attenpower, r_shadow_attenscale;
204 rtlight_t *r_shadow_compilingrtlight;
205 dlight_t *r_shadow_worldlightchain;
206 dlight_t *r_shadow_selectedlight;
207 dlight_t r_shadow_bufferlight;
208 vec3_t r_editlights_cursorlocation;
210 rtexture_t *lighttextures[5];
212 extern int con_vislines;
214 typedef struct cubemapinfo_s
221 #define MAX_CUBEMAPS 256
222 static int numcubemaps;
223 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
225 GLhandleARB r_shadow_program_light_diffusegloss = 0;
226 GLhandleARB r_shadow_program_light_diffuse = 0;
227 GLhandleARB r_shadow_program_light_gloss = 0;
229 void R_Shadow_UncompileWorldLights(void);
230 void R_Shadow_ClearWorldLights(void);
231 void R_Shadow_SaveWorldLights(void);
232 void R_Shadow_LoadWorldLights(void);
233 void R_Shadow_LoadLightsFile(void);
234 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
235 void R_Shadow_EditLights_Reload_f(void);
236 void R_Shadow_ValidateCvars(void);
237 static void R_Shadow_MakeTextures(void);
238 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
240 // beginnings of GL_ARB_shaders support, not done yet
241 GLhandleARB GL_Backend_LoadProgram(const char *vertexshaderfilename, const char *fragmentshaderfilename)
246 void GL_Backend_FreeProgram(GLhandleARB prog)
250 void r_shadow_start(void)
252 // allocate vertex processing arrays
254 r_shadow_normalcubetexture = NULL;
255 r_shadow_attenuation2dtexture = NULL;
256 r_shadow_attenuation3dtexture = NULL;
257 r_shadow_blankbumptexture = NULL;
258 r_shadow_blankglosstexture = NULL;
259 r_shadow_blankwhitetexture = NULL;
260 r_shadow_texturepool = NULL;
261 r_shadow_filters_texturepool = NULL;
262 R_Shadow_ValidateCvars();
263 R_Shadow_MakeTextures();
264 maxshadowelements = 0;
265 shadowelements = NULL;
273 shadowmarklist = NULL;
275 r_shadow_buffer_numclusterpvsbytes = 0;
276 r_shadow_buffer_clusterpvs = NULL;
277 r_shadow_buffer_clusterlist = NULL;
278 r_shadow_buffer_numsurfacepvsbytes = 0;
279 r_shadow_buffer_surfacepvs = NULL;
280 r_shadow_buffer_surfacelist = NULL;
281 if (gl_support_fragment_shader)
283 r_shadow_program_light_diffusegloss = GL_Backend_LoadProgram("glsl/diffusegloss.vert", "glsl/diffusegloss.frag");
284 r_shadow_program_light_diffuse = GL_Backend_LoadProgram("glsl/diffuse.vert", "glsl/diffuse.frag");
285 r_shadow_program_light_gloss = GL_Backend_LoadProgram("glsl/gloss.vert", "glsl/gloss.frag");
289 void r_shadow_shutdown(void)
291 R_Shadow_UncompileWorldLights();
292 GL_Backend_FreeProgram(r_shadow_program_light_diffusegloss);
293 r_shadow_program_light_diffusegloss = 0;
294 GL_Backend_FreeProgram(r_shadow_program_light_diffuse);
295 r_shadow_program_light_diffuse = 0;
296 GL_Backend_FreeProgram(r_shadow_program_light_gloss);
297 r_shadow_program_light_gloss = 0;
299 r_shadow_normalcubetexture = NULL;
300 r_shadow_attenuation2dtexture = NULL;
301 r_shadow_attenuation3dtexture = NULL;
302 r_shadow_blankbumptexture = NULL;
303 r_shadow_blankglosstexture = NULL;
304 r_shadow_blankwhitetexture = NULL;
305 R_FreeTexturePool(&r_shadow_texturepool);
306 R_FreeTexturePool(&r_shadow_filters_texturepool);
307 maxshadowelements = 0;
309 Mem_Free(shadowelements);
310 shadowelements = NULL;
313 Mem_Free(vertexupdate);
316 Mem_Free(vertexremap);
322 Mem_Free(shadowmark);
325 Mem_Free(shadowmarklist);
326 shadowmarklist = NULL;
328 r_shadow_buffer_numclusterpvsbytes = 0;
329 if (r_shadow_buffer_clusterpvs)
330 Mem_Free(r_shadow_buffer_clusterpvs);
331 r_shadow_buffer_clusterpvs = NULL;
332 if (r_shadow_buffer_clusterlist)
333 Mem_Free(r_shadow_buffer_clusterlist);
334 r_shadow_buffer_clusterlist = NULL;
335 r_shadow_buffer_numsurfacepvsbytes = 0;
336 if (r_shadow_buffer_surfacepvs)
337 Mem_Free(r_shadow_buffer_surfacepvs);
338 r_shadow_buffer_surfacepvs = NULL;
339 if (r_shadow_buffer_surfacelist)
340 Mem_Free(r_shadow_buffer_surfacelist);
341 r_shadow_buffer_surfacelist = NULL;
344 void r_shadow_newmap(void)
348 void R_Shadow_Help_f(void)
351 "Documentation on r_shadow system:\n"
353 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
354 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
355 "r_shadow_debuglight : render only this light number (-1 = all)\n"
356 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
357 "r_shadow_gloss2intensity : brightness of forced gloss\n"
358 "r_shadow_glossintensity : brightness of textured gloss\n"
359 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
360 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
361 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
362 "r_shadow_portallight : use portal visibility for static light precomputation\n"
363 "r_shadow_projectdistance : shadow volume projection distance\n"
364 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
365 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
366 "r_shadow_realtime_world : use high quality world lighting mode\n"
367 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
368 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
369 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
370 "r_shadow_scissor : use scissor optimization\n"
371 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
372 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
373 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
374 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
375 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
377 "r_shadow_help : this help\n"
381 void R_Shadow_Init(void)
383 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
384 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
385 Cvar_RegisterVariable(&r_shadow_cull);
386 Cvar_RegisterVariable(&r_shadow_debuglight);
387 Cvar_RegisterVariable(&r_shadow_gloss);
388 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
389 Cvar_RegisterVariable(&r_shadow_glossintensity);
390 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
391 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
392 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
393 Cvar_RegisterVariable(&r_shadow_portallight);
394 Cvar_RegisterVariable(&r_shadow_projectdistance);
395 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
396 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
397 Cvar_RegisterVariable(&r_shadow_realtime_world);
398 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
399 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
400 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
401 Cvar_RegisterVariable(&r_shadow_scissor);
402 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
403 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
404 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
405 Cvar_RegisterVariable(&r_shadow_staticworldlights);
406 Cvar_RegisterVariable(&r_shadow_texture3d);
407 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
408 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
409 if (gamemode == GAME_TENEBRAE)
411 Cvar_SetValue("r_shadow_gloss", 2);
412 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
414 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
415 R_Shadow_EditLights_Init();
416 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
417 r_shadow_worldlightchain = NULL;
418 maxshadowelements = 0;
419 shadowelements = NULL;
427 shadowmarklist = NULL;
429 r_shadow_buffer_numclusterpvsbytes = 0;
430 r_shadow_buffer_clusterpvs = NULL;
431 r_shadow_buffer_clusterlist = NULL;
432 r_shadow_buffer_numsurfacepvsbytes = 0;
433 r_shadow_buffer_surfacepvs = NULL;
434 r_shadow_buffer_surfacelist = NULL;
435 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
438 matrix4x4_t matrix_attenuationxyz =
441 {0.5, 0.0, 0.0, 0.5},
442 {0.0, 0.5, 0.0, 0.5},
443 {0.0, 0.0, 0.5, 0.5},
448 matrix4x4_t matrix_attenuationz =
451 {0.0, 0.0, 0.5, 0.5},
452 {0.0, 0.0, 0.0, 0.5},
453 {0.0, 0.0, 0.0, 0.5},
458 int *R_Shadow_ResizeShadowElements(int numtris)
460 // make sure shadowelements is big enough for this volume
461 if (maxshadowelements < numtris * 24)
463 maxshadowelements = numtris * 24;
465 Mem_Free(shadowelements);
466 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
468 return shadowelements;
471 void R_Shadow_EnlargeClusterBuffer(int numclusters)
473 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
474 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
476 if (r_shadow_buffer_clusterpvs)
477 Mem_Free(r_shadow_buffer_clusterpvs);
478 if (r_shadow_buffer_clusterlist)
479 Mem_Free(r_shadow_buffer_clusterlist);
480 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
481 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
482 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
486 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
488 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
489 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
491 if (r_shadow_buffer_surfacepvs)
492 Mem_Free(r_shadow_buffer_surfacepvs);
493 if (r_shadow_buffer_surfacelist)
494 Mem_Free(r_shadow_buffer_surfacelist);
495 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
496 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
497 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
501 void R_Shadow_PrepareShadowMark(int numtris)
503 // make sure shadowmark is big enough for this volume
504 if (maxshadowmark < numtris)
506 maxshadowmark = numtris;
508 Mem_Free(shadowmark);
510 Mem_Free(shadowmarklist);
511 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
512 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
516 // if shadowmarkcount wrapped we clear the array and adjust accordingly
517 if (shadowmarkcount == 0)
520 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
525 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
527 int i, j, tris = 0, vr[3], t, outvertices = 0;
532 if (maxvertexupdate < innumvertices)
534 maxvertexupdate = innumvertices;
536 Mem_Free(vertexupdate);
538 Mem_Free(vertexremap);
539 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
540 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
544 if (vertexupdatenum == 0)
547 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
548 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
551 for (i = 0;i < numshadowmarktris;i++)
552 shadowmark[shadowmarktris[i]] = shadowmarkcount;
554 for (i = 0;i < numshadowmarktris;i++)
556 t = shadowmarktris[i];
557 e = inelement3i + t * 3;
558 // make sure the vertices are created
559 for (j = 0;j < 3;j++)
561 if (vertexupdate[e[j]] != vertexupdatenum)
563 vertexupdate[e[j]] = vertexupdatenum;
564 vertexremap[e[j]] = outvertices;
565 v = invertex3f + e[j] * 3;
566 // project one copy of the vertex to the sphere radius of the light
567 // (FIXME: would projecting it to the light box be better?)
568 VectorSubtract(v, projectorigin, temp);
569 f = projectdistance / VectorLength(temp);
570 VectorCopy(v, outvertex3f);
571 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
578 for (i = 0;i < numshadowmarktris;i++)
580 t = shadowmarktris[i];
581 e = inelement3i + t * 3;
582 n = inneighbor3i + t * 3;
583 // output the front and back triangles
584 outelement3i[0] = vertexremap[e[0]];
585 outelement3i[1] = vertexremap[e[1]];
586 outelement3i[2] = vertexremap[e[2]];
587 outelement3i[3] = vertexremap[e[2]] + 1;
588 outelement3i[4] = vertexremap[e[1]] + 1;
589 outelement3i[5] = vertexremap[e[0]] + 1;
592 // output the sides (facing outward from this triangle)
593 if (shadowmark[n[0]] != shadowmarkcount)
595 vr[0] = vertexremap[e[0]];
596 vr[1] = vertexremap[e[1]];
597 outelement3i[0] = vr[1];
598 outelement3i[1] = vr[0];
599 outelement3i[2] = vr[0] + 1;
600 outelement3i[3] = vr[1];
601 outelement3i[4] = vr[0] + 1;
602 outelement3i[5] = vr[1] + 1;
606 if (shadowmark[n[1]] != shadowmarkcount)
608 vr[1] = vertexremap[e[1]];
609 vr[2] = vertexremap[e[2]];
610 outelement3i[0] = vr[2];
611 outelement3i[1] = vr[1];
612 outelement3i[2] = vr[1] + 1;
613 outelement3i[3] = vr[2];
614 outelement3i[4] = vr[1] + 1;
615 outelement3i[5] = vr[2] + 1;
619 if (shadowmark[n[2]] != shadowmarkcount)
621 vr[0] = vertexremap[e[0]];
622 vr[2] = vertexremap[e[2]];
623 outelement3i[0] = vr[0];
624 outelement3i[1] = vr[2];
625 outelement3i[2] = vr[2] + 1;
626 outelement3i[3] = vr[0];
627 outelement3i[4] = vr[2] + 1;
628 outelement3i[5] = vr[0] + 1;
634 *outnumvertices = outvertices;
638 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
641 if (projectdistance < 0.1)
643 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
646 if (!numverts || !nummarktris)
648 // make sure shadowelements is big enough for this volume
649 if (maxshadowelements < nummarktris * 24)
650 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
651 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
652 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
655 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs)
660 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
662 tend = firsttriangle + numtris;
663 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
664 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
665 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
667 // surface box entirely inside light box, no box cull
668 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
669 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
670 shadowmarklist[numshadowmark++] = t;
674 // surface box not entirely inside light box, cull each triangle
675 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
677 v[0] = invertex3f + e[0] * 3;
678 v[1] = invertex3f + e[1] * 3;
679 v[2] = invertex3f + e[2] * 3;
680 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
681 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
682 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
683 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
684 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
685 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
686 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
687 shadowmarklist[numshadowmark++] = t;
692 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
695 if (r_shadow_compilingrtlight)
697 // if we're compiling an rtlight, capture the mesh
698 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
701 memset(&m, 0, sizeof(m));
702 m.pointer_vertex = vertex3f;
704 GL_LockArrays(0, numvertices);
705 if (r_shadowstage == SHADOWSTAGE_STENCIL)
707 // increment stencil if backface is behind depthbuffer
708 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
709 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
710 R_Mesh_Draw(numvertices, numtriangles, element3i);
712 c_rt_shadowtris += numtriangles;
713 // decrement stencil if frontface is behind depthbuffer
714 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
715 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
717 R_Mesh_Draw(numvertices, numtriangles, element3i);
719 c_rt_shadowtris += numtriangles;
723 static void R_Shadow_MakeTextures(void)
725 int x, y, z, d, side;
726 float v[3], s, t, intensity;
728 R_FreeTexturePool(&r_shadow_texturepool);
729 r_shadow_texturepool = R_AllocTexturePool();
730 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
731 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
733 #define ATTEN2DSIZE 64
734 #define ATTEN3DSIZE 32
735 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
740 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
745 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
750 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
751 if (gl_texturecubemap)
753 for (side = 0;side < 6;side++)
755 for (y = 0;y < NORMSIZE;y++)
757 for (x = 0;x < NORMSIZE;x++)
759 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
760 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
794 intensity = 127.0f / sqrt(DotProduct(v, v));
795 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
796 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
797 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
798 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
802 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
805 r_shadow_normalcubetexture = NULL;
806 for (y = 0;y < ATTEN2DSIZE;y++)
808 for (x = 0;x < ATTEN2DSIZE;x++)
810 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
811 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
813 intensity = 1.0f - sqrt(DotProduct(v, v));
815 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
816 d = bound(0, intensity, 255);
817 data[(y*ATTEN2DSIZE+x)*4+0] = d;
818 data[(y*ATTEN2DSIZE+x)*4+1] = d;
819 data[(y*ATTEN2DSIZE+x)*4+2] = d;
820 data[(y*ATTEN2DSIZE+x)*4+3] = d;
823 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
824 if (r_shadow_texture3d.integer)
826 for (z = 0;z < ATTEN3DSIZE;z++)
828 for (y = 0;y < ATTEN3DSIZE;y++)
830 for (x = 0;x < ATTEN3DSIZE;x++)
832 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
833 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
834 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
835 intensity = 1.0f - sqrt(DotProduct(v, v));
837 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
838 d = bound(0, intensity, 255);
839 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
840 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
841 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
842 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
846 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
851 void R_Shadow_ValidateCvars(void)
853 if (r_shadow_texture3d.integer && !gl_texture3d)
854 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
855 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
856 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
859 void R_Shadow_Stage_Begin(void)
863 R_Shadow_ValidateCvars();
865 if (!r_shadow_attenuation2dtexture
866 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
867 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
868 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
869 R_Shadow_MakeTextures();
871 memset(&m, 0, sizeof(m));
872 GL_BlendFunc(GL_ONE, GL_ZERO);
876 GL_Color(0, 0, 0, 1);
877 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
878 qglEnable(GL_CULL_FACE);
879 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
880 r_shadowstage = SHADOWSTAGE_NONE;
883 void R_Shadow_Stage_ShadowVolumes(void)
886 memset(&m, 0, sizeof(m));
888 GL_Color(1, 1, 1, 1);
889 GL_ColorMask(0, 0, 0, 0);
890 GL_BlendFunc(GL_ONE, GL_ZERO);
893 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
894 //if (r_shadow_shadow_polygonoffset.value != 0)
896 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
897 // qglEnable(GL_POLYGON_OFFSET_FILL);
900 // qglDisable(GL_POLYGON_OFFSET_FILL);
901 qglDepthFunc(GL_LESS);
902 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
903 qglEnable(GL_STENCIL_TEST);
904 qglStencilFunc(GL_ALWAYS, 128, ~0);
905 if (gl_ext_stenciltwoside.integer)
907 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
908 qglDisable(GL_CULL_FACE);
909 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
910 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
912 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
913 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
915 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
919 r_shadowstage = SHADOWSTAGE_STENCIL;
920 qglEnable(GL_CULL_FACE);
922 // this is changed by every shadow render so its value here is unimportant
923 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
925 GL_Clear(GL_STENCIL_BUFFER_BIT);
927 // LordHavoc note: many shadow volumes reside entirely inside the world
928 // (that is to say they are entirely bounded by their lit surfaces),
929 // which can be optimized by handling things as an inverted light volume,
930 // with the shadow boundaries of the world being simulated by an altered
931 // (129) bias to stencil clearing on such lights
932 // FIXME: generate inverted light volumes for use as shadow volumes and
933 // optimize for them as noted above
936 void R_Shadow_Stage_Light(int shadowtest)
939 memset(&m, 0, sizeof(m));
941 GL_BlendFunc(GL_ONE, GL_ONE);
944 qglPolygonOffset(0, 0);
945 //qglDisable(GL_POLYGON_OFFSET_FILL);
946 GL_Color(1, 1, 1, 1);
947 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
948 qglDepthFunc(GL_EQUAL);
949 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
950 qglEnable(GL_CULL_FACE);
952 qglEnable(GL_STENCIL_TEST);
954 qglDisable(GL_STENCIL_TEST);
955 if (gl_support_stenciltwoside)
956 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
958 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
959 // only draw light where this geometry was already rendered AND the
960 // stencil is 128 (values other than this mean shadow)
961 qglStencilFunc(GL_EQUAL, 128, ~0);
962 r_shadowstage = SHADOWSTAGE_LIGHT;
966 void R_Shadow_Stage_End(void)
969 memset(&m, 0, sizeof(m));
971 GL_BlendFunc(GL_ONE, GL_ZERO);
974 qglPolygonOffset(0, 0);
975 //qglDisable(GL_POLYGON_OFFSET_FILL);
976 GL_Color(1, 1, 1, 1);
977 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
978 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
979 qglDepthFunc(GL_LEQUAL);
980 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
981 qglDisable(GL_STENCIL_TEST);
982 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
983 if (gl_support_stenciltwoside)
984 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
986 qglStencilFunc(GL_ALWAYS, 128, ~0);
987 r_shadowstage = SHADOWSTAGE_NONE;
990 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
992 int i, ix1, iy1, ix2, iy2;
993 float x1, y1, x2, y2, x, y, f;
996 if (!r_shadow_scissor.integer)
998 // if view is inside the box, just say yes it's visible
999 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1001 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1004 for (i = 0;i < 3;i++)
1006 if (r_viewforward[i] >= 0)
1017 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1018 if (DotProduct(r_viewforward, v2) <= f)
1020 // entirely behind nearclip plane
1023 if (DotProduct(r_viewforward, v) >= f)
1025 // entirely infront of nearclip plane
1026 x1 = y1 = x2 = y2 = 0;
1027 for (i = 0;i < 8;i++)
1029 v[0] = (i & 1) ? mins[0] : maxs[0];
1030 v[1] = (i & 2) ? mins[1] : maxs[1];
1031 v[2] = (i & 4) ? mins[2] : maxs[2];
1033 GL_TransformToScreen(v, v2);
1034 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1053 // clipped by nearclip plane
1054 // this is nasty and crude...
1055 // create viewspace bbox
1056 for (i = 0;i < 8;i++)
1058 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1059 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1060 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1061 v2[0] = -DotProduct(v, r_viewleft);
1062 v2[1] = DotProduct(v, r_viewup);
1063 v2[2] = DotProduct(v, r_viewforward);
1066 if (smins[0] > v2[0]) smins[0] = v2[0];
1067 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1068 if (smins[1] > v2[1]) smins[1] = v2[1];
1069 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1070 if (smins[2] > v2[2]) smins[2] = v2[2];
1071 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1075 smins[0] = smaxs[0] = v2[0];
1076 smins[1] = smaxs[1] = v2[1];
1077 smins[2] = smaxs[2] = v2[2];
1080 // now we have a bbox in viewspace
1081 // clip it to the view plane
1084 // return true if that culled the box
1085 if (smins[2] >= smaxs[2])
1087 // ok some of it is infront of the view, transform each corner back to
1088 // worldspace and then to screenspace and make screen rect
1089 // initialize these variables just to avoid compiler warnings
1090 x1 = y1 = x2 = y2 = 0;
1091 for (i = 0;i < 8;i++)
1093 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1094 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1095 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1096 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1097 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1098 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1100 GL_TransformToScreen(v, v2);
1101 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1118 // this code doesn't handle boxes with any points behind view properly
1119 x1 = 1000;x2 = -1000;
1120 y1 = 1000;y2 = -1000;
1121 for (i = 0;i < 8;i++)
1123 v[0] = (i & 1) ? mins[0] : maxs[0];
1124 v[1] = (i & 2) ? mins[1] : maxs[1];
1125 v[2] = (i & 4) ? mins[2] : maxs[2];
1127 GL_TransformToScreen(v, v2);
1128 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1146 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1147 if (ix1 < r_view_x) ix1 = r_view_x;
1148 if (iy1 < r_view_y) iy1 = r_view_y;
1149 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1150 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1151 if (ix2 <= ix1 || iy2 <= iy1)
1153 // set up the scissor rectangle
1154 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1155 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1156 //qglEnable(GL_SCISSOR_TEST);
1161 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1163 float *color4f = varray_color4f;
1164 float dist, dot, intensity, v[3], n[3];
1165 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1167 Matrix4x4_Transform(m, vertex3f, v);
1168 if ((dist = DotProduct(v, v)) < 1)
1170 Matrix4x4_Transform3x3(m, normal3f, n);
1171 if ((dot = DotProduct(n, v)) > 0)
1174 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1175 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1176 VectorScale(lightcolor, intensity, color4f);
1181 VectorClear(color4f);
1187 VectorClear(color4f);
1193 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1195 float *color4f = varray_color4f;
1196 float dist, dot, intensity, v[3], n[3];
1197 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1199 Matrix4x4_Transform(m, vertex3f, v);
1200 if ((dist = fabs(v[2])) < 1)
1202 Matrix4x4_Transform3x3(m, normal3f, n);
1203 if ((dot = DotProduct(n, v)) > 0)
1205 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1206 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1207 VectorScale(lightcolor, intensity, color4f);
1212 VectorClear(color4f);
1218 VectorClear(color4f);
1224 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1226 float *color4f = varray_color4f;
1227 float dot, intensity, v[3], n[3];
1228 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1230 Matrix4x4_Transform(m, vertex3f, v);
1231 Matrix4x4_Transform3x3(m, normal3f, n);
1232 if ((dot = DotProduct(n, v)) > 0)
1234 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1235 VectorScale(lightcolor, intensity, color4f);
1240 VectorClear(color4f);
1246 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1248 float *color4f = varray_color4f;
1249 float dist, intensity, v[3];
1250 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1252 Matrix4x4_Transform(m, vertex3f, v);
1253 if ((dist = DotProduct(v, v)) < 1)
1256 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1257 VectorScale(lightcolor, intensity, color4f);
1262 VectorClear(color4f);
1268 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1270 float *color4f = varray_color4f;
1271 float dist, intensity, v[3];
1272 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1274 Matrix4x4_Transform(m, vertex3f, v);
1275 if ((dist = fabs(v[2])) < 1)
1277 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1278 VectorScale(lightcolor, intensity, color4f);
1283 VectorClear(color4f);
1289 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1290 #define USETEXMATRIX
1292 #ifndef USETEXMATRIX
1293 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1294 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1295 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1299 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1300 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1301 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1308 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1312 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1313 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1321 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
1325 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1327 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1328 // the cubemap normalizes this for us
1329 out3f[0] = DotProduct(svector3f, lightdir);
1330 out3f[1] = DotProduct(tvector3f, lightdir);
1331 out3f[2] = DotProduct(normal3f, lightdir);
1335 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
1338 float lightdir[3], eyedir[3], halfdir[3];
1339 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1341 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1342 VectorNormalizeFast(lightdir);
1343 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1344 VectorNormalizeFast(eyedir);
1345 VectorAdd(lightdir, eyedir, halfdir);
1346 // the cubemap normalizes this for us
1347 out3f[0] = DotProduct(svector3f, halfdir);
1348 out3f[1] = DotProduct(tvector3f, halfdir);
1349 out3f[2] = DotProduct(normal3f, halfdir);
1353 void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale)
1356 float color[3], color2[3], colorscale;
1359 bumptexture = r_shadow_blankbumptexture;
1361 glosstexture = r_shadow_blankglosstexture;
1362 // FIXME: support EF_NODEPTHTEST
1363 GL_DepthMask(false);
1365 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1370 colorscale = r_shadow_lightintensityscale.value * ambientscale;
1371 // colorscale accounts for how much we multiply the brightness
1374 // mult is how many times the final pass of the lighting will be
1375 // performed to get more brightness than otherwise possible.
1377 // Limit mult to 64 for sanity sake.
1378 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1380 // 3 3D combine path (Geforce3, Radeon 8500)
1381 memset(&m, 0, sizeof(m));
1382 m.pointer_vertex = vertex3f;
1383 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1385 m.pointer_texcoord3f[0] = vertex3f;
1386 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1388 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1389 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1391 m.tex[1] = R_GetTexture(basetexture);
1392 m.pointer_texcoord[1] = texcoord2f;
1393 m.texcubemap[2] = R_GetTexture(lightcubemap);
1395 m.pointer_texcoord3f[2] = vertex3f;
1396 m.texmatrix[2] = *matrix_modeltolight;
1398 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1399 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1402 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1404 // 2 3D combine path (Geforce3, original Radeon)
1405 memset(&m, 0, sizeof(m));
1406 m.pointer_vertex = vertex3f;
1407 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1409 m.pointer_texcoord3f[0] = vertex3f;
1410 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1412 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1413 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1415 m.tex[1] = R_GetTexture(basetexture);
1416 m.pointer_texcoord[1] = texcoord2f;
1418 else if (r_textureunits.integer >= 4 && lightcubemap)
1420 // 4 2D combine path (Geforce3, Radeon 8500)
1421 memset(&m, 0, sizeof(m));
1422 m.pointer_vertex = vertex3f;
1423 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1425 m.pointer_texcoord3f[0] = vertex3f;
1426 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1428 m.pointer_texcoord[0] = varray_texcoord2f[0];
1429 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1431 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1433 m.pointer_texcoord3f[1] = vertex3f;
1434 m.texmatrix[1] = *matrix_modeltoattenuationz;
1436 m.pointer_texcoord[1] = varray_texcoord2f[1];
1437 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1439 m.tex[2] = R_GetTexture(basetexture);
1440 m.pointer_texcoord[2] = texcoord2f;
1443 m.texcubemap[3] = R_GetTexture(lightcubemap);
1445 m.pointer_texcoord3f[3] = vertex3f;
1446 m.texmatrix[3] = *matrix_modeltolight;
1448 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1449 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1453 else if (r_textureunits.integer >= 3 && !lightcubemap)
1455 // 3 2D combine path (Geforce3, original Radeon)
1456 memset(&m, 0, sizeof(m));
1457 m.pointer_vertex = vertex3f;
1458 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1460 m.pointer_texcoord3f[0] = vertex3f;
1461 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1463 m.pointer_texcoord[0] = varray_texcoord2f[0];
1464 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1466 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1468 m.pointer_texcoord3f[1] = vertex3f;
1469 m.texmatrix[1] = *matrix_modeltoattenuationz;
1471 m.pointer_texcoord[1] = varray_texcoord2f[1];
1472 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1474 m.tex[2] = R_GetTexture(basetexture);
1475 m.pointer_texcoord[2] = texcoord2f;
1479 // 2/2/2 2D combine path (any dot3 card)
1480 memset(&m, 0, sizeof(m));
1481 m.pointer_vertex = vertex3f;
1482 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1484 m.pointer_texcoord3f[0] = vertex3f;
1485 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1487 m.pointer_texcoord[0] = varray_texcoord2f[0];
1488 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1490 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1492 m.pointer_texcoord3f[1] = vertex3f;
1493 m.texmatrix[1] = *matrix_modeltoattenuationz;
1495 m.pointer_texcoord[1] = varray_texcoord2f[1];
1496 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1499 GL_ColorMask(0,0,0,1);
1500 GL_BlendFunc(GL_ONE, GL_ZERO);
1501 GL_LockArrays(0, numverts);
1502 R_Mesh_Draw(numverts, numtriangles, elements);
1503 GL_LockArrays(0, 0);
1505 c_rt_lighttris += numtriangles;
1507 memset(&m, 0, sizeof(m));
1508 m.pointer_vertex = vertex3f;
1509 m.tex[0] = R_GetTexture(basetexture);
1510 m.pointer_texcoord[0] = texcoord2f;
1513 m.texcubemap[1] = R_GetTexture(lightcubemap);
1515 m.pointer_texcoord3f[1] = vertex3f;
1516 m.texmatrix[1] = *matrix_modeltolight;
1518 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1519 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1523 // this final code is shared
1525 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1526 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1527 VectorScale(lightcolor, colorscale, color2);
1528 GL_LockArrays(0, numverts);
1529 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1531 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1532 R_Mesh_Draw(numverts, numtriangles, elements);
1534 c_rt_lighttris += numtriangles;
1536 GL_LockArrays(0, 0);
1541 colorscale = r_shadow_lightintensityscale.value * diffusescale;
1542 // colorscale accounts for how much we multiply the brightness
1545 // mult is how many times the final pass of the lighting will be
1546 // performed to get more brightness than otherwise possible.
1548 // Limit mult to 64 for sanity sake.
1549 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1551 // 3/2 3D combine path (Geforce3, Radeon 8500)
1552 memset(&m, 0, sizeof(m));
1553 m.pointer_vertex = vertex3f;
1554 m.tex[0] = R_GetTexture(bumptexture);
1555 m.texcombinergb[0] = GL_REPLACE;
1556 m.pointer_texcoord[0] = texcoord2f;
1557 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1558 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1559 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1560 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1561 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1563 m.pointer_texcoord3f[2] = vertex3f;
1564 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1566 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1567 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1570 GL_ColorMask(0,0,0,1);
1571 GL_BlendFunc(GL_ONE, GL_ZERO);
1572 GL_LockArrays(0, numverts);
1573 R_Mesh_Draw(numverts, numtriangles, elements);
1574 GL_LockArrays(0, 0);
1576 c_rt_lighttris += numtriangles;
1578 memset(&m, 0, sizeof(m));
1579 m.pointer_vertex = vertex3f;
1580 m.tex[0] = R_GetTexture(basetexture);
1581 m.pointer_texcoord[0] = texcoord2f;
1584 m.texcubemap[1] = R_GetTexture(lightcubemap);
1586 m.pointer_texcoord3f[1] = vertex3f;
1587 m.texmatrix[1] = *matrix_modeltolight;
1589 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1590 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1594 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1596 // 1/2/2 3D combine path (original Radeon)
1597 memset(&m, 0, sizeof(m));
1598 m.pointer_vertex = vertex3f;
1599 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1601 m.pointer_texcoord3f[0] = vertex3f;
1602 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1604 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1605 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1608 GL_ColorMask(0,0,0,1);
1609 GL_BlendFunc(GL_ONE, GL_ZERO);
1610 GL_LockArrays(0, numverts);
1611 R_Mesh_Draw(numverts, numtriangles, elements);
1612 GL_LockArrays(0, 0);
1614 c_rt_lighttris += numtriangles;
1616 memset(&m, 0, sizeof(m));
1617 m.pointer_vertex = vertex3f;
1618 m.tex[0] = R_GetTexture(bumptexture);
1619 m.texcombinergb[0] = GL_REPLACE;
1620 m.pointer_texcoord[0] = texcoord2f;
1621 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1622 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1623 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1624 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1626 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1627 GL_LockArrays(0, numverts);
1628 R_Mesh_Draw(numverts, numtriangles, elements);
1629 GL_LockArrays(0, 0);
1631 c_rt_lighttris += numtriangles;
1633 memset(&m, 0, sizeof(m));
1634 m.pointer_vertex = vertex3f;
1635 m.tex[0] = R_GetTexture(basetexture);
1636 m.pointer_texcoord[0] = texcoord2f;
1639 m.texcubemap[1] = R_GetTexture(lightcubemap);
1641 m.pointer_texcoord3f[1] = vertex3f;
1642 m.texmatrix[1] = *matrix_modeltolight;
1644 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1645 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1649 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1651 // 2/2 3D combine path (original Radeon)
1652 memset(&m, 0, sizeof(m));
1653 m.pointer_vertex = vertex3f;
1654 m.tex[0] = R_GetTexture(bumptexture);
1655 m.texcombinergb[0] = GL_REPLACE;
1656 m.pointer_texcoord[0] = texcoord2f;
1657 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1658 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1659 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1660 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1662 GL_ColorMask(0,0,0,1);
1663 GL_BlendFunc(GL_ONE, GL_ZERO);
1664 GL_LockArrays(0, numverts);
1665 R_Mesh_Draw(numverts, numtriangles, elements);
1666 GL_LockArrays(0, 0);
1668 c_rt_lighttris += numtriangles;
1670 memset(&m, 0, sizeof(m));
1671 m.pointer_vertex = vertex3f;
1672 m.tex[0] = R_GetTexture(basetexture);
1673 m.pointer_texcoord[0] = texcoord2f;
1674 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1676 m.pointer_texcoord3f[1] = vertex3f;
1677 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1679 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1680 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1683 else if (r_textureunits.integer >= 4)
1685 // 4/2 2D combine path (Geforce3, Radeon 8500)
1686 memset(&m, 0, sizeof(m));
1687 m.pointer_vertex = vertex3f;
1688 m.tex[0] = R_GetTexture(bumptexture);
1689 m.texcombinergb[0] = GL_REPLACE;
1690 m.pointer_texcoord[0] = texcoord2f;
1691 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1692 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1693 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1694 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1695 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1697 m.pointer_texcoord3f[2] = vertex3f;
1698 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1700 m.pointer_texcoord[2] = varray_texcoord2f[2];
1701 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1703 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1705 m.pointer_texcoord3f[3] = vertex3f;
1706 m.texmatrix[3] = *matrix_modeltoattenuationz;
1708 m.pointer_texcoord[3] = varray_texcoord2f[3];
1709 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1712 GL_ColorMask(0,0,0,1);
1713 GL_BlendFunc(GL_ONE, GL_ZERO);
1714 GL_LockArrays(0, numverts);
1715 R_Mesh_Draw(numverts, numtriangles, elements);
1716 GL_LockArrays(0, 0);
1718 c_rt_lighttris += numtriangles;
1720 memset(&m, 0, sizeof(m));
1721 m.pointer_vertex = vertex3f;
1722 m.tex[0] = R_GetTexture(basetexture);
1723 m.pointer_texcoord[0] = texcoord2f;
1726 m.texcubemap[1] = R_GetTexture(lightcubemap);
1728 m.pointer_texcoord3f[1] = vertex3f;
1729 m.texmatrix[1] = *matrix_modeltolight;
1731 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1732 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1738 // 2/2/2 2D combine path (any dot3 card)
1739 memset(&m, 0, sizeof(m));
1740 m.pointer_vertex = vertex3f;
1741 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1743 m.pointer_texcoord3f[0] = vertex3f;
1744 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1746 m.pointer_texcoord[0] = varray_texcoord2f[0];
1747 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1749 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1751 m.pointer_texcoord3f[1] = vertex3f;
1752 m.texmatrix[1] = *matrix_modeltoattenuationz;
1754 m.pointer_texcoord[1] = varray_texcoord2f[1];
1755 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1758 GL_ColorMask(0,0,0,1);
1759 GL_BlendFunc(GL_ONE, GL_ZERO);
1760 GL_LockArrays(0, numverts);
1761 R_Mesh_Draw(numverts, numtriangles, elements);
1762 GL_LockArrays(0, 0);
1764 c_rt_lighttris += numtriangles;
1766 memset(&m, 0, sizeof(m));
1767 m.pointer_vertex = vertex3f;
1768 m.tex[0] = R_GetTexture(bumptexture);
1769 m.texcombinergb[0] = GL_REPLACE;
1770 m.pointer_texcoord[0] = texcoord2f;
1771 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1772 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1773 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1774 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1776 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1777 GL_LockArrays(0, numverts);
1778 R_Mesh_Draw(numverts, numtriangles, elements);
1779 GL_LockArrays(0, 0);
1781 c_rt_lighttris += numtriangles;
1783 memset(&m, 0, sizeof(m));
1784 m.pointer_vertex = vertex3f;
1785 m.tex[0] = R_GetTexture(basetexture);
1786 m.pointer_texcoord[0] = texcoord2f;
1789 m.texcubemap[1] = R_GetTexture(lightcubemap);
1791 m.pointer_texcoord3f[1] = vertex3f;
1792 m.texmatrix[1] = *matrix_modeltolight;
1794 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1795 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1799 // this final code is shared
1801 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1802 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1803 VectorScale(lightcolor, colorscale, color2);
1804 GL_LockArrays(0, numverts);
1805 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1807 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1808 R_Mesh_Draw(numverts, numtriangles, elements);
1810 c_rt_lighttris += numtriangles;
1812 GL_LockArrays(0, 0);
1814 if (specularscale && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1816 // FIXME: detect blendsquare!
1817 //if (gl_support_blendsquare)
1819 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value * specularscale;
1820 if (glosstexture == r_shadow_blankglosstexture)
1821 colorscale *= r_shadow_gloss2intensity.value;
1823 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1825 // 2/0/0/1/2 3D combine blendsquare path
1826 memset(&m, 0, sizeof(m));
1827 m.pointer_vertex = vertex3f;
1828 m.tex[0] = R_GetTexture(bumptexture);
1829 m.pointer_texcoord[0] = texcoord2f;
1830 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1831 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1832 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1833 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1835 GL_ColorMask(0,0,0,1);
1836 // this squares the result
1837 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1838 GL_LockArrays(0, numverts);
1839 R_Mesh_Draw(numverts, numtriangles, elements);
1840 GL_LockArrays(0, 0);
1842 c_rt_lighttris += numtriangles;
1844 memset(&m, 0, sizeof(m));
1845 m.pointer_vertex = vertex3f;
1847 GL_LockArrays(0, numverts);
1848 // square alpha in framebuffer a few times to make it shiny
1849 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1850 // these comments are a test run through this math for intensity 0.5
1851 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1852 // 0.25 * 0.25 = 0.0625 (this is another pass)
1853 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1854 R_Mesh_Draw(numverts, numtriangles, elements);
1856 c_rt_lighttris += numtriangles;
1857 R_Mesh_Draw(numverts, numtriangles, elements);
1859 c_rt_lighttris += numtriangles;
1860 GL_LockArrays(0, 0);
1862 memset(&m, 0, sizeof(m));
1863 m.pointer_vertex = vertex3f;
1864 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1866 m.pointer_texcoord3f[0] = vertex3f;
1867 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1869 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1870 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1873 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1874 GL_LockArrays(0, numverts);
1875 R_Mesh_Draw(numverts, numtriangles, elements);
1876 GL_LockArrays(0, 0);
1878 c_rt_lighttris += numtriangles;
1880 memset(&m, 0, sizeof(m));
1881 m.pointer_vertex = vertex3f;
1882 m.tex[0] = R_GetTexture(glosstexture);
1883 m.pointer_texcoord[0] = texcoord2f;
1886 m.texcubemap[1] = R_GetTexture(lightcubemap);
1888 m.pointer_texcoord3f[1] = vertex3f;
1889 m.texmatrix[1] = *matrix_modeltolight;
1891 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1892 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1896 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1898 // 2/0/0/2 3D combine blendsquare path
1899 memset(&m, 0, sizeof(m));
1900 m.pointer_vertex = vertex3f;
1901 m.tex[0] = R_GetTexture(bumptexture);
1902 m.pointer_texcoord[0] = texcoord2f;
1903 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1904 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1905 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1906 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1908 GL_ColorMask(0,0,0,1);
1909 // this squares the result
1910 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1911 GL_LockArrays(0, numverts);
1912 R_Mesh_Draw(numverts, numtriangles, elements);
1913 GL_LockArrays(0, 0);
1915 c_rt_lighttris += numtriangles;
1917 memset(&m, 0, sizeof(m));
1918 m.pointer_vertex = vertex3f;
1920 GL_LockArrays(0, numverts);
1921 // square alpha in framebuffer a few times to make it shiny
1922 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1923 // these comments are a test run through this math for intensity 0.5
1924 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1925 // 0.25 * 0.25 = 0.0625 (this is another pass)
1926 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1927 R_Mesh_Draw(numverts, numtriangles, elements);
1929 c_rt_lighttris += numtriangles;
1930 R_Mesh_Draw(numverts, numtriangles, elements);
1932 c_rt_lighttris += numtriangles;
1933 GL_LockArrays(0, 0);
1935 memset(&m, 0, sizeof(m));
1936 m.pointer_vertex = vertex3f;
1937 m.tex[0] = R_GetTexture(glosstexture);
1938 m.pointer_texcoord[0] = texcoord2f;
1939 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1941 m.pointer_texcoord3f[1] = vertex3f;
1942 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1944 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1945 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1950 // 2/0/0/2/2 2D combine blendsquare path
1951 memset(&m, 0, sizeof(m));
1952 m.pointer_vertex = vertex3f;
1953 m.tex[0] = R_GetTexture(bumptexture);
1954 m.pointer_texcoord[0] = texcoord2f;
1955 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1956 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1957 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1958 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1960 GL_ColorMask(0,0,0,1);
1961 // this squares the result
1962 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1963 GL_LockArrays(0, numverts);
1964 R_Mesh_Draw(numverts, numtriangles, elements);
1965 GL_LockArrays(0, 0);
1967 c_rt_lighttris += numtriangles;
1969 memset(&m, 0, sizeof(m));
1970 m.pointer_vertex = vertex3f;
1972 GL_LockArrays(0, numverts);
1973 // square alpha in framebuffer a few times to make it shiny
1974 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1975 // these comments are a test run through this math for intensity 0.5
1976 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1977 // 0.25 * 0.25 = 0.0625 (this is another pass)
1978 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1979 R_Mesh_Draw(numverts, numtriangles, elements);
1981 c_rt_lighttris += numtriangles;
1982 R_Mesh_Draw(numverts, numtriangles, elements);
1984 c_rt_lighttris += numtriangles;
1985 GL_LockArrays(0, 0);
1987 memset(&m, 0, sizeof(m));
1988 m.pointer_vertex = vertex3f;
1989 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1991 m.pointer_texcoord3f[0] = vertex3f;
1992 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1994 m.pointer_texcoord[0] = varray_texcoord2f[0];
1995 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1997 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1999 m.pointer_texcoord3f[1] = vertex3f;
2000 m.texmatrix[1] = *matrix_modeltoattenuationz;
2002 m.pointer_texcoord[1] = varray_texcoord2f[1];
2003 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2006 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2007 GL_LockArrays(0, numverts);
2008 R_Mesh_Draw(numverts, numtriangles, elements);
2009 GL_LockArrays(0, 0);
2011 c_rt_lighttris += numtriangles;
2013 memset(&m, 0, sizeof(m));
2014 m.pointer_vertex = vertex3f;
2015 m.tex[0] = R_GetTexture(glosstexture);
2016 m.pointer_texcoord[0] = texcoord2f;
2019 m.texcubemap[1] = R_GetTexture(lightcubemap);
2021 m.pointer_texcoord3f[1] = vertex3f;
2022 m.texmatrix[1] = *matrix_modeltolight;
2024 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2025 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2030 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2031 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2032 VectorScale(lightcolor, colorscale, color2);
2033 GL_LockArrays(0, numverts);
2034 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2036 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2037 R_Mesh_Draw(numverts, numtriangles, elements);
2039 c_rt_lighttris += numtriangles;
2041 GL_LockArrays(0, 0);
2049 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2050 VectorScale(lightcolor, r_shadow_lightintensityscale.value * ambientscale, color2);
2051 memset(&m, 0, sizeof(m));
2052 m.pointer_vertex = vertex3f;
2053 m.tex[0] = R_GetTexture(basetexture);
2054 m.pointer_texcoord[0] = texcoord2f;
2055 if (r_textureunits.integer >= 2)
2058 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2060 m.pointer_texcoord3f[1] = vertex3f;
2061 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2063 m.pointer_texcoord[1] = varray_texcoord2f[1];
2064 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2066 if (r_textureunits.integer >= 3)
2068 // Geforce3/Radeon class but not using dot3
2069 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2071 m.pointer_texcoord3f[2] = vertex3f;
2072 m.texmatrix[2] = *matrix_modeltoattenuationz;
2074 m.pointer_texcoord[2] = varray_texcoord2f[2];
2075 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2079 if (r_textureunits.integer >= 3)
2080 m.pointer_color = NULL;
2082 m.pointer_color = varray_color4f;
2084 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2086 color[0] = bound(0, color2[0], 1);
2087 color[1] = bound(0, color2[1], 1);
2088 color[2] = bound(0, color2[2], 1);
2089 if (r_textureunits.integer >= 3)
2090 GL_Color(color[0], color[1], color[2], 1);
2091 else if (r_textureunits.integer >= 2)
2092 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2094 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2095 GL_LockArrays(0, numverts);
2096 R_Mesh_Draw(numverts, numtriangles, elements);
2097 GL_LockArrays(0, 0);
2099 c_rt_lighttris += numtriangles;
2104 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2105 VectorScale(lightcolor, r_shadow_lightintensityscale.value * diffusescale, color2);
2106 memset(&m, 0, sizeof(m));
2107 m.pointer_vertex = vertex3f;
2108 m.pointer_color = varray_color4f;
2109 m.tex[0] = R_GetTexture(basetexture);
2110 m.pointer_texcoord[0] = texcoord2f;
2111 if (r_textureunits.integer >= 2)
2114 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2116 m.pointer_texcoord3f[1] = vertex3f;
2117 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2119 m.pointer_texcoord[1] = varray_texcoord2f[1];
2120 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2122 if (r_textureunits.integer >= 3)
2124 // Geforce3/Radeon class but not using dot3
2125 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2127 m.pointer_texcoord3f[2] = vertex3f;
2128 m.texmatrix[2] = *matrix_modeltoattenuationz;
2130 m.pointer_texcoord[2] = varray_texcoord2f[2];
2131 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2136 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2138 color[0] = bound(0, color2[0], 1);
2139 color[1] = bound(0, color2[1], 1);
2140 color[2] = bound(0, color2[2], 1);
2141 if (r_textureunits.integer >= 3)
2142 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2143 else if (r_textureunits.integer >= 2)
2144 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2146 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2147 GL_LockArrays(0, numverts);
2148 R_Mesh_Draw(numverts, numtriangles, elements);
2149 GL_LockArrays(0, 0);
2151 c_rt_lighttris += numtriangles;
2157 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2161 R_RTLight_Uncompile(rtlight);
2162 memset(rtlight, 0, sizeof(*rtlight));
2164 VectorCopy(light->origin, rtlight->shadoworigin);
2165 VectorCopy(light->color, rtlight->color);
2166 rtlight->radius = light->radius;
2167 //rtlight->cullradius = rtlight->radius;
2168 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2169 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2170 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2171 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2172 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2173 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2174 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2175 rtlight->cubemapname[0] = 0;
2176 if (light->cubemapname[0])
2177 strcpy(rtlight->cubemapname, light->cubemapname);
2178 else if (light->cubemapnum > 0)
2179 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2180 rtlight->shadow = light->shadow;
2181 rtlight->corona = light->corona;
2182 rtlight->style = light->style;
2183 rtlight->isstatic = isstatic;
2184 rtlight->coronasizescale = light->coronasizescale;
2185 rtlight->ambientscale = light->ambientscale;
2186 rtlight->diffusescale = light->diffusescale;
2187 rtlight->specularscale = light->specularscale;
2188 rtlight->flags = light->flags;
2189 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2190 // ConcatScale won't work here because this needs to scale rotate and
2191 // translate, not just rotate
2192 scale = 1.0f / rtlight->radius;
2193 for (k = 0;k < 3;k++)
2194 for (j = 0;j < 4;j++)
2195 rtlight->matrix_worldtolight.m[k][j] *= scale;
2196 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2197 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2199 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2200 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2201 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2202 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2205 // compiles rtlight geometry
2206 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2207 void R_RTLight_Compile(rtlight_t *rtlight)
2209 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2210 entity_render_t *ent = &cl_entities[0].render;
2211 model_t *model = ent->model;
2213 // compile the light
2214 rtlight->compiled = true;
2215 rtlight->static_numclusters = 0;
2216 rtlight->static_numclusterpvsbytes = 0;
2217 rtlight->static_clusterlist = NULL;
2218 rtlight->static_clusterpvs = NULL;
2219 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2220 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2221 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2222 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2223 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2224 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2226 if (model && model->GetLightInfo)
2228 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2229 r_shadow_compilingrtlight = rtlight;
2230 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2231 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2232 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2235 rtlight->static_numclusters = numclusters;
2236 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2237 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2238 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2239 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2240 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2242 if (model->DrawShadowVolume && rtlight->shadow)
2244 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2245 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2246 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2248 if (model->DrawLight)
2250 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2251 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, 0, 0, 0, numsurfaces, r_shadow_buffer_surfacelist);
2252 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2254 // switch back to rendering when DrawShadowVolume or DrawLight is called
2255 r_shadow_compilingrtlight = NULL;
2259 // use smallest available cullradius - box radius or light radius
2260 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2261 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2265 if (rtlight->static_meshchain_shadow)
2268 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2271 shadowtris += mesh->numtriangles;
2277 if (rtlight->static_meshchain_light)
2280 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2283 lighttris += mesh->numtriangles;
2287 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes), %i light triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes, lighttris, lightmeshes);
2290 void R_RTLight_Uncompile(rtlight_t *rtlight)
2292 if (rtlight->compiled)
2294 if (rtlight->static_meshchain_shadow)
2295 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2296 rtlight->static_meshchain_shadow = NULL;
2297 if (rtlight->static_meshchain_light)
2298 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2299 rtlight->static_meshchain_light = NULL;
2300 if (rtlight->static_clusterlist)
2301 Mem_Free(rtlight->static_clusterlist);
2302 rtlight->static_clusterlist = NULL;
2303 if (rtlight->static_clusterpvs)
2304 Mem_Free(rtlight->static_clusterpvs);
2305 rtlight->static_clusterpvs = NULL;
2306 rtlight->static_numclusters = 0;
2307 rtlight->static_numclusterpvsbytes = 0;
2308 rtlight->compiled = false;
2312 void R_Shadow_UncompileWorldLights(void)
2315 for (light = r_shadow_worldlightchain;light;light = light->next)
2316 R_RTLight_Uncompile(&light->rtlight);
2319 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2322 entity_render_t *ent;
2324 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2325 rtexture_t *cubemaptexture;
2326 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2327 int numclusters, numsurfaces;
2328 int *clusterlist, *surfacelist;
2330 vec3_t cullmins, cullmaxs;
2334 // skip lights that don't light (corona only lights)
2335 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2338 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f);
2339 VectorScale(rtlight->color, f, lightcolor);
2340 if (VectorLength2(lightcolor) < 0.01)
2343 if (rtlight->selected)
2345 f = 2 + sin(realtime * M_PI * 4.0);
2346 VectorScale(lightcolor, f, lightcolor);
2350 // loading is done before visibility checks because loading should happen
2351 // all at once at the start of a level, not when it stalls gameplay.
2352 // (especially important to benchmarks)
2353 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2354 R_RTLight_Compile(rtlight);
2355 if (rtlight->cubemapname[0])
2356 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2358 cubemaptexture = NULL;
2360 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2361 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2362 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2363 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2364 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2365 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2366 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2373 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2375 // compiled light, world available and can receive realtime lighting
2376 // retrieve cluster information
2377 numclusters = rtlight->static_numclusters;
2378 clusterlist = rtlight->static_clusterlist;
2379 clusterpvs = rtlight->static_clusterpvs;
2380 VectorCopy(rtlight->cullmins, cullmins);
2381 VectorCopy(rtlight->cullmaxs, cullmaxs);
2383 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2385 // dynamic light, world available and can receive realtime lighting
2386 // if the light box is offscreen, skip it right away
2387 if (R_CullBox(cullmins, cullmaxs))
2389 // calculate lit surfaces and clusters
2390 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2391 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2392 r_refdef.worldmodel->GetLightInfo(&cl_entities[0].render, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2393 clusterlist = r_shadow_buffer_clusterlist;
2394 clusterpvs = r_shadow_buffer_clusterpvs;
2395 surfacelist = r_shadow_buffer_surfacelist;
2397 // if the reduced cluster bounds are offscreen, skip it
2398 if (R_CullBox(cullmins, cullmaxs))
2400 // check if light is illuminating any visible clusters
2403 for (i = 0;i < numclusters;i++)
2404 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2406 if (i == numclusters)
2409 // set up a scissor rectangle for this light
2410 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2413 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2415 if (shadow && (gl_stencil || visiblevolumes))
2417 if (!visiblevolumes)
2418 R_Shadow_Stage_ShadowVolumes();
2419 ent = &cl_entities[0].render;
2420 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2422 memset(&m, 0, sizeof(m));
2423 R_Mesh_Matrix(&ent->matrix);
2424 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2426 m.pointer_vertex = mesh->vertex3f;
2428 GL_LockArrays(0, mesh->numverts);
2429 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2431 // increment stencil if backface is behind depthbuffer
2432 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2433 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2434 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2435 c_rtcached_shadowmeshes++;
2436 c_rtcached_shadowtris += mesh->numtriangles;
2437 // decrement stencil if frontface is behind depthbuffer
2438 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2439 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2441 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2442 c_rtcached_shadowmeshes++;
2443 c_rtcached_shadowtris += mesh->numtriangles;
2444 GL_LockArrays(0, 0);
2447 else if (numsurfaces)
2449 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2450 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2452 if (r_drawentities.integer)
2454 for (i = 0;i < r_refdef.numentities;i++)
2456 ent = r_refdef.entities[i];
2458 if (r_shadow_cull.integer)
2460 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2462 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2465 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2467 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2468 // light emitting entities should not cast their own shadow
2469 if (VectorLength2(relativelightorigin) < 0.1)
2471 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2476 if (!visiblevolumes)
2478 R_Shadow_Stage_Light(shadow && gl_stencil);
2480 ent = &cl_entities[0].render;
2481 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2483 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2484 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2485 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2486 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2487 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2488 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2489 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2490 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2491 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2493 R_Mesh_Matrix(&ent->matrix);
2494 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2495 R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale);
2498 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2500 if (r_drawentities.integer)
2502 for (i = 0;i < r_refdef.numentities;i++)
2504 ent = r_refdef.entities[i];
2505 // can't draw transparent entity lighting here because
2506 // transparent meshes are deferred for later
2507 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT)
2509 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2510 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2511 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2512 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2513 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2514 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2515 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2516 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2517 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, ent->model->nummodelsurfaces, ent->model->surfacelist);
2524 void R_ShadowVolumeLighting(int visiblevolumes)
2530 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2531 R_Shadow_EditLights_Reload_f();
2535 memset(&m, 0, sizeof(m));
2538 GL_BlendFunc(GL_ONE, GL_ONE);
2539 GL_DepthMask(false);
2540 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2541 qglDisable(GL_CULL_FACE);
2542 GL_Color(0.0, 0.0125, 0.1, 1);
2545 R_Shadow_Stage_Begin();
2546 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2547 if (r_shadow_debuglight.integer >= 0)
2549 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2550 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2551 R_DrawRTLight(&light->rtlight, visiblevolumes);
2554 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2555 if (light->flags & flag)
2556 R_DrawRTLight(&light->rtlight, visiblevolumes);
2558 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2559 R_DrawRTLight(&light->rtlight, visiblevolumes);
2563 qglEnable(GL_CULL_FACE);
2564 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2567 R_Shadow_Stage_End();
2570 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2571 typedef struct suffixinfo_s
2574 qboolean flipx, flipy, flipdiagonal;
2577 static suffixinfo_t suffix[3][6] =
2580 {"px", false, false, false},
2581 {"nx", false, false, false},
2582 {"py", false, false, false},
2583 {"ny", false, false, false},
2584 {"pz", false, false, false},
2585 {"nz", false, false, false}
2588 {"posx", false, false, false},
2589 {"negx", false, false, false},
2590 {"posy", false, false, false},
2591 {"negy", false, false, false},
2592 {"posz", false, false, false},
2593 {"negz", false, false, false}
2596 {"rt", true, false, true},
2597 {"lf", false, true, true},
2598 {"ft", true, true, false},
2599 {"bk", false, false, false},
2600 {"up", true, false, true},
2601 {"dn", true, false, true}
2605 static int componentorder[4] = {0, 1, 2, 3};
2607 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2609 int i, j, cubemapsize;
2610 qbyte *cubemappixels, *image_rgba;
2611 rtexture_t *cubemaptexture;
2613 // must start 0 so the first loadimagepixels has no requested width/height
2615 cubemappixels = NULL;
2616 cubemaptexture = NULL;
2617 // keep trying different suffix groups (posx, px, rt) until one loads
2618 for (j = 0;j < 3 && !cubemappixels;j++)
2620 // load the 6 images in the suffix group
2621 for (i = 0;i < 6;i++)
2623 // generate an image name based on the base and and suffix
2624 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2626 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2628 // an image loaded, make sure width and height are equal
2629 if (image_width == image_height)
2631 // if this is the first image to load successfully, allocate the cubemap memory
2632 if (!cubemappixels && image_width >= 1)
2634 cubemapsize = image_width;
2635 // note this clears to black, so unavailable sides are black
2636 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2638 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2640 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_rgba, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2643 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2645 Mem_Free(image_rgba);
2649 // if a cubemap loaded, upload it
2652 if (!r_shadow_filters_texturepool)
2653 r_shadow_filters_texturepool = R_AllocTexturePool();
2654 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2655 Mem_Free(cubemappixels);
2659 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2660 for (j = 0;j < 3;j++)
2661 for (i = 0;i < 6;i++)
2662 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2663 Con_Print(" and was unable to find any of them.\n");
2665 return cubemaptexture;
2668 rtexture_t *R_Shadow_Cubemap(const char *basename)
2671 for (i = 0;i < numcubemaps;i++)
2672 if (!strcasecmp(cubemaps[i].basename, basename))
2673 return cubemaps[i].texture;
2674 if (i >= MAX_CUBEMAPS)
2677 strcpy(cubemaps[i].basename, basename);
2678 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2679 return cubemaps[i].texture;
2682 void R_Shadow_FreeCubemaps(void)
2685 R_FreeTexturePool(&r_shadow_filters_texturepool);
2688 dlight_t *R_Shadow_NewWorldLight(void)
2691 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2692 light->next = r_shadow_worldlightchain;
2693 r_shadow_worldlightchain = light;
2697 void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2699 VectorCopy(origin, light->origin);
2700 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2701 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2702 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2703 light->color[0] = max(color[0], 0);
2704 light->color[1] = max(color[1], 0);
2705 light->color[2] = max(color[2], 0);
2706 light->radius = max(radius, 0);
2707 light->style = style;
2708 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2710 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2713 light->shadow = shadowenable;
2714 light->corona = corona;
2717 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
2718 light->coronasizescale = coronasizescale;
2719 light->ambientscale = ambientscale;
2720 light->diffusescale = diffusescale;
2721 light->specularscale = specularscale;
2722 light->flags = flags;
2723 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2725 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2728 void R_Shadow_FreeWorldLight(dlight_t *light)
2730 dlight_t **lightpointer;
2731 R_RTLight_Uncompile(&light->rtlight);
2732 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2733 if (*lightpointer != light)
2734 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2735 *lightpointer = light->next;
2739 void R_Shadow_ClearWorldLights(void)
2741 while (r_shadow_worldlightchain)
2742 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2743 r_shadow_selectedlight = NULL;
2744 R_Shadow_FreeCubemaps();
2747 void R_Shadow_SelectLight(dlight_t *light)
2749 if (r_shadow_selectedlight)
2750 r_shadow_selectedlight->selected = false;
2751 r_shadow_selectedlight = light;
2752 if (r_shadow_selectedlight)
2753 r_shadow_selectedlight->selected = true;
2756 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2758 float scale = r_editlights_cursorgrid.value * 0.5f;
2759 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[0], false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
2762 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2765 const dlight_t *light;
2768 if (light->selected)
2769 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2772 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[calldata2], false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
2775 void R_Shadow_DrawLightSprites(void)
2781 for (i = 0;i < 5;i++)
2783 lighttextures[i] = NULL;
2784 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2785 lighttextures[i] = pic->tex;
2788 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2789 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
2790 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2793 void R_Shadow_SelectLightInView(void)
2795 float bestrating, rating, temp[3];
2796 dlight_t *best, *light;
2799 for (light = r_shadow_worldlightchain;light;light = light->next)
2801 VectorSubtract(light->origin, r_vieworigin, temp);
2802 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2805 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2806 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2808 bestrating = rating;
2813 R_Shadow_SelectLight(best);
2816 void R_Shadow_LoadWorldLights(void)
2818 int n, a, style, shadow, flags;
2819 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2820 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2821 if (r_refdef.worldmodel == NULL)
2823 Con_Print("No map loaded.\n");
2826 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2827 strlcat (name, ".rtlights", sizeof (name));
2828 lightsstring = FS_LoadFile(name, tempmempool, false);
2838 for (;COM_Parse(t, true) && strcmp(
2839 if (COM_Parse(t, true))
2841 if (com_token[0] == '!')
2844 origin[0] = atof(com_token+1);
2847 origin[0] = atof(com_token);
2852 while (*s && *s != '\n')
2858 // check for modifier flags
2864 a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
2866 flags = LIGHTFLAG_REALTIMEMODE;
2874 coronasizescale = 0.25f;
2876 VectorClear(angles);
2879 if (a < 9 || !strcmp(cubemapname, "\"\""))
2881 // remove quotes on cubemapname
2882 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2884 cubemapname[strlen(cubemapname)-1] = 0;
2885 strcpy(cubemapname, cubemapname + 1);
2890 Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1);
2893 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2894 radius *= r_editlights_rtlightssizescale.value;
2895 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2900 Con_Printf("invalid rtlights file \"%s\"\n", name);
2901 Mem_Free(lightsstring);
2905 void R_Shadow_SaveWorldLights(void)
2908 int bufchars, bufmaxchars;
2910 char name[MAX_QPATH];
2912 if (!r_shadow_worldlightchain)
2914 if (r_refdef.worldmodel == NULL)
2916 Con_Print("No map loaded.\n");
2919 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2920 strlcat (name, ".rtlights", sizeof (name));
2921 bufchars = bufmaxchars = 0;
2923 for (light = r_shadow_worldlightchain;light;light = light->next)
2925 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2926 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
2927 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2928 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
2930 sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style);
2931 if (bufchars + (int) strlen(line) > bufmaxchars)
2933 bufmaxchars = bufchars + strlen(line) + 2048;
2935 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2939 memcpy(buf, oldbuf, bufchars);
2945 memcpy(buf + bufchars, line, strlen(line));
2946 bufchars += strlen(line);
2950 FS_WriteFile(name, buf, bufchars);
2955 void R_Shadow_LoadLightsFile(void)
2958 char name[MAX_QPATH], *lightsstring, *s, *t;
2959 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2960 if (r_refdef.worldmodel == NULL)
2962 Con_Print("No map loaded.\n");
2965 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2966 strlcat (name, ".lights", sizeof (name));
2967 lightsstring = FS_LoadFile(name, tempmempool, false);
2975 while (*s && *s != '\n')
2980 a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style);
2984 Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
2987 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2988 radius = bound(15, radius, 4096);
2989 VectorScale(color, (2.0f / (8388608.0f)), color);
2990 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2995 Con_Printf("invalid lights file \"%s\"\n", name);
2996 Mem_Free(lightsstring);
3000 // tyrlite/hmap2 light types in the delay field
3001 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3003 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3005 int entnum, style, islight, skin, pflags, effects, type, n;
3008 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3009 char key[256], value[1024];
3011 if (r_refdef.worldmodel == NULL)
3013 Con_Print("No map loaded.\n");
3016 // try to load a .ent file first
3017 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3018 strlcat (key, ".ent", sizeof (key));
3019 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3020 // and if that is not found, fall back to the bsp file entity string
3022 data = r_refdef.worldmodel->brush.entities;
3025 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3027 type = LIGHTTYPE_MINUSX;
3028 origin[0] = origin[1] = origin[2] = 0;
3029 originhack[0] = originhack[1] = originhack[2] = 0;
3030 angles[0] = angles[1] = angles[2] = 0;
3031 color[0] = color[1] = color[2] = 1;
3032 light[0] = light[1] = light[2] = 1;light[3] = 300;
3033 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3043 if (!COM_ParseToken(&data, false))
3045 if (com_token[0] == '}')
3046 break; // end of entity
3047 if (com_token[0] == '_')
3048 strcpy(key, com_token + 1);
3050 strcpy(key, com_token);
3051 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3052 key[strlen(key)-1] = 0;
3053 if (!COM_ParseToken(&data, false))
3055 strcpy(value, com_token);
3057 // now that we have the key pair worked out...
3058 if (!strcmp("light", key))
3060 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3064 light[0] = vec[0] * (1.0f / 256.0f);
3065 light[1] = vec[0] * (1.0f / 256.0f);
3066 light[2] = vec[0] * (1.0f / 256.0f);
3072 light[0] = vec[0] * (1.0f / 255.0f);
3073 light[1] = vec[1] * (1.0f / 255.0f);
3074 light[2] = vec[2] * (1.0f / 255.0f);
3078 else if (!strcmp("delay", key))
3080 else if (!strcmp("origin", key))
3081 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3082 else if (!strcmp("angle", key))
3083 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3084 else if (!strcmp("angles", key))
3085 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3086 else if (!strcmp("color", key))
3087 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3088 else if (!strcmp("wait", key))
3089 fadescale = atof(value);
3090 else if (!strcmp("classname", key))
3092 if (!strncmp(value, "light", 5))
3095 if (!strcmp(value, "light_fluoro"))
3100 overridecolor[0] = 1;
3101 overridecolor[1] = 1;
3102 overridecolor[2] = 1;
3104 if (!strcmp(value, "light_fluorospark"))
3109 overridecolor[0] = 1;
3110 overridecolor[1] = 1;
3111 overridecolor[2] = 1;
3113 if (!strcmp(value, "light_globe"))
3118 overridecolor[0] = 1;
3119 overridecolor[1] = 0.8;
3120 overridecolor[2] = 0.4;
3122 if (!strcmp(value, "light_flame_large_yellow"))
3127 overridecolor[0] = 1;
3128 overridecolor[1] = 0.5;
3129 overridecolor[2] = 0.1;
3131 if (!strcmp(value, "light_flame_small_yellow"))
3136 overridecolor[0] = 1;
3137 overridecolor[1] = 0.5;
3138 overridecolor[2] = 0.1;
3140 if (!strcmp(value, "light_torch_small_white"))
3145 overridecolor[0] = 1;
3146 overridecolor[1] = 0.5;
3147 overridecolor[2] = 0.1;
3149 if (!strcmp(value, "light_torch_small_walltorch"))
3154 overridecolor[0] = 1;
3155 overridecolor[1] = 0.5;
3156 overridecolor[2] = 0.1;
3160 else if (!strcmp("style", key))
3161 style = atoi(value);
3162 else if (r_refdef.worldmodel->type == mod_brushq3)
3164 if (!strcmp("scale", key))
3165 lightscale = atof(value);
3166 if (!strcmp("fade", key))
3167 fadescale = atof(value);
3169 else if (!strcmp("skin", key))
3170 skin = (int)atof(value);
3171 else if (!strcmp("pflags", key))
3172 pflags = (int)atof(value);
3173 else if (!strcmp("effects", key))
3174 effects = (int)atof(value);
3178 if (lightscale <= 0)
3182 if (color[0] == color[1] && color[0] == color[2])
3184 color[0] *= overridecolor[0];
3185 color[1] *= overridecolor[1];
3186 color[2] *= overridecolor[2];
3188 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3189 color[0] = color[0] * light[0];
3190 color[1] = color[1] * light[1];
3191 color[2] = color[2] * light[2];
3194 case LIGHTTYPE_MINUSX:
3196 case LIGHTTYPE_RECIPX:
3198 VectorScale(color, (1.0f / 16.0f), color);
3200 case LIGHTTYPE_RECIPXX:
3202 VectorScale(color, (1.0f / 16.0f), color);
3205 case LIGHTTYPE_NONE:
3209 case LIGHTTYPE_MINUSXX:
3212 VectorAdd(origin, originhack, origin);
3214 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3217 Mem_Free(entfiledata);
3221 void R_Shadow_SetCursorLocationForView(void)
3223 vec_t dist, push, frac;
3224 vec3_t dest, endpos, normal;
3225 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3226 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3229 dist = frac * r_editlights_cursordistance.value;
3230 push = r_editlights_cursorpushback.value;
3234 VectorMA(endpos, push, r_viewforward, endpos);
3235 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3237 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3238 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3239 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3242 void R_Shadow_UpdateWorldLightSelection(void)
3244 if (r_editlights.integer)
3246 R_Shadow_SetCursorLocationForView();
3247 R_Shadow_SelectLightInView();
3248 R_Shadow_DrawLightSprites();
3251 R_Shadow_SelectLight(NULL);
3254 void R_Shadow_EditLights_Clear_f(void)
3256 R_Shadow_ClearWorldLights();
3259 void R_Shadow_EditLights_Reload_f(void)
3261 if (!r_refdef.worldmodel)
3263 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3264 R_Shadow_ClearWorldLights();
3265 R_Shadow_LoadWorldLights();
3266 if (r_shadow_worldlightchain == NULL)
3268 R_Shadow_LoadLightsFile();
3269 if (r_shadow_worldlightchain == NULL)
3270 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3274 void R_Shadow_EditLights_Save_f(void)
3276 if (!r_refdef.worldmodel)
3278 R_Shadow_SaveWorldLights();
3281 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3283 R_Shadow_ClearWorldLights();
3284 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3287 void R_Shadow_EditLights_ImportLightsFile_f(void)
3289 R_Shadow_ClearWorldLights();
3290 R_Shadow_LoadLightsFile();
3293 void R_Shadow_EditLights_Spawn_f(void)
3296 if (!r_editlights.integer)
3298 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3301 if (Cmd_Argc() != 1)
3303 Con_Print("r_editlights_spawn does not take parameters\n");
3306 color[0] = color[1] = color[2] = 1;
3307 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3310 void R_Shadow_EditLights_Edit_f(void)
3312 vec3_t origin, angles, color;
3313 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3314 int style, shadows, flags, normalmode, realtimemode;
3315 char cubemapname[1024];
3316 if (!r_editlights.integer)
3318 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3321 if (!r_shadow_selectedlight)
3323 Con_Print("No selected light.\n");
3326 VectorCopy(r_shadow_selectedlight->origin, origin);
3327 VectorCopy(r_shadow_selectedlight->angles, angles);
3328 VectorCopy(r_shadow_selectedlight->color, color);
3329 radius = r_shadow_selectedlight->radius;
3330 style = r_shadow_selectedlight->style;
3331 if (r_shadow_selectedlight->cubemapname)
3332 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3335 shadows = r_shadow_selectedlight->shadow;
3336 corona = r_shadow_selectedlight->corona;
3337 coronasizescale = r_shadow_selectedlight->coronasizescale;
3338 ambientscale = r_shadow_selectedlight->ambientscale;
3339 diffusescale = r_shadow_selectedlight->diffusescale;
3340 specularscale = r_shadow_selectedlight->specularscale;
3341 flags = r_shadow_selectedlight->flags;
3342 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3343 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3344 if (!strcmp(Cmd_Argv(1), "origin"))
3346 if (Cmd_Argc() != 5)
3348 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3351 origin[0] = atof(Cmd_Argv(2));
3352 origin[1] = atof(Cmd_Argv(3));
3353 origin[2] = atof(Cmd_Argv(4));
3355 else if (!strcmp(Cmd_Argv(1), "originx"))
3357 if (Cmd_Argc() != 3)
3359 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3362 origin[0] = atof(Cmd_Argv(2));
3364 else if (!strcmp(Cmd_Argv(1), "originy"))
3366 if (Cmd_Argc() != 3)
3368 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3371 origin[1] = atof(Cmd_Argv(2));
3373 else if (!strcmp(Cmd_Argv(1), "originz"))
3375 if (Cmd_Argc() != 3)
3377 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3380 origin[2] = atof(Cmd_Argv(2));
3382 else if (!strcmp(Cmd_Argv(1), "move"))
3384 if (Cmd_Argc() != 5)
3386 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3389 origin[0] += atof(Cmd_Argv(2));
3390 origin[1] += atof(Cmd_Argv(3));
3391 origin[2] += atof(Cmd_Argv(4));
3393 else if (!strcmp(Cmd_Argv(1), "movex"))
3395 if (Cmd_Argc() != 3)
3397 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3400 origin[0] += atof(Cmd_Argv(2));
3402 else if (!strcmp(Cmd_Argv(1), "movey"))
3404 if (Cmd_Argc() != 3)
3406 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3409 origin[1] += atof(Cmd_Argv(2));
3411 else if (!strcmp(Cmd_Argv(1), "movez"))
3413 if (Cmd_Argc() != 3)
3415 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3418 origin[2] += atof(Cmd_Argv(2));
3420 else if (!strcmp(Cmd_Argv(1), "angles"))
3422 if (Cmd_Argc() != 5)
3424 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3427 angles[0] = atof(Cmd_Argv(2));
3428 angles[1] = atof(Cmd_Argv(3));
3429 angles[2] = atof(Cmd_Argv(4));
3431 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3433 if (Cmd_Argc() != 3)
3435 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3438 angles[0] = atof(Cmd_Argv(2));
3440 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3442 if (Cmd_Argc() != 3)
3444 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3447 angles[1] = atof(Cmd_Argv(2));
3449 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3451 if (Cmd_Argc() != 3)
3453 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3456 angles[2] = atof(Cmd_Argv(2));
3458 else if (!strcmp(Cmd_Argv(1), "color"))
3460 if (Cmd_Argc() != 5)
3462 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3465 color[0] = atof(Cmd_Argv(2));
3466 color[1] = atof(Cmd_Argv(3));
3467 color[2] = atof(Cmd_Argv(4));
3469 else if (!strcmp(Cmd_Argv(1), "radius"))
3471 if (Cmd_Argc() != 3)
3473 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3476 radius = atof(Cmd_Argv(2));
3478 else if (!strcmp(Cmd_Argv(1), "style"))
3480 if (Cmd_Argc() != 3)
3482 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3485 style = atoi(Cmd_Argv(2));
3487 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3491 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3494 if (Cmd_Argc() == 3)
3495 strcpy(cubemapname, Cmd_Argv(2));
3499 else if (!strcmp(Cmd_Argv(1), "shadows"))
3501 if (Cmd_Argc() != 3)
3503 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3506 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3508 else if (!strcmp(Cmd_Argv(1), "corona"))
3510 if (Cmd_Argc() != 3)
3512 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3515 corona = atof(Cmd_Argv(2));
3517 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3519 if (Cmd_Argc() != 3)
3521 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3524 coronasizescale = atof(Cmd_Argv(2));
3526 else if (!strcmp(Cmd_Argv(1), "ambient"))
3528 if (Cmd_Argc() != 3)
3530 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3533 ambientscale = atof(Cmd_Argv(2));
3535 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3537 if (Cmd_Argc() != 3)
3539 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3542 diffusescale = atof(Cmd_Argv(2));
3544 else if (!strcmp(Cmd_Argv(1), "specular"))
3546 if (Cmd_Argc() != 3)
3548 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3551 specularscale = atof(Cmd_Argv(2));
3553 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3555 if (Cmd_Argc() != 3)
3557 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3560 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3562 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3564 if (Cmd_Argc() != 3)
3566 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3569 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3573 Con_Print("usage: r_editlights_edit [property] [value]\n");
3574 Con_Print("Selected light's properties:\n");
3575 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3576 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3577 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3578 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3579 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3580 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3581 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3582 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3583 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3584 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3585 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3586 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3587 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3588 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3591 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3592 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3595 void R_Shadow_EditLights_EditAll_f(void)
3599 if (!r_editlights.integer)
3601 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3605 for (light = r_shadow_worldlightchain;light;light = light->next)
3607 R_Shadow_SelectLight(light);
3608 R_Shadow_EditLights_Edit_f();
3612 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3614 int lightnumber, lightcount;
3618 if (!r_editlights.integer)
3624 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3625 if (light == r_shadow_selectedlight)
3626 lightnumber = lightcount;
3627 sprintf(temp, "Cursor %f %f %f Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3628 if (r_shadow_selectedlight == NULL)
3630 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3631 sprintf(temp, "Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3632 sprintf(temp, "Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3633 sprintf(temp, "Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3634 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3635 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3636 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3637 sprintf(temp, "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3638 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3639 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3640 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3641 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3642 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3643 sprintf(temp, "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3644 sprintf(temp, "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3647 void R_Shadow_EditLights_ToggleShadow_f(void)
3649 if (!r_editlights.integer)
3651 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3654 if (!r_shadow_selectedlight)
3656 Con_Print("No selected light.\n");
3659 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
3662 void R_Shadow_EditLights_ToggleCorona_f(void)
3664 if (!r_editlights.integer)
3666 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3669 if (!r_shadow_selectedlight)
3671 Con_Print("No selected light.\n");
3674 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
3677 void R_Shadow_EditLights_Remove_f(void)
3679 if (!r_editlights.integer)
3681 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3684 if (!r_shadow_selectedlight)
3686 Con_Print("No selected light.\n");
3689 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3690 r_shadow_selectedlight = NULL;
3693 void R_Shadow_EditLights_Help_f(void)
3696 "Documentation on r_editlights system:\n"
3698 "r_editlights : enable/disable editing mode\n"
3699 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3700 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3701 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3702 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3703 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3704 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3705 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3707 "r_editlights_help : this help\n"
3708 "r_editlights_clear : remove all lights\n"
3709 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3710 "r_editlights_save : save to .rtlights file\n"
3711 "r_editlights_spawn : create a light with default settings\n"
3712 "r_editlights_edit command : edit selected light - more documentation below\n"
3713 "r_editlights_remove : remove selected light\n"
3714 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3715 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3716 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3718 "origin x y z : set light location\n"
3719 "originx x: set x component of light location\n"
3720 "originy y: set y component of light location\n"
3721 "originz z: set z component of light location\n"
3722 "move x y z : adjust light location\n"
3723 "movex x: adjust x component of light location\n"
3724 "movey y: adjust y component of light location\n"
3725 "movez z: adjust z component of light location\n"
3726 "angles x y z : set light angles\n"
3727 "anglesx x: set x component of light angles\n"
3728 "anglesy y: set y component of light angles\n"
3729 "anglesz z: set z component of light angles\n"
3730 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3731 "radius radius : set radius (size) of light\n"
3732 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3733 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3734 "shadows 1/0 : turn on/off shadows\n"
3735 "corona n : set corona intensity\n"
3736 "coronasize n : set corona size (0-1)\n"
3737 "ambient n : set ambient intensity (0-1)\n"
3738 "diffuse n : set diffuse intensity (0-1)\n"
3739 "specular n : set specular intensity (0-1)\n"
3740 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3741 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3742 "<nothing> : print light properties to console\n"
3746 void R_Shadow_EditLights_CopyInfo_f(void)
3748 if (!r_editlights.integer)
3750 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3753 if (!r_shadow_selectedlight)
3755 Con_Print("No selected light.\n");
3758 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3759 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3760 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3761 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3762 if (r_shadow_selectedlight->cubemapname)
3763 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3765 r_shadow_bufferlight.cubemapname[0] = 0;
3766 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3767 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3768 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3769 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3770 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3771 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3772 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3775 void R_Shadow_EditLights_PasteInfo_f(void)
3777 if (!r_editlights.integer)
3779 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3782 if (!r_shadow_selectedlight)
3784 Con_Print("No selected light.\n");
3787 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
3790 void R_Shadow_EditLights_Init(void)
3792 Cvar_RegisterVariable(&r_editlights);
3793 Cvar_RegisterVariable(&r_editlights_cursordistance);
3794 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3795 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3796 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3797 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3798 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3799 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3800 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3801 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3802 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3803 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3804 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3805 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3806 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3807 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3808 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3809 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3810 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3811 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3812 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3813 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);