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 // increment stencil if backface is behind depthbuffer
2426 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2427 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2428 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2429 c_rtcached_shadowmeshes++;
2430 c_rtcached_shadowtris += mesh->numtriangles;
2431 // decrement stencil if frontface is behind depthbuffer
2432 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2433 qglStencilOp(GL_KEEP, GL_DECR, 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, "\"\""))
2875 // remove quotes on cubemapname
2876 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2878 cubemapname[strlen(cubemapname)-1] = 0;
2879 strcpy(cubemapname, cubemapname + 1);
2884 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);
2887 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2888 radius *= r_editlights_rtlightssizescale.value;
2889 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2894 Con_Printf("invalid rtlights file \"%s\"\n", name);
2895 Mem_Free(lightsstring);
2899 void R_Shadow_SaveWorldLights(void)
2902 int bufchars, bufmaxchars;
2904 char name[MAX_QPATH];
2906 if (!r_shadow_worldlightchain)
2908 if (r_refdef.worldmodel == NULL)
2910 Con_Print("No map loaded.\n");
2913 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2914 strlcat (name, ".rtlights", sizeof (name));
2915 bufchars = bufmaxchars = 0;
2917 for (light = r_shadow_worldlightchain;light;light = light->next)
2919 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2920 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);
2921 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2922 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]);
2924 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);
2925 if (bufchars + (int) strlen(line) > bufmaxchars)
2927 bufmaxchars = bufchars + strlen(line) + 2048;
2929 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2933 memcpy(buf, oldbuf, bufchars);
2939 memcpy(buf + bufchars, line, strlen(line));
2940 bufchars += strlen(line);
2944 FS_WriteFile(name, buf, bufchars);
2949 void R_Shadow_LoadLightsFile(void)
2952 char name[MAX_QPATH], *lightsstring, *s, *t;
2953 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2954 if (r_refdef.worldmodel == NULL)
2956 Con_Print("No map loaded.\n");
2959 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2960 strlcat (name, ".lights", sizeof (name));
2961 lightsstring = FS_LoadFile(name, tempmempool, false);
2969 while (*s && *s != '\n')
2974 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);
2978 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);
2981 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2982 radius = bound(15, radius, 4096);
2983 VectorScale(color, (2.0f / (8388608.0f)), color);
2984 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2989 Con_Printf("invalid lights file \"%s\"\n", name);
2990 Mem_Free(lightsstring);
2994 // tyrlite/hmap2 light types in the delay field
2995 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2997 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2999 int entnum, style, islight, skin, pflags, effects, type, n;
3002 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3003 char key[256], value[1024];
3005 if (r_refdef.worldmodel == NULL)
3007 Con_Print("No map loaded.\n");
3010 // try to load a .ent file first
3011 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3012 strlcat (key, ".ent", sizeof (key));
3013 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3014 // and if that is not found, fall back to the bsp file entity string
3016 data = r_refdef.worldmodel->brush.entities;
3019 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3021 type = LIGHTTYPE_MINUSX;
3022 origin[0] = origin[1] = origin[2] = 0;
3023 originhack[0] = originhack[1] = originhack[2] = 0;
3024 angles[0] = angles[1] = angles[2] = 0;
3025 color[0] = color[1] = color[2] = 1;
3026 light[0] = light[1] = light[2] = 1;light[3] = 300;
3027 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3037 if (!COM_ParseToken(&data, false))
3039 if (com_token[0] == '}')
3040 break; // end of entity
3041 if (com_token[0] == '_')
3042 strcpy(key, com_token + 1);
3044 strcpy(key, com_token);
3045 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3046 key[strlen(key)-1] = 0;
3047 if (!COM_ParseToken(&data, false))
3049 strcpy(value, com_token);
3051 // now that we have the key pair worked out...
3052 if (!strcmp("light", key))
3054 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3058 light[0] = vec[0] * (1.0f / 256.0f);
3059 light[1] = vec[0] * (1.0f / 256.0f);
3060 light[2] = vec[0] * (1.0f / 256.0f);
3066 light[0] = vec[0] * (1.0f / 255.0f);
3067 light[1] = vec[1] * (1.0f / 255.0f);
3068 light[2] = vec[2] * (1.0f / 255.0f);
3072 else if (!strcmp("delay", key))
3074 else if (!strcmp("origin", key))
3075 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3076 else if (!strcmp("angle", key))
3077 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3078 else if (!strcmp("angles", key))
3079 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3080 else if (!strcmp("color", key))
3081 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3082 else if (!strcmp("wait", key))
3083 fadescale = atof(value);
3084 else if (!strcmp("classname", key))
3086 if (!strncmp(value, "light", 5))
3089 if (!strcmp(value, "light_fluoro"))
3094 overridecolor[0] = 1;
3095 overridecolor[1] = 1;
3096 overridecolor[2] = 1;
3098 if (!strcmp(value, "light_fluorospark"))
3103 overridecolor[0] = 1;
3104 overridecolor[1] = 1;
3105 overridecolor[2] = 1;
3107 if (!strcmp(value, "light_globe"))
3112 overridecolor[0] = 1;
3113 overridecolor[1] = 0.8;
3114 overridecolor[2] = 0.4;
3116 if (!strcmp(value, "light_flame_large_yellow"))
3121 overridecolor[0] = 1;
3122 overridecolor[1] = 0.5;
3123 overridecolor[2] = 0.1;
3125 if (!strcmp(value, "light_flame_small_yellow"))
3130 overridecolor[0] = 1;
3131 overridecolor[1] = 0.5;
3132 overridecolor[2] = 0.1;
3134 if (!strcmp(value, "light_torch_small_white"))
3139 overridecolor[0] = 1;
3140 overridecolor[1] = 0.5;
3141 overridecolor[2] = 0.1;
3143 if (!strcmp(value, "light_torch_small_walltorch"))
3148 overridecolor[0] = 1;
3149 overridecolor[1] = 0.5;
3150 overridecolor[2] = 0.1;
3154 else if (!strcmp("style", key))
3155 style = atoi(value);
3156 else if (r_refdef.worldmodel->type == mod_brushq3)
3158 if (!strcmp("scale", key))
3159 lightscale = atof(value);
3160 if (!strcmp("fade", key))
3161 fadescale = atof(value);
3163 else if (!strcmp("skin", key))
3164 skin = (int)atof(value);
3165 else if (!strcmp("pflags", key))
3166 pflags = (int)atof(value);
3167 else if (!strcmp("effects", key))
3168 effects = (int)atof(value);
3172 if (lightscale <= 0)
3176 if (color[0] == color[1] && color[0] == color[2])
3178 color[0] *= overridecolor[0];
3179 color[1] *= overridecolor[1];
3180 color[2] *= overridecolor[2];
3182 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3183 color[0] = color[0] * light[0];
3184 color[1] = color[1] * light[1];
3185 color[2] = color[2] * light[2];
3188 case LIGHTTYPE_MINUSX:
3190 case LIGHTTYPE_RECIPX:
3192 VectorScale(color, (1.0f / 16.0f), color);
3194 case LIGHTTYPE_RECIPXX:
3196 VectorScale(color, (1.0f / 16.0f), color);
3199 case LIGHTTYPE_NONE:
3203 case LIGHTTYPE_MINUSXX:
3206 VectorAdd(origin, originhack, origin);
3208 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);
3211 Mem_Free(entfiledata);
3215 void R_Shadow_SetCursorLocationForView(void)
3217 vec_t dist, push, frac;
3218 vec3_t dest, endpos, normal;
3219 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3220 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3223 dist = frac * r_editlights_cursordistance.value;
3224 push = r_editlights_cursorpushback.value;
3228 VectorMA(endpos, push, r_viewforward, endpos);
3229 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3231 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3232 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3233 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3236 void R_Shadow_UpdateWorldLightSelection(void)
3238 if (r_editlights.integer)
3240 R_Shadow_SetCursorLocationForView();
3241 R_Shadow_SelectLightInView();
3242 R_Shadow_DrawLightSprites();
3245 R_Shadow_SelectLight(NULL);
3248 void R_Shadow_EditLights_Clear_f(void)
3250 R_Shadow_ClearWorldLights();
3253 void R_Shadow_EditLights_Reload_f(void)
3255 if (!r_refdef.worldmodel)
3257 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3258 R_Shadow_ClearWorldLights();
3259 R_Shadow_LoadWorldLights();
3260 if (r_shadow_worldlightchain == NULL)
3262 R_Shadow_LoadLightsFile();
3263 if (r_shadow_worldlightchain == NULL)
3264 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3268 void R_Shadow_EditLights_Save_f(void)
3270 if (!r_refdef.worldmodel)
3272 R_Shadow_SaveWorldLights();
3275 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3277 R_Shadow_ClearWorldLights();
3278 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3281 void R_Shadow_EditLights_ImportLightsFile_f(void)
3283 R_Shadow_ClearWorldLights();
3284 R_Shadow_LoadLightsFile();
3287 void R_Shadow_EditLights_Spawn_f(void)
3290 if (!r_editlights.integer)
3292 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3295 if (Cmd_Argc() != 1)
3297 Con_Print("r_editlights_spawn does not take parameters\n");
3300 color[0] = color[1] = color[2] = 1;
3301 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3304 void R_Shadow_EditLights_Edit_f(void)
3306 vec3_t origin, angles, color;
3307 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3308 int style, shadows, flags, normalmode, realtimemode;
3309 char cubemapname[1024];
3310 if (!r_editlights.integer)
3312 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3315 if (!r_shadow_selectedlight)
3317 Con_Print("No selected light.\n");
3320 VectorCopy(r_shadow_selectedlight->origin, origin);
3321 VectorCopy(r_shadow_selectedlight->angles, angles);
3322 VectorCopy(r_shadow_selectedlight->color, color);
3323 radius = r_shadow_selectedlight->radius;
3324 style = r_shadow_selectedlight->style;
3325 if (r_shadow_selectedlight->cubemapname)
3326 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3329 shadows = r_shadow_selectedlight->shadow;
3330 corona = r_shadow_selectedlight->corona;
3331 coronasizescale = r_shadow_selectedlight->coronasizescale;
3332 ambientscale = r_shadow_selectedlight->ambientscale;
3333 diffusescale = r_shadow_selectedlight->diffusescale;
3334 specularscale = r_shadow_selectedlight->specularscale;
3335 flags = r_shadow_selectedlight->flags;
3336 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3337 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3338 if (!strcmp(Cmd_Argv(1), "origin"))
3340 if (Cmd_Argc() != 5)
3342 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3345 origin[0] = atof(Cmd_Argv(2));
3346 origin[1] = atof(Cmd_Argv(3));
3347 origin[2] = atof(Cmd_Argv(4));
3349 else if (!strcmp(Cmd_Argv(1), "originx"))
3351 if (Cmd_Argc() != 3)
3353 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3356 origin[0] = atof(Cmd_Argv(2));
3358 else if (!strcmp(Cmd_Argv(1), "originy"))
3360 if (Cmd_Argc() != 3)
3362 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3365 origin[1] = atof(Cmd_Argv(2));
3367 else if (!strcmp(Cmd_Argv(1), "originz"))
3369 if (Cmd_Argc() != 3)
3371 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3374 origin[2] = atof(Cmd_Argv(2));
3376 else if (!strcmp(Cmd_Argv(1), "move"))
3378 if (Cmd_Argc() != 5)
3380 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3383 origin[0] += atof(Cmd_Argv(2));
3384 origin[1] += atof(Cmd_Argv(3));
3385 origin[2] += atof(Cmd_Argv(4));
3387 else if (!strcmp(Cmd_Argv(1), "movex"))
3389 if (Cmd_Argc() != 3)
3391 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3394 origin[0] += atof(Cmd_Argv(2));
3396 else if (!strcmp(Cmd_Argv(1), "movey"))
3398 if (Cmd_Argc() != 3)
3400 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3403 origin[1] += atof(Cmd_Argv(2));
3405 else if (!strcmp(Cmd_Argv(1), "movez"))
3407 if (Cmd_Argc() != 3)
3409 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3412 origin[2] += atof(Cmd_Argv(2));
3414 else if (!strcmp(Cmd_Argv(1), "angles"))
3416 if (Cmd_Argc() != 5)
3418 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3421 angles[0] = atof(Cmd_Argv(2));
3422 angles[1] = atof(Cmd_Argv(3));
3423 angles[2] = atof(Cmd_Argv(4));
3425 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3427 if (Cmd_Argc() != 3)
3429 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3432 angles[0] = atof(Cmd_Argv(2));
3434 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3436 if (Cmd_Argc() != 3)
3438 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3441 angles[1] = atof(Cmd_Argv(2));
3443 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3445 if (Cmd_Argc() != 3)
3447 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3450 angles[2] = atof(Cmd_Argv(2));
3452 else if (!strcmp(Cmd_Argv(1), "color"))
3454 if (Cmd_Argc() != 5)
3456 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3459 color[0] = atof(Cmd_Argv(2));
3460 color[1] = atof(Cmd_Argv(3));
3461 color[2] = atof(Cmd_Argv(4));
3463 else if (!strcmp(Cmd_Argv(1), "radius"))
3465 if (Cmd_Argc() != 3)
3467 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3470 radius = atof(Cmd_Argv(2));
3472 else if (!strcmp(Cmd_Argv(1), "style"))
3474 if (Cmd_Argc() != 3)
3476 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3479 style = atoi(Cmd_Argv(2));
3481 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3485 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3488 if (Cmd_Argc() == 3)
3489 strcpy(cubemapname, Cmd_Argv(2));
3493 else if (!strcmp(Cmd_Argv(1), "shadows"))
3495 if (Cmd_Argc() != 3)
3497 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3500 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3502 else if (!strcmp(Cmd_Argv(1), "corona"))
3504 if (Cmd_Argc() != 3)
3506 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3509 corona = atof(Cmd_Argv(2));
3511 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3513 if (Cmd_Argc() != 3)
3515 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3518 coronasizescale = atof(Cmd_Argv(2));
3520 else if (!strcmp(Cmd_Argv(1), "ambient"))
3522 if (Cmd_Argc() != 3)
3524 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3527 ambientscale = atof(Cmd_Argv(2));
3529 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3531 if (Cmd_Argc() != 3)
3533 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3536 diffusescale = atof(Cmd_Argv(2));
3538 else if (!strcmp(Cmd_Argv(1), "specular"))
3540 if (Cmd_Argc() != 3)
3542 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3545 specularscale = atof(Cmd_Argv(2));
3547 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3549 if (Cmd_Argc() != 3)
3551 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3554 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3556 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3558 if (Cmd_Argc() != 3)
3560 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3563 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3567 Con_Print("usage: r_editlights_edit [property] [value]\n");
3568 Con_Print("Selected light's properties:\n");
3569 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3570 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3571 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3572 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3573 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3574 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3575 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3576 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3577 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3578 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3579 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3580 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3581 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3582 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3585 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3586 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3589 void R_Shadow_EditLights_EditAll_f(void)
3593 if (!r_editlights.integer)
3595 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3599 for (light = r_shadow_worldlightchain;light;light = light->next)
3601 R_Shadow_SelectLight(light);
3602 R_Shadow_EditLights_Edit_f();
3606 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3608 int lightnumber, lightcount;
3612 if (!r_editlights.integer)
3618 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3619 if (light == r_shadow_selectedlight)
3620 lightnumber = lightcount;
3621 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;
3622 if (r_shadow_selectedlight == NULL)
3624 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3625 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;
3626 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;
3627 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;
3628 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3629 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3630 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3631 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;
3632 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3633 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3634 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3635 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3636 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3637 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;
3638 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;
3641 void R_Shadow_EditLights_ToggleShadow_f(void)
3643 if (!r_editlights.integer)
3645 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3648 if (!r_shadow_selectedlight)
3650 Con_Print("No selected light.\n");
3653 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);
3656 void R_Shadow_EditLights_ToggleCorona_f(void)
3658 if (!r_editlights.integer)
3660 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3663 if (!r_shadow_selectedlight)
3665 Con_Print("No selected light.\n");
3668 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);
3671 void R_Shadow_EditLights_Remove_f(void)
3673 if (!r_editlights.integer)
3675 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3678 if (!r_shadow_selectedlight)
3680 Con_Print("No selected light.\n");
3683 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3684 r_shadow_selectedlight = NULL;
3687 void R_Shadow_EditLights_Help_f(void)
3690 "Documentation on r_editlights system:\n"
3692 "r_editlights : enable/disable editing mode\n"
3693 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3694 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3695 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3696 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3697 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3698 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3699 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3701 "r_editlights_help : this help\n"
3702 "r_editlights_clear : remove all lights\n"
3703 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3704 "r_editlights_save : save to .rtlights file\n"
3705 "r_editlights_spawn : create a light with default settings\n"
3706 "r_editlights_edit command : edit selected light - more documentation below\n"
3707 "r_editlights_remove : remove selected light\n"
3708 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3709 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3710 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3712 "origin x y z : set light location\n"
3713 "originx x: set x component of light location\n"
3714 "originy y: set y component of light location\n"
3715 "originz z: set z component of light location\n"
3716 "move x y z : adjust light location\n"
3717 "movex x: adjust x component of light location\n"
3718 "movey y: adjust y component of light location\n"
3719 "movez z: adjust z component of light location\n"
3720 "angles x y z : set light angles\n"
3721 "anglesx x: set x component of light angles\n"
3722 "anglesy y: set y component of light angles\n"
3723 "anglesz z: set z component of light angles\n"
3724 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3725 "radius radius : set radius (size) of light\n"
3726 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3727 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3728 "shadows 1/0 : turn on/off shadows\n"
3729 "corona n : set corona intensity\n"
3730 "coronasize n : set corona size (0-1)\n"
3731 "ambient n : set ambient intensity (0-1)\n"
3732 "diffuse n : set diffuse intensity (0-1)\n"
3733 "specular n : set specular intensity (0-1)\n"
3734 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3735 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3736 "<nothing> : print light properties to console\n"
3740 void R_Shadow_EditLights_CopyInfo_f(void)
3742 if (!r_editlights.integer)
3744 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3747 if (!r_shadow_selectedlight)
3749 Con_Print("No selected light.\n");
3752 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3753 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3754 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3755 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3756 if (r_shadow_selectedlight->cubemapname)
3757 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3759 r_shadow_bufferlight.cubemapname[0] = 0;
3760 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3761 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3762 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3763 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3764 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3765 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3766 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3769 void R_Shadow_EditLights_PasteInfo_f(void)
3771 if (!r_editlights.integer)
3773 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3776 if (!r_shadow_selectedlight)
3778 Con_Print("No selected light.\n");
3781 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);
3784 void R_Shadow_EditLights_Init(void)
3786 Cvar_RegisterVariable(&r_editlights);
3787 Cvar_RegisterVariable(&r_editlights_cursordistance);
3788 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3789 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3790 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3791 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3792 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3793 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3794 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3795 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3796 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3797 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3798 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3799 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3800 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3801 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3802 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3803 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3804 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3805 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3806 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3807 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);