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 // loading is done before visibility checks because loading should happen
2335 // all at once at the start of a level, not when it stalls gameplay.
2336 // (especially important to benchmarks)
2337 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2338 R_RTLight_Compile(rtlight);
2339 if (rtlight->cubemapname[0])
2340 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2342 cubemaptexture = NULL;
2344 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2345 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2346 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2347 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2348 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2349 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2350 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2357 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2359 // compiled light, world available and can receive realtime lighting
2360 // retrieve cluster information
2361 numclusters = rtlight->static_numclusters;
2362 clusterlist = rtlight->static_clusterlist;
2363 clusterpvs = rtlight->static_clusterpvs;
2364 VectorCopy(rtlight->cullmins, cullmins);
2365 VectorCopy(rtlight->cullmaxs, cullmaxs);
2367 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2369 // dynamic light, world available and can receive realtime lighting
2370 // if the light box is offscreen, skip it right away
2371 if (R_CullBox(cullmins, cullmaxs))
2373 // calculate lit surfaces and clusters
2374 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2375 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2376 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);
2377 clusterlist = r_shadow_buffer_clusterlist;
2378 clusterpvs = r_shadow_buffer_clusterpvs;
2379 surfacelist = r_shadow_buffer_surfacelist;
2381 // if the reduced cluster bounds are offscreen, skip it
2382 if (R_CullBox(cullmins, cullmaxs))
2384 // check if light is illuminating any visible clusters
2387 for (i = 0;i < numclusters;i++)
2388 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2390 if (i == numclusters)
2393 // set up a scissor rectangle for this light
2394 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2397 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f);
2398 VectorScale(rtlight->color, f, lightcolor);
2400 if (rtlight->selected)
2402 f = 2 + sin(realtime * M_PI * 4.0);
2403 VectorScale(lightcolor, f, lightcolor);
2407 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2409 if (shadow && (gl_stencil || visiblevolumes))
2411 if (!visiblevolumes)
2412 R_Shadow_Stage_ShadowVolumes();
2413 ent = &cl_entities[0].render;
2414 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2416 memset(&m, 0, sizeof(m));
2417 R_Mesh_Matrix(&ent->matrix);
2418 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2420 m.pointer_vertex = mesh->vertex3f;
2422 GL_LockArrays(0, mesh->numverts);
2423 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2425 // decrement stencil if frontface is behind depthbuffer
2426 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2427 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2428 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2429 c_rtcached_shadowmeshes++;
2430 c_rtcached_shadowtris += mesh->numtriangles;
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);
2435 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2436 c_rtcached_shadowmeshes++;
2437 c_rtcached_shadowtris += mesh->numtriangles;
2438 GL_LockArrays(0, 0);
2441 else if (numsurfaces)
2443 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2444 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2446 if (r_drawentities.integer)
2448 for (i = 0;i < r_refdef.numentities;i++)
2450 ent = r_refdef.entities[i];
2452 if (r_shadow_cull.integer)
2454 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2456 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2459 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2461 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2462 // light emitting entities should not cast their own shadow
2463 if (VectorLength2(relativelightorigin) < 0.1)
2465 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2470 if (!visiblevolumes)
2472 R_Shadow_Stage_Light(shadow && gl_stencil);
2474 ent = &cl_entities[0].render;
2475 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2477 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2478 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2479 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2480 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2481 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2482 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2483 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2484 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2485 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2487 R_Mesh_Matrix(&ent->matrix);
2488 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2489 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);
2492 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2494 if (r_drawentities.integer)
2496 for (i = 0;i < r_refdef.numentities;i++)
2498 ent = r_refdef.entities[i];
2499 // can't draw transparent entity lighting here because
2500 // transparent meshes are deferred for later
2501 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)
2503 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2504 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2505 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2506 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2507 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2508 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2509 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2510 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2511 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);
2518 void R_ShadowVolumeLighting(int visiblevolumes)
2524 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2525 R_Shadow_EditLights_Reload_f();
2529 memset(&m, 0, sizeof(m));
2532 GL_BlendFunc(GL_ONE, GL_ONE);
2533 GL_DepthMask(false);
2534 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2535 qglDisable(GL_CULL_FACE);
2536 GL_Color(0.0, 0.0125, 0.1, 1);
2539 R_Shadow_Stage_Begin();
2540 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2541 if (r_shadow_debuglight.integer >= 0)
2543 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2544 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2545 R_DrawRTLight(&light->rtlight, visiblevolumes);
2548 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2549 if (light->flags & flag)
2550 R_DrawRTLight(&light->rtlight, visiblevolumes);
2552 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2553 R_DrawRTLight(&light->rtlight, visiblevolumes);
2557 qglEnable(GL_CULL_FACE);
2558 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2561 R_Shadow_Stage_End();
2564 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2565 typedef struct suffixinfo_s
2568 qboolean flipx, flipy, flipdiagonal;
2571 static suffixinfo_t suffix[3][6] =
2574 {"px", false, false, false},
2575 {"nx", false, false, false},
2576 {"py", false, false, false},
2577 {"ny", false, false, false},
2578 {"pz", false, false, false},
2579 {"nz", false, false, false}
2582 {"posx", false, false, false},
2583 {"negx", false, false, false},
2584 {"posy", false, false, false},
2585 {"negy", false, false, false},
2586 {"posz", false, false, false},
2587 {"negz", false, false, false}
2590 {"rt", true, false, true},
2591 {"lf", false, true, true},
2592 {"ft", true, true, false},
2593 {"bk", false, false, false},
2594 {"up", true, false, true},
2595 {"dn", true, false, true}
2599 static int componentorder[4] = {0, 1, 2, 3};
2601 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2603 int i, j, cubemapsize;
2604 qbyte *cubemappixels, *image_rgba;
2605 rtexture_t *cubemaptexture;
2607 // must start 0 so the first loadimagepixels has no requested width/height
2609 cubemappixels = NULL;
2610 cubemaptexture = NULL;
2611 // keep trying different suffix groups (posx, px, rt) until one loads
2612 for (j = 0;j < 3 && !cubemappixels;j++)
2614 // load the 6 images in the suffix group
2615 for (i = 0;i < 6;i++)
2617 // generate an image name based on the base and and suffix
2618 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2620 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2622 // an image loaded, make sure width and height are equal
2623 if (image_width == image_height)
2625 // if this is the first image to load successfully, allocate the cubemap memory
2626 if (!cubemappixels && image_width >= 1)
2628 cubemapsize = image_width;
2629 // note this clears to black, so unavailable sides are black
2630 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2632 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2634 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);
2637 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2639 Mem_Free(image_rgba);
2643 // if a cubemap loaded, upload it
2646 if (!r_shadow_filters_texturepool)
2647 r_shadow_filters_texturepool = R_AllocTexturePool();
2648 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2649 Mem_Free(cubemappixels);
2653 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2654 for (j = 0;j < 3;j++)
2655 for (i = 0;i < 6;i++)
2656 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2657 Con_Print(" and was unable to find any of them.\n");
2659 return cubemaptexture;
2662 rtexture_t *R_Shadow_Cubemap(const char *basename)
2665 for (i = 0;i < numcubemaps;i++)
2666 if (!strcasecmp(cubemaps[i].basename, basename))
2667 return cubemaps[i].texture;
2668 if (i >= MAX_CUBEMAPS)
2671 strcpy(cubemaps[i].basename, basename);
2672 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2673 return cubemaps[i].texture;
2676 void R_Shadow_FreeCubemaps(void)
2679 R_FreeTexturePool(&r_shadow_filters_texturepool);
2682 dlight_t *R_Shadow_NewWorldLight(void)
2685 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2686 light->next = r_shadow_worldlightchain;
2687 r_shadow_worldlightchain = light;
2691 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)
2693 VectorCopy(origin, light->origin);
2694 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2695 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2696 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2697 light->color[0] = max(color[0], 0);
2698 light->color[1] = max(color[1], 0);
2699 light->color[2] = max(color[2], 0);
2700 light->radius = max(radius, 0);
2701 light->style = style;
2702 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2704 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2707 light->shadow = shadowenable;
2708 light->corona = corona;
2711 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
2712 light->coronasizescale = coronasizescale;
2713 light->ambientscale = ambientscale;
2714 light->diffusescale = diffusescale;
2715 light->specularscale = specularscale;
2716 light->flags = flags;
2717 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2719 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2722 void R_Shadow_FreeWorldLight(dlight_t *light)
2724 dlight_t **lightpointer;
2725 R_RTLight_Uncompile(&light->rtlight);
2726 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2727 if (*lightpointer != light)
2728 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2729 *lightpointer = light->next;
2733 void R_Shadow_ClearWorldLights(void)
2735 while (r_shadow_worldlightchain)
2736 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2737 r_shadow_selectedlight = NULL;
2738 R_Shadow_FreeCubemaps();
2741 void R_Shadow_SelectLight(dlight_t *light)
2743 if (r_shadow_selectedlight)
2744 r_shadow_selectedlight->selected = false;
2745 r_shadow_selectedlight = light;
2746 if (r_shadow_selectedlight)
2747 r_shadow_selectedlight->selected = true;
2750 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2752 float scale = r_editlights_cursorgrid.value * 0.5f;
2753 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);
2756 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2759 const dlight_t *light;
2762 if (light->selected)
2763 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2766 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);
2769 void R_Shadow_DrawLightSprites(void)
2775 for (i = 0;i < 5;i++)
2777 lighttextures[i] = NULL;
2778 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2779 lighttextures[i] = pic->tex;
2782 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2783 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
2784 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2787 void R_Shadow_SelectLightInView(void)
2789 float bestrating, rating, temp[3];
2790 dlight_t *best, *light;
2793 for (light = r_shadow_worldlightchain;light;light = light->next)
2795 VectorSubtract(light->origin, r_vieworigin, temp);
2796 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2799 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2800 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2802 bestrating = rating;
2807 R_Shadow_SelectLight(best);
2810 void R_Shadow_LoadWorldLights(void)
2812 int n, a, style, shadow, flags;
2813 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2814 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2815 if (r_refdef.worldmodel == NULL)
2817 Con_Print("No map loaded.\n");
2820 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2821 strlcat (name, ".rtlights", sizeof (name));
2822 lightsstring = FS_LoadFile(name, tempmempool, false);
2832 for (;COM_Parse(t, true) && strcmp(
2833 if (COM_Parse(t, true))
2835 if (com_token[0] == '!')
2838 origin[0] = atof(com_token+1);
2841 origin[0] = atof(com_token);
2846 while (*s && *s != '\n')
2852 // check for modifier flags
2858 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);
2860 flags = LIGHTFLAG_REALTIMEMODE;
2868 coronasizescale = 0.25f;
2870 VectorClear(angles);
2873 if (a < 9 || !strcmp(cubemapname, "\"\""))
2878 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);
2881 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2882 radius *= r_editlights_rtlightssizescale.value;
2883 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2888 Con_Printf("invalid rtlights file \"%s\"\n", name);
2889 Mem_Free(lightsstring);
2893 void R_Shadow_SaveWorldLights(void)
2896 int bufchars, bufmaxchars;
2898 char name[MAX_QPATH];
2900 if (!r_shadow_worldlightchain)
2902 if (r_refdef.worldmodel == NULL)
2904 Con_Print("No map loaded.\n");
2907 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2908 strlcat (name, ".rtlights", sizeof (name));
2909 bufchars = bufmaxchars = 0;
2911 for (light = r_shadow_worldlightchain;light;light = light->next)
2913 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2914 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);
2915 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2916 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]);
2918 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);
2919 if (bufchars + (int) strlen(line) > bufmaxchars)
2921 bufmaxchars = bufchars + strlen(line) + 2048;
2923 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2927 memcpy(buf, oldbuf, bufchars);
2933 memcpy(buf + bufchars, line, strlen(line));
2934 bufchars += strlen(line);
2938 FS_WriteFile(name, buf, bufchars);
2943 void R_Shadow_LoadLightsFile(void)
2946 char name[MAX_QPATH], *lightsstring, *s, *t;
2947 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2948 if (r_refdef.worldmodel == NULL)
2950 Con_Print("No map loaded.\n");
2953 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2954 strlcat (name, ".lights", sizeof (name));
2955 lightsstring = FS_LoadFile(name, tempmempool, false);
2963 while (*s && *s != '\n')
2968 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);
2972 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);
2975 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2976 radius = bound(15, radius, 4096);
2977 VectorScale(color, (2.0f / (8388608.0f)), color);
2978 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2983 Con_Printf("invalid lights file \"%s\"\n", name);
2984 Mem_Free(lightsstring);
2988 // tyrlite/hmap2 light types in the delay field
2989 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2991 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2993 int entnum, style, islight, skin, pflags, effects, type, n;
2996 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2997 char key[256], value[1024];
2999 if (r_refdef.worldmodel == NULL)
3001 Con_Print("No map loaded.\n");
3004 // try to load a .ent file first
3005 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3006 strlcat (key, ".ent", sizeof (key));
3007 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3008 // and if that is not found, fall back to the bsp file entity string
3010 data = r_refdef.worldmodel->brush.entities;
3013 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3015 type = LIGHTTYPE_MINUSX;
3016 origin[0] = origin[1] = origin[2] = 0;
3017 originhack[0] = originhack[1] = originhack[2] = 0;
3018 angles[0] = angles[1] = angles[2] = 0;
3019 color[0] = color[1] = color[2] = 1;
3020 light[0] = light[1] = light[2] = 1;light[3] = 300;
3021 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3031 if (!COM_ParseToken(&data, false))
3033 if (com_token[0] == '}')
3034 break; // end of entity
3035 if (com_token[0] == '_')
3036 strcpy(key, com_token + 1);
3038 strcpy(key, com_token);
3039 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3040 key[strlen(key)-1] = 0;
3041 if (!COM_ParseToken(&data, false))
3043 strcpy(value, com_token);
3045 // now that we have the key pair worked out...
3046 if (!strcmp("light", key))
3048 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3052 light[0] = vec[0] * (1.0f / 256.0f);
3053 light[1] = vec[0] * (1.0f / 256.0f);
3054 light[2] = vec[0] * (1.0f / 256.0f);
3060 light[0] = vec[0] * (1.0f / 255.0f);
3061 light[1] = vec[1] * (1.0f / 255.0f);
3062 light[2] = vec[2] * (1.0f / 255.0f);
3066 else if (!strcmp("delay", key))
3068 else if (!strcmp("origin", key))
3069 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3070 else if (!strcmp("angle", key))
3071 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3072 else if (!strcmp("angles", key))
3073 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3074 else if (!strcmp("color", key))
3075 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3076 else if (!strcmp("wait", key))
3077 fadescale = atof(value);
3078 else if (!strcmp("classname", key))
3080 if (!strncmp(value, "light", 5))
3083 if (!strcmp(value, "light_fluoro"))
3088 overridecolor[0] = 1;
3089 overridecolor[1] = 1;
3090 overridecolor[2] = 1;
3092 if (!strcmp(value, "light_fluorospark"))
3097 overridecolor[0] = 1;
3098 overridecolor[1] = 1;
3099 overridecolor[2] = 1;
3101 if (!strcmp(value, "light_globe"))
3106 overridecolor[0] = 1;
3107 overridecolor[1] = 0.8;
3108 overridecolor[2] = 0.4;
3110 if (!strcmp(value, "light_flame_large_yellow"))
3115 overridecolor[0] = 1;
3116 overridecolor[1] = 0.5;
3117 overridecolor[2] = 0.1;
3119 if (!strcmp(value, "light_flame_small_yellow"))
3124 overridecolor[0] = 1;
3125 overridecolor[1] = 0.5;
3126 overridecolor[2] = 0.1;
3128 if (!strcmp(value, "light_torch_small_white"))
3133 overridecolor[0] = 1;
3134 overridecolor[1] = 0.5;
3135 overridecolor[2] = 0.1;
3137 if (!strcmp(value, "light_torch_small_walltorch"))
3142 overridecolor[0] = 1;
3143 overridecolor[1] = 0.5;
3144 overridecolor[2] = 0.1;
3148 else if (!strcmp("style", key))
3149 style = atoi(value);
3150 else if (r_refdef.worldmodel->type == mod_brushq3)
3152 if (!strcmp("scale", key))
3153 lightscale = atof(value);
3154 if (!strcmp("fade", key))
3155 fadescale = atof(value);
3157 else if (!strcmp("skin", key))
3158 skin = (int)atof(value);
3159 else if (!strcmp("pflags", key))
3160 pflags = (int)atof(value);
3161 else if (!strcmp("effects", key))
3162 effects = (int)atof(value);
3166 if (lightscale <= 0)
3170 if (color[0] == color[1] && color[0] == color[2])
3172 color[0] *= overridecolor[0];
3173 color[1] *= overridecolor[1];
3174 color[2] *= overridecolor[2];
3176 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3177 color[0] = color[0] * light[0];
3178 color[1] = color[1] * light[1];
3179 color[2] = color[2] * light[2];
3182 case LIGHTTYPE_MINUSX:
3184 case LIGHTTYPE_RECIPX:
3186 VectorScale(color, (1.0f / 16.0f), color);
3188 case LIGHTTYPE_RECIPXX:
3190 VectorScale(color, (1.0f / 16.0f), color);
3193 case LIGHTTYPE_NONE:
3197 case LIGHTTYPE_MINUSXX:
3200 VectorAdd(origin, originhack, origin);
3202 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);
3205 Mem_Free(entfiledata);
3209 void R_Shadow_SetCursorLocationForView(void)
3211 vec_t dist, push, frac;
3212 vec3_t dest, endpos, normal;
3213 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3214 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3217 dist = frac * r_editlights_cursordistance.value;
3218 push = r_editlights_cursorpushback.value;
3222 VectorMA(endpos, push, r_viewforward, endpos);
3223 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3225 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3226 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3227 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3230 void R_Shadow_UpdateWorldLightSelection(void)
3232 if (r_editlights.integer)
3234 R_Shadow_SetCursorLocationForView();
3235 R_Shadow_SelectLightInView();
3236 R_Shadow_DrawLightSprites();
3239 R_Shadow_SelectLight(NULL);
3242 void R_Shadow_EditLights_Clear_f(void)
3244 R_Shadow_ClearWorldLights();
3247 void R_Shadow_EditLights_Reload_f(void)
3249 if (!r_refdef.worldmodel)
3251 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3252 R_Shadow_ClearWorldLights();
3253 R_Shadow_LoadWorldLights();
3254 if (r_shadow_worldlightchain == NULL)
3256 R_Shadow_LoadLightsFile();
3257 if (r_shadow_worldlightchain == NULL)
3258 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3262 void R_Shadow_EditLights_Save_f(void)
3264 if (!r_refdef.worldmodel)
3266 R_Shadow_SaveWorldLights();
3269 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3271 R_Shadow_ClearWorldLights();
3272 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3275 void R_Shadow_EditLights_ImportLightsFile_f(void)
3277 R_Shadow_ClearWorldLights();
3278 R_Shadow_LoadLightsFile();
3281 void R_Shadow_EditLights_Spawn_f(void)
3284 if (!r_editlights.integer)
3286 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3289 if (Cmd_Argc() != 1)
3291 Con_Print("r_editlights_spawn does not take parameters\n");
3294 color[0] = color[1] = color[2] = 1;
3295 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3298 void R_Shadow_EditLights_Edit_f(void)
3300 vec3_t origin, angles, color;
3301 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3302 int style, shadows, flags, normalmode, realtimemode;
3303 char cubemapname[1024];
3304 if (!r_editlights.integer)
3306 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3309 if (!r_shadow_selectedlight)
3311 Con_Print("No selected light.\n");
3314 VectorCopy(r_shadow_selectedlight->origin, origin);
3315 VectorCopy(r_shadow_selectedlight->angles, angles);
3316 VectorCopy(r_shadow_selectedlight->color, color);
3317 radius = r_shadow_selectedlight->radius;
3318 style = r_shadow_selectedlight->style;
3319 if (r_shadow_selectedlight->cubemapname)
3320 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3323 shadows = r_shadow_selectedlight->shadow;
3324 corona = r_shadow_selectedlight->corona;
3325 coronasizescale = r_shadow_selectedlight->coronasizescale;
3326 ambientscale = r_shadow_selectedlight->ambientscale;
3327 diffusescale = r_shadow_selectedlight->diffusescale;
3328 specularscale = r_shadow_selectedlight->specularscale;
3329 flags = r_shadow_selectedlight->flags;
3330 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3331 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3332 if (!strcmp(Cmd_Argv(1), "origin"))
3334 if (Cmd_Argc() != 5)
3336 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3339 origin[0] = atof(Cmd_Argv(2));
3340 origin[1] = atof(Cmd_Argv(3));
3341 origin[2] = atof(Cmd_Argv(4));
3343 else if (!strcmp(Cmd_Argv(1), "originx"))
3345 if (Cmd_Argc() != 3)
3347 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3350 origin[0] = atof(Cmd_Argv(2));
3352 else if (!strcmp(Cmd_Argv(1), "originy"))
3354 if (Cmd_Argc() != 3)
3356 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3359 origin[1] = atof(Cmd_Argv(2));
3361 else if (!strcmp(Cmd_Argv(1), "originz"))
3363 if (Cmd_Argc() != 3)
3365 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3368 origin[2] = atof(Cmd_Argv(2));
3370 else if (!strcmp(Cmd_Argv(1), "move"))
3372 if (Cmd_Argc() != 5)
3374 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3377 origin[0] += atof(Cmd_Argv(2));
3378 origin[1] += atof(Cmd_Argv(3));
3379 origin[2] += atof(Cmd_Argv(4));
3381 else if (!strcmp(Cmd_Argv(1), "movex"))
3383 if (Cmd_Argc() != 3)
3385 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3388 origin[0] += atof(Cmd_Argv(2));
3390 else if (!strcmp(Cmd_Argv(1), "movey"))
3392 if (Cmd_Argc() != 3)
3394 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3397 origin[1] += atof(Cmd_Argv(2));
3399 else if (!strcmp(Cmd_Argv(1), "movez"))
3401 if (Cmd_Argc() != 3)
3403 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3406 origin[2] += atof(Cmd_Argv(2));
3408 else if (!strcmp(Cmd_Argv(1), "angles"))
3410 if (Cmd_Argc() != 5)
3412 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3415 angles[0] = atof(Cmd_Argv(2));
3416 angles[1] = atof(Cmd_Argv(3));
3417 angles[2] = atof(Cmd_Argv(4));
3419 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3421 if (Cmd_Argc() != 3)
3423 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3426 angles[0] = atof(Cmd_Argv(2));
3428 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3430 if (Cmd_Argc() != 3)
3432 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3435 angles[1] = atof(Cmd_Argv(2));
3437 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3439 if (Cmd_Argc() != 3)
3441 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3444 angles[2] = atof(Cmd_Argv(2));
3446 else if (!strcmp(Cmd_Argv(1), "color"))
3448 if (Cmd_Argc() != 5)
3450 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3453 color[0] = atof(Cmd_Argv(2));
3454 color[1] = atof(Cmd_Argv(3));
3455 color[2] = atof(Cmd_Argv(4));
3457 else if (!strcmp(Cmd_Argv(1), "radius"))
3459 if (Cmd_Argc() != 3)
3461 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3464 radius = atof(Cmd_Argv(2));
3466 else if (!strcmp(Cmd_Argv(1), "style"))
3468 if (Cmd_Argc() != 3)
3470 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3473 style = atoi(Cmd_Argv(2));
3475 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3479 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3482 if (Cmd_Argc() == 3)
3483 strcpy(cubemapname, Cmd_Argv(2));
3487 else if (!strcmp(Cmd_Argv(1), "shadows"))
3489 if (Cmd_Argc() != 3)
3491 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3494 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3496 else if (!strcmp(Cmd_Argv(1), "corona"))
3498 if (Cmd_Argc() != 3)
3500 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3503 corona = atof(Cmd_Argv(2));
3505 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3507 if (Cmd_Argc() != 3)
3509 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3512 coronasizescale = atof(Cmd_Argv(2));
3514 else if (!strcmp(Cmd_Argv(1), "ambient"))
3516 if (Cmd_Argc() != 3)
3518 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3521 ambientscale = atof(Cmd_Argv(2));
3523 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3525 if (Cmd_Argc() != 3)
3527 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3530 diffusescale = atof(Cmd_Argv(2));
3532 else if (!strcmp(Cmd_Argv(1), "specular"))
3534 if (Cmd_Argc() != 3)
3536 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3539 specularscale = atof(Cmd_Argv(2));
3541 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3543 if (Cmd_Argc() != 3)
3545 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3548 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3550 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3552 if (Cmd_Argc() != 3)
3554 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3557 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3561 Con_Print("usage: r_editlights_edit [property] [value]\n");
3562 Con_Print("Selected light's properties:\n");
3563 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3564 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3565 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3566 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3567 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3568 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3569 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3570 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3571 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3572 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3573 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3574 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3575 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3576 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3579 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3580 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3583 void R_Shadow_EditLights_EditAll_f(void)
3587 if (!r_editlights.integer)
3589 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3593 for (light = r_shadow_worldlightchain;light;light = light->next)
3595 R_Shadow_SelectLight(light);
3596 R_Shadow_EditLights_Edit_f();
3600 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3602 int lightnumber, lightcount;
3606 if (!r_editlights.integer)
3612 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3613 if (light == r_shadow_selectedlight)
3614 lightnumber = lightcount;
3615 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;
3616 if (r_shadow_selectedlight == NULL)
3618 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3619 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;
3620 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;
3621 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;
3622 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3623 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3624 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3625 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;
3626 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3627 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3628 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3629 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3630 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3631 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;
3632 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;
3635 void R_Shadow_EditLights_ToggleShadow_f(void)
3637 if (!r_editlights.integer)
3639 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3642 if (!r_shadow_selectedlight)
3644 Con_Print("No selected light.\n");
3647 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);
3650 void R_Shadow_EditLights_ToggleCorona_f(void)
3652 if (!r_editlights.integer)
3654 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3657 if (!r_shadow_selectedlight)
3659 Con_Print("No selected light.\n");
3662 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);
3665 void R_Shadow_EditLights_Remove_f(void)
3667 if (!r_editlights.integer)
3669 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3672 if (!r_shadow_selectedlight)
3674 Con_Print("No selected light.\n");
3677 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3678 r_shadow_selectedlight = NULL;
3681 void R_Shadow_EditLights_Help_f(void)
3684 "Documentation on r_editlights system:\n"
3686 "r_editlights : enable/disable editing mode\n"
3687 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3688 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3689 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3690 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3691 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3692 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3693 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3695 "r_editlights_help : this help\n"
3696 "r_editlights_clear : remove all lights\n"
3697 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3698 "r_editlights_save : save to .rtlights file\n"
3699 "r_editlights_spawn : create a light with default settings\n"
3700 "r_editlights_edit command : edit selected light - more documentation below\n"
3701 "r_editlights_remove : remove selected light\n"
3702 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3703 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3704 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3706 "origin x y z : set light location\n"
3707 "originx x: set x component of light location\n"
3708 "originy y: set y component of light location\n"
3709 "originz z: set z component of light location\n"
3710 "move x y z : adjust light location\n"
3711 "movex x: adjust x component of light location\n"
3712 "movey y: adjust y component of light location\n"
3713 "movez z: adjust z component of light location\n"
3714 "angles x y z : set light angles\n"
3715 "anglesx x: set x component of light angles\n"
3716 "anglesy y: set y component of light angles\n"
3717 "anglesz z: set z component of light angles\n"
3718 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3719 "radius radius : set radius (size) of light\n"
3720 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3721 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3722 "shadows 1/0 : turn on/off shadows\n"
3723 "corona n : set corona intensity\n"
3724 "coronasize n : set corona size (0-1)\n"
3725 "ambient n : set ambient intensity (0-1)\n"
3726 "diffuse n : set diffuse intensity (0-1)\n"
3727 "specular n : set specular intensity (0-1)\n"
3728 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3729 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3730 "<nothing> : print light properties to console\n"
3734 void R_Shadow_EditLights_CopyInfo_f(void)
3736 if (!r_editlights.integer)
3738 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3741 if (!r_shadow_selectedlight)
3743 Con_Print("No selected light.\n");
3746 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3747 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3748 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3749 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3750 if (r_shadow_selectedlight->cubemapname)
3751 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3753 r_shadow_bufferlight.cubemapname[0] = 0;
3754 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3755 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3756 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3757 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3758 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3759 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3760 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3763 void R_Shadow_EditLights_PasteInfo_f(void)
3765 if (!r_editlights.integer)
3767 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3770 if (!r_shadow_selectedlight)
3772 Con_Print("No selected light.\n");
3775 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);
3778 void R_Shadow_EditLights_Init(void)
3780 Cvar_RegisterVariable(&r_editlights);
3781 Cvar_RegisterVariable(&r_editlights_cursordistance);
3782 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3783 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3784 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3785 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3786 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3787 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3788 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3789 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3790 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3791 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3792 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3793 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3794 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3795 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3796 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3797 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3798 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3799 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3800 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3801 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);