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);
1401 GL_BlendFunc(GL_ONE, GL_ONE);
1403 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1405 // 2 3D combine path (Geforce3, original Radeon)
1406 memset(&m, 0, sizeof(m));
1407 m.pointer_vertex = vertex3f;
1408 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1410 m.pointer_texcoord3f[0] = vertex3f;
1411 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1413 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1414 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1416 m.tex[1] = R_GetTexture(basetexture);
1417 m.pointer_texcoord[1] = texcoord2f;
1418 GL_BlendFunc(GL_ONE, GL_ONE);
1420 else if (r_textureunits.integer >= 4 && lightcubemap)
1422 // 4 2D combine path (Geforce3, Radeon 8500)
1423 memset(&m, 0, sizeof(m));
1424 m.pointer_vertex = vertex3f;
1425 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1427 m.pointer_texcoord3f[0] = vertex3f;
1428 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1430 m.pointer_texcoord[0] = varray_texcoord2f[0];
1431 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1433 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1435 m.pointer_texcoord3f[1] = vertex3f;
1436 m.texmatrix[1] = *matrix_modeltoattenuationz;
1438 m.pointer_texcoord[1] = varray_texcoord2f[1];
1439 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1441 m.tex[2] = R_GetTexture(basetexture);
1442 m.pointer_texcoord[2] = texcoord2f;
1445 m.texcubemap[3] = R_GetTexture(lightcubemap);
1447 m.pointer_texcoord3f[3] = vertex3f;
1448 m.texmatrix[3] = *matrix_modeltolight;
1450 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1451 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1454 GL_BlendFunc(GL_ONE, GL_ONE);
1456 else if (r_textureunits.integer >= 3 && !lightcubemap)
1458 // 3 2D combine path (Geforce3, original Radeon)
1459 memset(&m, 0, sizeof(m));
1460 m.pointer_vertex = vertex3f;
1461 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1463 m.pointer_texcoord3f[0] = vertex3f;
1464 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1466 m.pointer_texcoord[0] = varray_texcoord2f[0];
1467 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1469 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1471 m.pointer_texcoord3f[1] = vertex3f;
1472 m.texmatrix[1] = *matrix_modeltoattenuationz;
1474 m.pointer_texcoord[1] = varray_texcoord2f[1];
1475 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1477 m.tex[2] = R_GetTexture(basetexture);
1478 m.pointer_texcoord[2] = texcoord2f;
1479 GL_BlendFunc(GL_ONE, GL_ONE);
1483 // 2/2/2 2D combine path (any dot3 card)
1484 memset(&m, 0, sizeof(m));
1485 m.pointer_vertex = vertex3f;
1486 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1488 m.pointer_texcoord3f[0] = vertex3f;
1489 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1491 m.pointer_texcoord[0] = varray_texcoord2f[0];
1492 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1494 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1496 m.pointer_texcoord3f[1] = vertex3f;
1497 m.texmatrix[1] = *matrix_modeltoattenuationz;
1499 m.pointer_texcoord[1] = varray_texcoord2f[1];
1500 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1503 GL_ColorMask(0,0,0,1);
1504 GL_BlendFunc(GL_ONE, GL_ZERO);
1505 GL_LockArrays(0, numverts);
1506 R_Mesh_Draw(numverts, numtriangles, elements);
1507 GL_LockArrays(0, 0);
1509 c_rt_lighttris += numtriangles;
1511 memset(&m, 0, sizeof(m));
1512 m.pointer_vertex = vertex3f;
1513 m.tex[0] = R_GetTexture(basetexture);
1514 m.pointer_texcoord[0] = texcoord2f;
1517 m.texcubemap[1] = R_GetTexture(lightcubemap);
1519 m.pointer_texcoord3f[1] = vertex3f;
1520 m.texmatrix[1] = *matrix_modeltolight;
1522 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1523 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1526 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1528 // this final code is shared
1530 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1531 VectorScale(lightcolor, colorscale, color2);
1532 GL_LockArrays(0, numverts);
1533 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1535 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1536 R_Mesh_Draw(numverts, numtriangles, elements);
1538 c_rt_lighttris += numtriangles;
1540 GL_LockArrays(0, 0);
1545 colorscale = r_shadow_lightintensityscale.value * diffusescale;
1546 // colorscale accounts for how much we multiply the brightness
1549 // mult is how many times the final pass of the lighting will be
1550 // performed to get more brightness than otherwise possible.
1552 // Limit mult to 64 for sanity sake.
1553 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1555 // 3/2 3D combine path (Geforce3, Radeon 8500)
1556 memset(&m, 0, sizeof(m));
1557 m.pointer_vertex = vertex3f;
1558 m.tex[0] = R_GetTexture(bumptexture);
1559 m.texcombinergb[0] = GL_REPLACE;
1560 m.pointer_texcoord[0] = texcoord2f;
1561 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1562 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1563 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1564 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1565 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1567 m.pointer_texcoord3f[2] = vertex3f;
1568 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1570 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1571 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1574 GL_ColorMask(0,0,0,1);
1575 GL_BlendFunc(GL_ONE, GL_ZERO);
1576 GL_LockArrays(0, numverts);
1577 R_Mesh_Draw(numverts, numtriangles, elements);
1578 GL_LockArrays(0, 0);
1580 c_rt_lighttris += numtriangles;
1582 memset(&m, 0, sizeof(m));
1583 m.pointer_vertex = vertex3f;
1584 m.tex[0] = R_GetTexture(basetexture);
1585 m.pointer_texcoord[0] = texcoord2f;
1588 m.texcubemap[1] = R_GetTexture(lightcubemap);
1590 m.pointer_texcoord3f[1] = vertex3f;
1591 m.texmatrix[1] = *matrix_modeltolight;
1593 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1594 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1597 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1599 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1601 // 1/2/2 3D combine path (original Radeon)
1602 memset(&m, 0, sizeof(m));
1603 m.pointer_vertex = vertex3f;
1604 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1606 m.pointer_texcoord3f[0] = vertex3f;
1607 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1609 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1610 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1613 GL_ColorMask(0,0,0,1);
1614 GL_BlendFunc(GL_ONE, GL_ZERO);
1615 GL_LockArrays(0, numverts);
1616 R_Mesh_Draw(numverts, numtriangles, elements);
1617 GL_LockArrays(0, 0);
1619 c_rt_lighttris += numtriangles;
1621 memset(&m, 0, sizeof(m));
1622 m.pointer_vertex = vertex3f;
1623 m.tex[0] = R_GetTexture(bumptexture);
1624 m.texcombinergb[0] = GL_REPLACE;
1625 m.pointer_texcoord[0] = texcoord2f;
1626 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1627 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1628 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1629 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1631 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1632 GL_LockArrays(0, numverts);
1633 R_Mesh_Draw(numverts, numtriangles, elements);
1634 GL_LockArrays(0, 0);
1636 c_rt_lighttris += numtriangles;
1638 memset(&m, 0, sizeof(m));
1639 m.pointer_vertex = vertex3f;
1640 m.tex[0] = R_GetTexture(basetexture);
1641 m.pointer_texcoord[0] = texcoord2f;
1644 m.texcubemap[1] = R_GetTexture(lightcubemap);
1646 m.pointer_texcoord3f[1] = vertex3f;
1647 m.texmatrix[1] = *matrix_modeltolight;
1649 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1650 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1653 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1655 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1657 // 2/2 3D combine path (original Radeon)
1658 memset(&m, 0, sizeof(m));
1659 m.pointer_vertex = vertex3f;
1660 m.tex[0] = R_GetTexture(bumptexture);
1661 m.texcombinergb[0] = GL_REPLACE;
1662 m.pointer_texcoord[0] = texcoord2f;
1663 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1664 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1665 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1666 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1668 GL_ColorMask(0,0,0,1);
1669 GL_BlendFunc(GL_ONE, GL_ZERO);
1670 GL_LockArrays(0, numverts);
1671 R_Mesh_Draw(numverts, numtriangles, elements);
1672 GL_LockArrays(0, 0);
1674 c_rt_lighttris += numtriangles;
1676 memset(&m, 0, sizeof(m));
1677 m.pointer_vertex = vertex3f;
1678 m.tex[0] = R_GetTexture(basetexture);
1679 m.pointer_texcoord[0] = texcoord2f;
1680 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1682 m.pointer_texcoord3f[1] = vertex3f;
1683 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1685 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1686 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1688 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1690 else if (r_textureunits.integer >= 4)
1692 // 4/2 2D combine path (Geforce3, Radeon 8500)
1693 memset(&m, 0, sizeof(m));
1694 m.pointer_vertex = vertex3f;
1695 m.tex[0] = R_GetTexture(bumptexture);
1696 m.texcombinergb[0] = GL_REPLACE;
1697 m.pointer_texcoord[0] = texcoord2f;
1698 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1699 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1700 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1701 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1702 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1704 m.pointer_texcoord3f[2] = vertex3f;
1705 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1707 m.pointer_texcoord[2] = varray_texcoord2f[2];
1708 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1710 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1712 m.pointer_texcoord3f[3] = vertex3f;
1713 m.texmatrix[3] = *matrix_modeltoattenuationz;
1715 m.pointer_texcoord[3] = varray_texcoord2f[3];
1716 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1719 GL_ColorMask(0,0,0,1);
1720 GL_BlendFunc(GL_ONE, GL_ZERO);
1721 GL_LockArrays(0, numverts);
1722 R_Mesh_Draw(numverts, numtriangles, elements);
1723 GL_LockArrays(0, 0);
1725 c_rt_lighttris += numtriangles;
1727 memset(&m, 0, sizeof(m));
1728 m.pointer_vertex = vertex3f;
1729 m.tex[0] = R_GetTexture(basetexture);
1730 m.pointer_texcoord[0] = texcoord2f;
1733 m.texcubemap[1] = R_GetTexture(lightcubemap);
1735 m.pointer_texcoord3f[1] = vertex3f;
1736 m.texmatrix[1] = *matrix_modeltolight;
1738 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1739 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1742 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1746 // 2/2/2 2D combine path (any dot3 card)
1747 memset(&m, 0, sizeof(m));
1748 m.pointer_vertex = vertex3f;
1749 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1751 m.pointer_texcoord3f[0] = vertex3f;
1752 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1754 m.pointer_texcoord[0] = varray_texcoord2f[0];
1755 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1757 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1759 m.pointer_texcoord3f[1] = vertex3f;
1760 m.texmatrix[1] = *matrix_modeltoattenuationz;
1762 m.pointer_texcoord[1] = varray_texcoord2f[1];
1763 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1766 GL_ColorMask(0,0,0,1);
1767 GL_BlendFunc(GL_ONE, GL_ZERO);
1768 GL_LockArrays(0, numverts);
1769 R_Mesh_Draw(numverts, numtriangles, elements);
1770 GL_LockArrays(0, 0);
1772 c_rt_lighttris += numtriangles;
1774 memset(&m, 0, sizeof(m));
1775 m.pointer_vertex = vertex3f;
1776 m.tex[0] = R_GetTexture(bumptexture);
1777 m.texcombinergb[0] = GL_REPLACE;
1778 m.pointer_texcoord[0] = texcoord2f;
1779 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1780 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1781 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1782 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1784 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1785 GL_LockArrays(0, numverts);
1786 R_Mesh_Draw(numverts, numtriangles, elements);
1787 GL_LockArrays(0, 0);
1789 c_rt_lighttris += numtriangles;
1791 memset(&m, 0, sizeof(m));
1792 m.pointer_vertex = vertex3f;
1793 m.tex[0] = R_GetTexture(basetexture);
1794 m.pointer_texcoord[0] = texcoord2f;
1797 m.texcubemap[1] = R_GetTexture(lightcubemap);
1799 m.pointer_texcoord3f[1] = vertex3f;
1800 m.texmatrix[1] = *matrix_modeltolight;
1802 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1803 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1806 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1808 // this final code is shared
1810 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1811 VectorScale(lightcolor, colorscale, color2);
1812 GL_LockArrays(0, numverts);
1813 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1815 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1816 R_Mesh_Draw(numverts, numtriangles, elements);
1818 c_rt_lighttris += numtriangles;
1820 GL_LockArrays(0, 0);
1822 if (specularscale && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1824 // FIXME: detect blendsquare!
1825 //if (gl_support_blendsquare)
1827 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value * specularscale;
1828 if (glosstexture == r_shadow_blankglosstexture)
1829 colorscale *= r_shadow_gloss2intensity.value;
1831 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1833 // 2/0/0/1/2 3D combine blendsquare path
1834 memset(&m, 0, sizeof(m));
1835 m.pointer_vertex = vertex3f;
1836 m.tex[0] = R_GetTexture(bumptexture);
1837 m.pointer_texcoord[0] = texcoord2f;
1838 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1839 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1840 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1841 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1843 GL_ColorMask(0,0,0,1);
1844 // this squares the result
1845 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1846 GL_LockArrays(0, numverts);
1847 R_Mesh_Draw(numverts, numtriangles, elements);
1848 GL_LockArrays(0, 0);
1850 c_rt_lighttris += numtriangles;
1852 memset(&m, 0, sizeof(m));
1853 m.pointer_vertex = vertex3f;
1855 GL_LockArrays(0, numverts);
1856 // square alpha in framebuffer a few times to make it shiny
1857 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1858 // these comments are a test run through this math for intensity 0.5
1859 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1860 // 0.25 * 0.25 = 0.0625 (this is another pass)
1861 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1862 R_Mesh_Draw(numverts, numtriangles, elements);
1864 c_rt_lighttris += numtriangles;
1865 R_Mesh_Draw(numverts, numtriangles, elements);
1867 c_rt_lighttris += numtriangles;
1868 GL_LockArrays(0, 0);
1870 memset(&m, 0, sizeof(m));
1871 m.pointer_vertex = vertex3f;
1872 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1874 m.pointer_texcoord3f[0] = vertex3f;
1875 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1877 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1878 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1881 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1882 GL_LockArrays(0, numverts);
1883 R_Mesh_Draw(numverts, numtriangles, elements);
1884 GL_LockArrays(0, 0);
1886 c_rt_lighttris += numtriangles;
1888 memset(&m, 0, sizeof(m));
1889 m.pointer_vertex = vertex3f;
1890 m.tex[0] = R_GetTexture(glosstexture);
1891 m.pointer_texcoord[0] = texcoord2f;
1894 m.texcubemap[1] = R_GetTexture(lightcubemap);
1896 m.pointer_texcoord3f[1] = vertex3f;
1897 m.texmatrix[1] = *matrix_modeltolight;
1899 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1900 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1903 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1905 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1907 // 2/0/0/2 3D combine blendsquare path
1908 memset(&m, 0, sizeof(m));
1909 m.pointer_vertex = vertex3f;
1910 m.tex[0] = R_GetTexture(bumptexture);
1911 m.pointer_texcoord[0] = texcoord2f;
1912 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1913 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1914 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1915 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1917 GL_ColorMask(0,0,0,1);
1918 // this squares the result
1919 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1920 GL_LockArrays(0, numverts);
1921 R_Mesh_Draw(numverts, numtriangles, elements);
1922 GL_LockArrays(0, 0);
1924 c_rt_lighttris += numtriangles;
1926 memset(&m, 0, sizeof(m));
1927 m.pointer_vertex = vertex3f;
1929 GL_LockArrays(0, numverts);
1930 // square alpha in framebuffer a few times to make it shiny
1931 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1932 // these comments are a test run through this math for intensity 0.5
1933 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1934 // 0.25 * 0.25 = 0.0625 (this is another pass)
1935 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1936 R_Mesh_Draw(numverts, numtriangles, elements);
1938 c_rt_lighttris += numtriangles;
1939 R_Mesh_Draw(numverts, numtriangles, elements);
1941 c_rt_lighttris += numtriangles;
1942 GL_LockArrays(0, 0);
1944 memset(&m, 0, sizeof(m));
1945 m.pointer_vertex = vertex3f;
1946 m.tex[0] = R_GetTexture(glosstexture);
1947 m.pointer_texcoord[0] = texcoord2f;
1948 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1950 m.pointer_texcoord3f[1] = vertex3f;
1951 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1953 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1954 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1956 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1960 // 2/0/0/2/2 2D combine blendsquare path
1961 memset(&m, 0, sizeof(m));
1962 m.pointer_vertex = vertex3f;
1963 m.tex[0] = R_GetTexture(bumptexture);
1964 m.pointer_texcoord[0] = texcoord2f;
1965 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1966 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1967 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1968 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1970 GL_ColorMask(0,0,0,1);
1971 // this squares the result
1972 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1973 GL_LockArrays(0, numverts);
1974 R_Mesh_Draw(numverts, numtriangles, elements);
1975 GL_LockArrays(0, 0);
1977 c_rt_lighttris += numtriangles;
1979 memset(&m, 0, sizeof(m));
1980 m.pointer_vertex = vertex3f;
1982 GL_LockArrays(0, numverts);
1983 // square alpha in framebuffer a few times to make it shiny
1984 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1985 // these comments are a test run through this math for intensity 0.5
1986 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1987 // 0.25 * 0.25 = 0.0625 (this is another pass)
1988 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1989 R_Mesh_Draw(numverts, numtriangles, elements);
1991 c_rt_lighttris += numtriangles;
1992 R_Mesh_Draw(numverts, numtriangles, elements);
1994 c_rt_lighttris += numtriangles;
1995 GL_LockArrays(0, 0);
1997 memset(&m, 0, sizeof(m));
1998 m.pointer_vertex = vertex3f;
1999 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2001 m.pointer_texcoord3f[0] = vertex3f;
2002 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2004 m.pointer_texcoord[0] = varray_texcoord2f[0];
2005 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2007 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2009 m.pointer_texcoord3f[1] = vertex3f;
2010 m.texmatrix[1] = *matrix_modeltoattenuationz;
2012 m.pointer_texcoord[1] = varray_texcoord2f[1];
2013 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2016 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2017 GL_LockArrays(0, numverts);
2018 R_Mesh_Draw(numverts, numtriangles, elements);
2019 GL_LockArrays(0, 0);
2021 c_rt_lighttris += numtriangles;
2023 memset(&m, 0, sizeof(m));
2024 m.pointer_vertex = vertex3f;
2025 m.tex[0] = R_GetTexture(glosstexture);
2026 m.pointer_texcoord[0] = texcoord2f;
2029 m.texcubemap[1] = R_GetTexture(lightcubemap);
2031 m.pointer_texcoord3f[1] = vertex3f;
2032 m.texmatrix[1] = *matrix_modeltolight;
2034 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2035 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2038 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2041 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2042 VectorScale(lightcolor, colorscale, color2);
2043 GL_LockArrays(0, numverts);
2044 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2046 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2047 R_Mesh_Draw(numverts, numtriangles, elements);
2049 c_rt_lighttris += numtriangles;
2051 GL_LockArrays(0, 0);
2059 GL_BlendFunc(GL_ONE, GL_ONE);
2060 VectorScale(lightcolor, r_shadow_lightintensityscale.value * ambientscale, color2);
2061 memset(&m, 0, sizeof(m));
2062 m.pointer_vertex = vertex3f;
2063 m.tex[0] = R_GetTexture(basetexture);
2064 m.pointer_texcoord[0] = texcoord2f;
2065 if (r_textureunits.integer >= 2)
2068 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2070 m.pointer_texcoord3f[1] = vertex3f;
2071 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2073 m.pointer_texcoord[1] = varray_texcoord2f[1];
2074 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2076 if (r_textureunits.integer >= 3)
2078 // Geforce3/Radeon class but not using dot3
2079 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2081 m.pointer_texcoord3f[2] = vertex3f;
2082 m.texmatrix[2] = *matrix_modeltoattenuationz;
2084 m.pointer_texcoord[2] = varray_texcoord2f[2];
2085 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2089 if (r_textureunits.integer >= 3)
2090 m.pointer_color = NULL;
2092 m.pointer_color = varray_color4f;
2094 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2096 color[0] = bound(0, color2[0], 1);
2097 color[1] = bound(0, color2[1], 1);
2098 color[2] = bound(0, color2[2], 1);
2099 if (r_textureunits.integer >= 3)
2100 GL_Color(color[0], color[1], color[2], 1);
2101 else if (r_textureunits.integer >= 2)
2102 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2104 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2105 GL_LockArrays(0, numverts);
2106 R_Mesh_Draw(numverts, numtriangles, elements);
2107 GL_LockArrays(0, 0);
2109 c_rt_lighttris += numtriangles;
2114 GL_BlendFunc(GL_ONE, GL_ONE);
2115 VectorScale(lightcolor, r_shadow_lightintensityscale.value * diffusescale, color2);
2116 memset(&m, 0, sizeof(m));
2117 m.pointer_vertex = vertex3f;
2118 m.pointer_color = varray_color4f;
2119 m.tex[0] = R_GetTexture(basetexture);
2120 m.pointer_texcoord[0] = texcoord2f;
2121 if (r_textureunits.integer >= 2)
2124 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2126 m.pointer_texcoord3f[1] = vertex3f;
2127 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2129 m.pointer_texcoord[1] = varray_texcoord2f[1];
2130 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2132 if (r_textureunits.integer >= 3)
2134 // Geforce3/Radeon class but not using dot3
2135 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2137 m.pointer_texcoord3f[2] = vertex3f;
2138 m.texmatrix[2] = *matrix_modeltoattenuationz;
2140 m.pointer_texcoord[2] = varray_texcoord2f[2];
2141 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2146 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2148 color[0] = bound(0, color2[0], 1);
2149 color[1] = bound(0, color2[1], 1);
2150 color[2] = bound(0, color2[2], 1);
2151 if (r_textureunits.integer >= 3)
2152 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2153 else if (r_textureunits.integer >= 2)
2154 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2156 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2157 GL_LockArrays(0, numverts);
2158 R_Mesh_Draw(numverts, numtriangles, elements);
2159 GL_LockArrays(0, 0);
2161 c_rt_lighttris += numtriangles;
2167 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2171 R_RTLight_Uncompile(rtlight);
2172 memset(rtlight, 0, sizeof(*rtlight));
2174 VectorCopy(light->origin, rtlight->shadoworigin);
2175 VectorCopy(light->color, rtlight->color);
2176 rtlight->radius = light->radius;
2177 //rtlight->cullradius = rtlight->radius;
2178 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2179 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2180 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2181 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2182 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2183 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2184 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2185 rtlight->cubemapname[0] = 0;
2186 if (light->cubemapname[0])
2187 strcpy(rtlight->cubemapname, light->cubemapname);
2188 else if (light->cubemapnum > 0)
2189 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2190 rtlight->shadow = light->shadow;
2191 rtlight->corona = light->corona;
2192 rtlight->style = light->style;
2193 rtlight->isstatic = isstatic;
2194 rtlight->coronasizescale = light->coronasizescale;
2195 rtlight->ambientscale = light->ambientscale;
2196 rtlight->diffusescale = light->diffusescale;
2197 rtlight->specularscale = light->specularscale;
2198 rtlight->flags = light->flags;
2199 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2200 // ConcatScale won't work here because this needs to scale rotate and
2201 // translate, not just rotate
2202 scale = 1.0f / rtlight->radius;
2203 for (k = 0;k < 3;k++)
2204 for (j = 0;j < 4;j++)
2205 rtlight->matrix_worldtolight.m[k][j] *= scale;
2206 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2207 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2209 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2210 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2211 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2212 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2215 // compiles rtlight geometry
2216 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2217 void R_RTLight_Compile(rtlight_t *rtlight)
2219 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2220 entity_render_t *ent = &cl_entities[0].render;
2221 model_t *model = ent->model;
2223 // compile the light
2224 rtlight->compiled = true;
2225 rtlight->static_numclusters = 0;
2226 rtlight->static_numclusterpvsbytes = 0;
2227 rtlight->static_clusterlist = NULL;
2228 rtlight->static_clusterpvs = NULL;
2229 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2230 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2231 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2232 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2233 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2234 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2236 if (model && model->GetLightInfo)
2238 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2239 r_shadow_compilingrtlight = rtlight;
2240 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2241 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2242 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);
2243 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2244 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2247 rtlight->static_numclusters = numclusters;
2248 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2249 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2250 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2252 if (model->DrawShadowVolume && rtlight->shadow)
2254 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2255 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2256 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2258 if (model->DrawLight)
2260 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2261 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);
2262 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2264 // switch back to rendering when DrawShadowVolume or DrawLight is called
2265 r_shadow_compilingrtlight = NULL;
2269 // use smallest available cullradius - box radius or light radius
2270 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2271 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2275 if (rtlight->static_meshchain_shadow)
2278 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2281 shadowtris += mesh->numtriangles;
2287 if (rtlight->static_meshchain_light)
2290 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2293 lighttris += mesh->numtriangles;
2297 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);
2300 void R_RTLight_Uncompile(rtlight_t *rtlight)
2302 if (rtlight->compiled)
2304 if (rtlight->static_meshchain_shadow)
2305 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2306 rtlight->static_meshchain_shadow = NULL;
2307 if (rtlight->static_meshchain_light)
2308 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2309 rtlight->static_meshchain_light = NULL;
2310 if (rtlight->static_clusterlist)
2311 Mem_Free(rtlight->static_clusterlist);
2312 rtlight->static_clusterlist = NULL;
2313 if (rtlight->static_clusterpvs)
2314 Mem_Free(rtlight->static_clusterpvs);
2315 rtlight->static_clusterpvs = NULL;
2316 rtlight->static_numclusters = 0;
2317 rtlight->static_numclusterpvsbytes = 0;
2318 rtlight->compiled = false;
2322 void R_Shadow_UncompileWorldLights(void)
2325 for (light = r_shadow_worldlightchain;light;light = light->next)
2326 R_RTLight_Uncompile(&light->rtlight);
2329 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2331 int i, shadow, usestencil;
2332 entity_render_t *ent;
2334 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2335 rtexture_t *cubemaptexture;
2336 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2337 int numclusters, numsurfaces;
2338 int *clusterlist, *surfacelist;
2340 vec3_t cullmins, cullmaxs;
2344 // skip lights that don't light (corona only lights)
2345 if (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale < 0.01)
2348 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f);
2349 VectorScale(rtlight->color, f, lightcolor);
2350 if (VectorLength2(lightcolor) < 0.01)
2353 if (rtlight->selected)
2355 f = 2 + sin(realtime * M_PI * 4.0);
2356 VectorScale(lightcolor, f, lightcolor);
2360 // loading is done before visibility checks because loading should happen
2361 // all at once at the start of a level, not when it stalls gameplay.
2362 // (especially important to benchmarks)
2363 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2364 R_RTLight_Compile(rtlight);
2365 if (rtlight->cubemapname[0])
2366 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2368 cubemaptexture = NULL;
2370 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2371 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2372 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2373 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2374 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2375 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2376 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2383 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2385 // compiled light, world available and can receive realtime lighting
2386 // retrieve cluster information
2387 numclusters = rtlight->static_numclusters;
2388 clusterlist = rtlight->static_clusterlist;
2389 clusterpvs = rtlight->static_clusterpvs;
2390 VectorCopy(rtlight->cullmins, cullmins);
2391 VectorCopy(rtlight->cullmaxs, cullmaxs);
2393 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2395 // dynamic light, world available and can receive realtime lighting
2396 // if the light box is offscreen, skip it right away
2397 if (R_CullBox(cullmins, cullmaxs))
2399 // calculate lit surfaces and clusters
2400 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2401 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces);
2402 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);
2403 clusterlist = r_shadow_buffer_clusterlist;
2404 clusterpvs = r_shadow_buffer_clusterpvs;
2405 surfacelist = r_shadow_buffer_surfacelist;
2407 // if the reduced cluster bounds are offscreen, skip it
2408 if (R_CullBox(cullmins, cullmaxs))
2410 // check if light is illuminating any visible clusters
2413 for (i = 0;i < numclusters;i++)
2414 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2416 if (i == numclusters)
2419 // set up a scissor rectangle for this light
2420 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2423 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2426 if (shadow && (gl_stencil || visiblevolumes))
2428 if (!visiblevolumes)
2430 R_Shadow_Stage_ShadowVolumes();
2433 ent = &cl_entities[0].render;
2434 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2436 memset(&m, 0, sizeof(m));
2437 R_Mesh_Matrix(&ent->matrix);
2438 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2440 m.pointer_vertex = mesh->vertex3f;
2442 GL_LockArrays(0, mesh->numverts);
2443 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2445 // increment stencil if backface is behind depthbuffer
2446 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2447 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2448 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2449 c_rtcached_shadowmeshes++;
2450 c_rtcached_shadowtris += mesh->numtriangles;
2451 // decrement stencil if frontface is behind depthbuffer
2452 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2453 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2455 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2456 c_rtcached_shadowmeshes++;
2457 c_rtcached_shadowtris += mesh->numtriangles;
2458 GL_LockArrays(0, 0);
2461 else if (numsurfaces)
2463 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2464 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2466 if (r_drawentities.integer)
2468 for (i = 0;i < r_refdef.numentities;i++)
2470 ent = r_refdef.entities[i];
2472 if (r_shadow_cull.integer)
2474 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2476 if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2479 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2481 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2482 // light emitting entities should not cast their own shadow
2483 if (VectorLength2(relativelightorigin) < 0.1)
2485 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2490 if (!visiblevolumes)
2492 R_Shadow_Stage_Light(usestencil);
2494 ent = &cl_entities[0].render;
2495 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2497 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2498 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2499 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2500 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2501 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2502 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2503 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2504 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2505 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2507 R_Mesh_Matrix(&ent->matrix);
2508 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2509 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);
2512 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2514 if (r_drawentities.integer)
2516 for (i = 0;i < r_refdef.numentities;i++)
2518 ent = r_refdef.entities[i];
2519 // can't draw transparent entity lighting here because
2520 // transparent meshes are deferred for later
2521 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)
2523 lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2524 lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2525 lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2526 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2527 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2528 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2529 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2530 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2531 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);
2538 void R_ShadowVolumeLighting(int visiblevolumes)
2544 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2545 R_Shadow_EditLights_Reload_f();
2549 memset(&m, 0, sizeof(m));
2552 GL_BlendFunc(GL_ONE, GL_ONE);
2553 GL_DepthMask(false);
2554 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2555 qglDisable(GL_CULL_FACE);
2556 GL_Color(0.0, 0.0125, 0.1, 1);
2559 R_Shadow_Stage_Begin();
2560 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2561 if (r_shadow_debuglight.integer >= 0)
2563 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2564 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2565 R_DrawRTLight(&light->rtlight, visiblevolumes);
2568 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2569 if (light->flags & flag)
2570 R_DrawRTLight(&light->rtlight, visiblevolumes);
2572 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2573 R_DrawRTLight(&light->rtlight, visiblevolumes);
2577 qglEnable(GL_CULL_FACE);
2578 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2581 R_Shadow_Stage_End();
2584 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2585 typedef struct suffixinfo_s
2588 qboolean flipx, flipy, flipdiagonal;
2591 static suffixinfo_t suffix[3][6] =
2594 {"px", false, false, false},
2595 {"nx", false, false, false},
2596 {"py", false, false, false},
2597 {"ny", false, false, false},
2598 {"pz", false, false, false},
2599 {"nz", false, false, false}
2602 {"posx", false, false, false},
2603 {"negx", false, false, false},
2604 {"posy", false, false, false},
2605 {"negy", false, false, false},
2606 {"posz", false, false, false},
2607 {"negz", false, false, false}
2610 {"rt", true, false, true},
2611 {"lf", false, true, true},
2612 {"ft", true, true, false},
2613 {"bk", false, false, false},
2614 {"up", true, false, true},
2615 {"dn", true, false, true}
2619 static int componentorder[4] = {0, 1, 2, 3};
2621 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2623 int i, j, cubemapsize;
2624 qbyte *cubemappixels, *image_rgba;
2625 rtexture_t *cubemaptexture;
2627 // must start 0 so the first loadimagepixels has no requested width/height
2629 cubemappixels = NULL;
2630 cubemaptexture = NULL;
2631 // keep trying different suffix groups (posx, px, rt) until one loads
2632 for (j = 0;j < 3 && !cubemappixels;j++)
2634 // load the 6 images in the suffix group
2635 for (i = 0;i < 6;i++)
2637 // generate an image name based on the base and and suffix
2638 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2640 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2642 // an image loaded, make sure width and height are equal
2643 if (image_width == image_height)
2645 // if this is the first image to load successfully, allocate the cubemap memory
2646 if (!cubemappixels && image_width >= 1)
2648 cubemapsize = image_width;
2649 // note this clears to black, so unavailable sides are black
2650 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2652 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2654 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);
2657 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2659 Mem_Free(image_rgba);
2663 // if a cubemap loaded, upload it
2666 if (!r_shadow_filters_texturepool)
2667 r_shadow_filters_texturepool = R_AllocTexturePool();
2668 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2669 Mem_Free(cubemappixels);
2673 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2674 for (j = 0;j < 3;j++)
2675 for (i = 0;i < 6;i++)
2676 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2677 Con_Print(" and was unable to find any of them.\n");
2679 return cubemaptexture;
2682 rtexture_t *R_Shadow_Cubemap(const char *basename)
2685 for (i = 0;i < numcubemaps;i++)
2686 if (!strcasecmp(cubemaps[i].basename, basename))
2687 return cubemaps[i].texture;
2688 if (i >= MAX_CUBEMAPS)
2691 strcpy(cubemaps[i].basename, basename);
2692 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2693 return cubemaps[i].texture;
2696 void R_Shadow_FreeCubemaps(void)
2699 R_FreeTexturePool(&r_shadow_filters_texturepool);
2702 dlight_t *R_Shadow_NewWorldLight(void)
2705 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2706 light->next = r_shadow_worldlightchain;
2707 r_shadow_worldlightchain = light;
2711 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)
2713 VectorCopy(origin, light->origin);
2714 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2715 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2716 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2717 light->color[0] = max(color[0], 0);
2718 light->color[1] = max(color[1], 0);
2719 light->color[2] = max(color[2], 0);
2720 light->radius = max(radius, 0);
2721 light->style = style;
2722 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2724 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2727 light->shadow = shadowenable;
2728 light->corona = corona;
2731 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
2732 light->coronasizescale = coronasizescale;
2733 light->ambientscale = ambientscale;
2734 light->diffusescale = diffusescale;
2735 light->specularscale = specularscale;
2736 light->flags = flags;
2737 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2739 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2742 void R_Shadow_FreeWorldLight(dlight_t *light)
2744 dlight_t **lightpointer;
2745 R_RTLight_Uncompile(&light->rtlight);
2746 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2747 if (*lightpointer != light)
2748 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2749 *lightpointer = light->next;
2753 void R_Shadow_ClearWorldLights(void)
2755 while (r_shadow_worldlightchain)
2756 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2757 r_shadow_selectedlight = NULL;
2758 R_Shadow_FreeCubemaps();
2761 void R_Shadow_SelectLight(dlight_t *light)
2763 if (r_shadow_selectedlight)
2764 r_shadow_selectedlight->selected = false;
2765 r_shadow_selectedlight = light;
2766 if (r_shadow_selectedlight)
2767 r_shadow_selectedlight->selected = true;
2770 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2772 float scale = r_editlights_cursorgrid.value * 0.5f;
2773 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);
2776 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2779 const dlight_t *light;
2782 if (light->selected)
2783 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2786 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);
2789 void R_Shadow_DrawLightSprites(void)
2795 for (i = 0;i < 5;i++)
2797 lighttextures[i] = NULL;
2798 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2799 lighttextures[i] = pic->tex;
2802 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2803 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
2804 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2807 void R_Shadow_SelectLightInView(void)
2809 float bestrating, rating, temp[3];
2810 dlight_t *best, *light;
2813 for (light = r_shadow_worldlightchain;light;light = light->next)
2815 VectorSubtract(light->origin, r_vieworigin, temp);
2816 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2819 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2820 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2822 bestrating = rating;
2827 R_Shadow_SelectLight(best);
2830 void R_Shadow_LoadWorldLights(void)
2832 int n, a, style, shadow, flags;
2833 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2834 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2835 if (r_refdef.worldmodel == NULL)
2837 Con_Print("No map loaded.\n");
2840 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2841 strlcat (name, ".rtlights", sizeof (name));
2842 lightsstring = FS_LoadFile(name, tempmempool, false);
2852 for (;COM_Parse(t, true) && strcmp(
2853 if (COM_Parse(t, true))
2855 if (com_token[0] == '!')
2858 origin[0] = atof(com_token+1);
2861 origin[0] = atof(com_token);
2866 while (*s && *s != '\n')
2872 // check for modifier flags
2878 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);
2880 flags = LIGHTFLAG_REALTIMEMODE;
2888 coronasizescale = 0.25f;
2890 VectorClear(angles);
2893 if (a < 9 || !strcmp(cubemapname, "\"\""))
2895 // remove quotes on cubemapname
2896 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2898 cubemapname[strlen(cubemapname)-1] = 0;
2899 strcpy(cubemapname, cubemapname + 1);
2904 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);
2907 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2908 radius *= r_editlights_rtlightssizescale.value;
2909 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2914 Con_Printf("invalid rtlights file \"%s\"\n", name);
2915 Mem_Free(lightsstring);
2919 void R_Shadow_SaveWorldLights(void)
2922 int bufchars, bufmaxchars;
2924 char name[MAX_QPATH];
2926 if (!r_shadow_worldlightchain)
2928 if (r_refdef.worldmodel == NULL)
2930 Con_Print("No map loaded.\n");
2933 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2934 strlcat (name, ".rtlights", sizeof (name));
2935 bufchars = bufmaxchars = 0;
2937 for (light = r_shadow_worldlightchain;light;light = light->next)
2939 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2940 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);
2941 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2942 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]);
2944 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);
2945 if (bufchars + (int) strlen(line) > bufmaxchars)
2947 bufmaxchars = bufchars + strlen(line) + 2048;
2949 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2953 memcpy(buf, oldbuf, bufchars);
2959 memcpy(buf + bufchars, line, strlen(line));
2960 bufchars += strlen(line);
2964 FS_WriteFile(name, buf, bufchars);
2969 void R_Shadow_LoadLightsFile(void)
2972 char name[MAX_QPATH], *lightsstring, *s, *t;
2973 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2974 if (r_refdef.worldmodel == NULL)
2976 Con_Print("No map loaded.\n");
2979 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2980 strlcat (name, ".lights", sizeof (name));
2981 lightsstring = FS_LoadFile(name, tempmempool, false);
2989 while (*s && *s != '\n')
2994 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);
2998 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);
3001 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3002 radius = bound(15, radius, 4096);
3003 VectorScale(color, (2.0f / (8388608.0f)), color);
3004 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3009 Con_Printf("invalid lights file \"%s\"\n", name);
3010 Mem_Free(lightsstring);
3014 // tyrlite/hmap2 light types in the delay field
3015 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3017 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3019 int entnum, style, islight, skin, pflags, effects, type, n;
3022 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3023 char key[256], value[1024];
3025 if (r_refdef.worldmodel == NULL)
3027 Con_Print("No map loaded.\n");
3030 // try to load a .ent file first
3031 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3032 strlcat (key, ".ent", sizeof (key));
3033 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3034 // and if that is not found, fall back to the bsp file entity string
3036 data = r_refdef.worldmodel->brush.entities;
3039 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3041 type = LIGHTTYPE_MINUSX;
3042 origin[0] = origin[1] = origin[2] = 0;
3043 originhack[0] = originhack[1] = originhack[2] = 0;
3044 angles[0] = angles[1] = angles[2] = 0;
3045 color[0] = color[1] = color[2] = 1;
3046 light[0] = light[1] = light[2] = 1;light[3] = 300;
3047 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3057 if (!COM_ParseToken(&data, false))
3059 if (com_token[0] == '}')
3060 break; // end of entity
3061 if (com_token[0] == '_')
3062 strcpy(key, com_token + 1);
3064 strcpy(key, com_token);
3065 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3066 key[strlen(key)-1] = 0;
3067 if (!COM_ParseToken(&data, false))
3069 strcpy(value, com_token);
3071 // now that we have the key pair worked out...
3072 if (!strcmp("light", key))
3074 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3078 light[0] = vec[0] * (1.0f / 256.0f);
3079 light[1] = vec[0] * (1.0f / 256.0f);
3080 light[2] = vec[0] * (1.0f / 256.0f);
3086 light[0] = vec[0] * (1.0f / 255.0f);
3087 light[1] = vec[1] * (1.0f / 255.0f);
3088 light[2] = vec[2] * (1.0f / 255.0f);
3092 else if (!strcmp("delay", key))
3094 else if (!strcmp("origin", key))
3095 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3096 else if (!strcmp("angle", key))
3097 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3098 else if (!strcmp("angles", key))
3099 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3100 else if (!strcmp("color", key))
3101 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3102 else if (!strcmp("wait", key))
3103 fadescale = atof(value);
3104 else if (!strcmp("classname", key))
3106 if (!strncmp(value, "light", 5))
3109 if (!strcmp(value, "light_fluoro"))
3114 overridecolor[0] = 1;
3115 overridecolor[1] = 1;
3116 overridecolor[2] = 1;
3118 if (!strcmp(value, "light_fluorospark"))
3123 overridecolor[0] = 1;
3124 overridecolor[1] = 1;
3125 overridecolor[2] = 1;
3127 if (!strcmp(value, "light_globe"))
3132 overridecolor[0] = 1;
3133 overridecolor[1] = 0.8;
3134 overridecolor[2] = 0.4;
3136 if (!strcmp(value, "light_flame_large_yellow"))
3141 overridecolor[0] = 1;
3142 overridecolor[1] = 0.5;
3143 overridecolor[2] = 0.1;
3145 if (!strcmp(value, "light_flame_small_yellow"))
3150 overridecolor[0] = 1;
3151 overridecolor[1] = 0.5;
3152 overridecolor[2] = 0.1;
3154 if (!strcmp(value, "light_torch_small_white"))
3159 overridecolor[0] = 1;
3160 overridecolor[1] = 0.5;
3161 overridecolor[2] = 0.1;
3163 if (!strcmp(value, "light_torch_small_walltorch"))
3168 overridecolor[0] = 1;
3169 overridecolor[1] = 0.5;
3170 overridecolor[2] = 0.1;
3174 else if (!strcmp("style", key))
3175 style = atoi(value);
3176 else if (r_refdef.worldmodel->type == mod_brushq3)
3178 if (!strcmp("scale", key))
3179 lightscale = atof(value);
3180 if (!strcmp("fade", key))
3181 fadescale = atof(value);
3183 else if (!strcmp("skin", key))
3184 skin = (int)atof(value);
3185 else if (!strcmp("pflags", key))
3186 pflags = (int)atof(value);
3187 else if (!strcmp("effects", key))
3188 effects = (int)atof(value);
3192 if (lightscale <= 0)
3196 if (color[0] == color[1] && color[0] == color[2])
3198 color[0] *= overridecolor[0];
3199 color[1] *= overridecolor[1];
3200 color[2] *= overridecolor[2];
3202 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3203 color[0] = color[0] * light[0];
3204 color[1] = color[1] * light[1];
3205 color[2] = color[2] * light[2];
3208 case LIGHTTYPE_MINUSX:
3210 case LIGHTTYPE_RECIPX:
3212 VectorScale(color, (1.0f / 16.0f), color);
3214 case LIGHTTYPE_RECIPXX:
3216 VectorScale(color, (1.0f / 16.0f), color);
3219 case LIGHTTYPE_NONE:
3223 case LIGHTTYPE_MINUSXX:
3226 VectorAdd(origin, originhack, origin);
3228 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);
3231 Mem_Free(entfiledata);
3235 void R_Shadow_SetCursorLocationForView(void)
3237 vec_t dist, push, frac;
3238 vec3_t dest, endpos, normal;
3239 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3240 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3243 dist = frac * r_editlights_cursordistance.value;
3244 push = r_editlights_cursorpushback.value;
3248 VectorMA(endpos, push, r_viewforward, endpos);
3249 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3251 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3252 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3253 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3256 void R_Shadow_UpdateWorldLightSelection(void)
3258 if (r_editlights.integer)
3260 R_Shadow_SetCursorLocationForView();
3261 R_Shadow_SelectLightInView();
3262 R_Shadow_DrawLightSprites();
3265 R_Shadow_SelectLight(NULL);
3268 void R_Shadow_EditLights_Clear_f(void)
3270 R_Shadow_ClearWorldLights();
3273 void R_Shadow_EditLights_Reload_f(void)
3275 if (!r_refdef.worldmodel)
3277 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3278 R_Shadow_ClearWorldLights();
3279 R_Shadow_LoadWorldLights();
3280 if (r_shadow_worldlightchain == NULL)
3282 R_Shadow_LoadLightsFile();
3283 if (r_shadow_worldlightchain == NULL)
3284 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3288 void R_Shadow_EditLights_Save_f(void)
3290 if (!r_refdef.worldmodel)
3292 R_Shadow_SaveWorldLights();
3295 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3297 R_Shadow_ClearWorldLights();
3298 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3301 void R_Shadow_EditLights_ImportLightsFile_f(void)
3303 R_Shadow_ClearWorldLights();
3304 R_Shadow_LoadLightsFile();
3307 void R_Shadow_EditLights_Spawn_f(void)
3310 if (!r_editlights.integer)
3312 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3315 if (Cmd_Argc() != 1)
3317 Con_Print("r_editlights_spawn does not take parameters\n");
3320 color[0] = color[1] = color[2] = 1;
3321 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3324 void R_Shadow_EditLights_Edit_f(void)
3326 vec3_t origin, angles, color;
3327 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3328 int style, shadows, flags, normalmode, realtimemode;
3329 char cubemapname[1024];
3330 if (!r_editlights.integer)
3332 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3335 if (!r_shadow_selectedlight)
3337 Con_Print("No selected light.\n");
3340 VectorCopy(r_shadow_selectedlight->origin, origin);
3341 VectorCopy(r_shadow_selectedlight->angles, angles);
3342 VectorCopy(r_shadow_selectedlight->color, color);
3343 radius = r_shadow_selectedlight->radius;
3344 style = r_shadow_selectedlight->style;
3345 if (r_shadow_selectedlight->cubemapname)
3346 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3349 shadows = r_shadow_selectedlight->shadow;
3350 corona = r_shadow_selectedlight->corona;
3351 coronasizescale = r_shadow_selectedlight->coronasizescale;
3352 ambientscale = r_shadow_selectedlight->ambientscale;
3353 diffusescale = r_shadow_selectedlight->diffusescale;
3354 specularscale = r_shadow_selectedlight->specularscale;
3355 flags = r_shadow_selectedlight->flags;
3356 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3357 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3358 if (!strcmp(Cmd_Argv(1), "origin"))
3360 if (Cmd_Argc() != 5)
3362 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3365 origin[0] = atof(Cmd_Argv(2));
3366 origin[1] = atof(Cmd_Argv(3));
3367 origin[2] = atof(Cmd_Argv(4));
3369 else if (!strcmp(Cmd_Argv(1), "originx"))
3371 if (Cmd_Argc() != 3)
3373 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3376 origin[0] = atof(Cmd_Argv(2));
3378 else if (!strcmp(Cmd_Argv(1), "originy"))
3380 if (Cmd_Argc() != 3)
3382 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3385 origin[1] = atof(Cmd_Argv(2));
3387 else if (!strcmp(Cmd_Argv(1), "originz"))
3389 if (Cmd_Argc() != 3)
3391 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3394 origin[2] = atof(Cmd_Argv(2));
3396 else if (!strcmp(Cmd_Argv(1), "move"))
3398 if (Cmd_Argc() != 5)
3400 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3403 origin[0] += atof(Cmd_Argv(2));
3404 origin[1] += atof(Cmd_Argv(3));
3405 origin[2] += atof(Cmd_Argv(4));
3407 else if (!strcmp(Cmd_Argv(1), "movex"))
3409 if (Cmd_Argc() != 3)
3411 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3414 origin[0] += atof(Cmd_Argv(2));
3416 else if (!strcmp(Cmd_Argv(1), "movey"))
3418 if (Cmd_Argc() != 3)
3420 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3423 origin[1] += atof(Cmd_Argv(2));
3425 else if (!strcmp(Cmd_Argv(1), "movez"))
3427 if (Cmd_Argc() != 3)
3429 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3432 origin[2] += atof(Cmd_Argv(2));
3434 else if (!strcmp(Cmd_Argv(1), "angles"))
3436 if (Cmd_Argc() != 5)
3438 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3441 angles[0] = atof(Cmd_Argv(2));
3442 angles[1] = atof(Cmd_Argv(3));
3443 angles[2] = atof(Cmd_Argv(4));
3445 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3447 if (Cmd_Argc() != 3)
3449 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3452 angles[0] = atof(Cmd_Argv(2));
3454 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3456 if (Cmd_Argc() != 3)
3458 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3461 angles[1] = atof(Cmd_Argv(2));
3463 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3465 if (Cmd_Argc() != 3)
3467 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3470 angles[2] = atof(Cmd_Argv(2));
3472 else if (!strcmp(Cmd_Argv(1), "color"))
3474 if (Cmd_Argc() != 5)
3476 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3479 color[0] = atof(Cmd_Argv(2));
3480 color[1] = atof(Cmd_Argv(3));
3481 color[2] = atof(Cmd_Argv(4));
3483 else if (!strcmp(Cmd_Argv(1), "radius"))
3485 if (Cmd_Argc() != 3)
3487 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3490 radius = atof(Cmd_Argv(2));
3492 else if (!strcmp(Cmd_Argv(1), "style"))
3494 if (Cmd_Argc() != 3)
3496 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3499 style = atoi(Cmd_Argv(2));
3501 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3505 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3508 if (Cmd_Argc() == 3)
3509 strcpy(cubemapname, Cmd_Argv(2));
3513 else if (!strcmp(Cmd_Argv(1), "shadows"))
3515 if (Cmd_Argc() != 3)
3517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3520 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3522 else if (!strcmp(Cmd_Argv(1), "corona"))
3524 if (Cmd_Argc() != 3)
3526 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3529 corona = atof(Cmd_Argv(2));
3531 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3533 if (Cmd_Argc() != 3)
3535 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3538 coronasizescale = atof(Cmd_Argv(2));
3540 else if (!strcmp(Cmd_Argv(1), "ambient"))
3542 if (Cmd_Argc() != 3)
3544 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3547 ambientscale = atof(Cmd_Argv(2));
3549 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3551 if (Cmd_Argc() != 3)
3553 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3556 diffusescale = atof(Cmd_Argv(2));
3558 else if (!strcmp(Cmd_Argv(1), "specular"))
3560 if (Cmd_Argc() != 3)
3562 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3565 specularscale = atof(Cmd_Argv(2));
3567 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3569 if (Cmd_Argc() != 3)
3571 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3574 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3576 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3578 if (Cmd_Argc() != 3)
3580 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3583 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3587 Con_Print("usage: r_editlights_edit [property] [value]\n");
3588 Con_Print("Selected light's properties:\n");
3589 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3590 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3591 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3592 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3593 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3594 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3595 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3596 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3597 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3598 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3599 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3600 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3601 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3602 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3605 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3606 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3609 void R_Shadow_EditLights_EditAll_f(void)
3613 if (!r_editlights.integer)
3615 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3619 for (light = r_shadow_worldlightchain;light;light = light->next)
3621 R_Shadow_SelectLight(light);
3622 R_Shadow_EditLights_Edit_f();
3626 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3628 int lightnumber, lightcount;
3632 if (!r_editlights.integer)
3638 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3639 if (light == r_shadow_selectedlight)
3640 lightnumber = lightcount;
3641 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;
3642 if (r_shadow_selectedlight == NULL)
3644 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3645 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;
3646 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;
3647 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;
3648 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3649 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3650 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3651 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;
3652 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3653 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3654 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3655 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3656 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3657 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;
3658 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;
3661 void R_Shadow_EditLights_ToggleShadow_f(void)
3663 if (!r_editlights.integer)
3665 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3668 if (!r_shadow_selectedlight)
3670 Con_Print("No selected light.\n");
3673 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);
3676 void R_Shadow_EditLights_ToggleCorona_f(void)
3678 if (!r_editlights.integer)
3680 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3683 if (!r_shadow_selectedlight)
3685 Con_Print("No selected light.\n");
3688 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);
3691 void R_Shadow_EditLights_Remove_f(void)
3693 if (!r_editlights.integer)
3695 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3698 if (!r_shadow_selectedlight)
3700 Con_Print("No selected light.\n");
3703 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3704 r_shadow_selectedlight = NULL;
3707 void R_Shadow_EditLights_Help_f(void)
3710 "Documentation on r_editlights system:\n"
3712 "r_editlights : enable/disable editing mode\n"
3713 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3714 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3715 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3716 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3717 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3718 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3719 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3721 "r_editlights_help : this help\n"
3722 "r_editlights_clear : remove all lights\n"
3723 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3724 "r_editlights_save : save to .rtlights file\n"
3725 "r_editlights_spawn : create a light with default settings\n"
3726 "r_editlights_edit command : edit selected light - more documentation below\n"
3727 "r_editlights_remove : remove selected light\n"
3728 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3729 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3730 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3732 "origin x y z : set light location\n"
3733 "originx x: set x component of light location\n"
3734 "originy y: set y component of light location\n"
3735 "originz z: set z component of light location\n"
3736 "move x y z : adjust light location\n"
3737 "movex x: adjust x component of light location\n"
3738 "movey y: adjust y component of light location\n"
3739 "movez z: adjust z component of light location\n"
3740 "angles x y z : set light angles\n"
3741 "anglesx x: set x component of light angles\n"
3742 "anglesy y: set y component of light angles\n"
3743 "anglesz z: set z component of light angles\n"
3744 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3745 "radius radius : set radius (size) of light\n"
3746 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3747 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3748 "shadows 1/0 : turn on/off shadows\n"
3749 "corona n : set corona intensity\n"
3750 "coronasize n : set corona size (0-1)\n"
3751 "ambient n : set ambient intensity (0-1)\n"
3752 "diffuse n : set diffuse intensity (0-1)\n"
3753 "specular n : set specular intensity (0-1)\n"
3754 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3755 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3756 "<nothing> : print light properties to console\n"
3760 void R_Shadow_EditLights_CopyInfo_f(void)
3762 if (!r_editlights.integer)
3764 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3767 if (!r_shadow_selectedlight)
3769 Con_Print("No selected light.\n");
3772 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3773 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3774 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3775 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3776 if (r_shadow_selectedlight->cubemapname)
3777 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3779 r_shadow_bufferlight.cubemapname[0] = 0;
3780 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3781 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3782 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3783 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3784 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3785 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3786 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3789 void R_Shadow_EditLights_PasteInfo_f(void)
3791 if (!r_editlights.integer)
3793 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3796 if (!r_shadow_selectedlight)
3798 Con_Print("No selected light.\n");
3801 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);
3804 void R_Shadow_EditLights_Init(void)
3806 Cvar_RegisterVariable(&r_editlights);
3807 Cvar_RegisterVariable(&r_editlights_cursordistance);
3808 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3809 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3810 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3811 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3812 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3813 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3814 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3815 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3816 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3817 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3818 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3819 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3820 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3821 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3822 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3823 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3824 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3825 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3826 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3827 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);