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;
128 int r_shadow_reloadlights = false;
130 mempool_t *r_shadow_mempool;
132 int maxshadowelements;
146 rtexturepool_t *r_shadow_texturepool;
147 rtexture_t *r_shadow_normalcubetexture;
148 rtexture_t *r_shadow_attenuation2dtexture;
149 rtexture_t *r_shadow_attenuation3dtexture;
150 rtexture_t *r_shadow_blankbumptexture;
151 rtexture_t *r_shadow_blankglosstexture;
152 rtexture_t *r_shadow_blankwhitetexture;
154 // used only for light filters (cubemaps)
155 rtexturepool_t *r_shadow_filters_texturepool;
157 cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
158 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
159 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
160 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
161 cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
162 cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "0"};
163 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
164 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
165 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
166 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
167 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
168 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
169 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
170 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
171 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0"};
172 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1"};
173 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
174 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "10000"};
175 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
176 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
177 cvar_t r_shadow_worldshadows = {0, "r_shadow_worldshadows", "1"};
178 cvar_t r_shadow_dlightshadows = {CVAR_SAVE, "r_shadow_dlightshadows", "1"};
179 cvar_t r_shadow_showtris = {0, "r_shadow_showtris", "0"};
180 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
181 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
182 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
184 int c_rt_lights, c_rt_clears, c_rt_scissored;
185 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
186 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
188 void R_Shadow_ClearWorldLights(void);
189 void R_Shadow_SaveWorldLights(void);
190 void R_Shadow_LoadWorldLights(void);
191 void R_Shadow_LoadLightsFile(void);
192 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
194 void r_shadow_start(void)
196 // allocate vertex processing arrays
197 r_shadow_mempool = Mem_AllocPool("R_Shadow");
198 maxshadowelements = 0;
199 shadowelements = NULL;
207 shadowmarklist = NULL;
209 r_shadow_normalcubetexture = NULL;
210 r_shadow_attenuation2dtexture = NULL;
211 r_shadow_attenuation3dtexture = NULL;
212 r_shadow_blankbumptexture = NULL;
213 r_shadow_blankglosstexture = NULL;
214 r_shadow_blankwhitetexture = NULL;
215 r_shadow_texturepool = NULL;
216 r_shadow_filters_texturepool = NULL;
217 R_Shadow_ClearWorldLights();
218 r_shadow_reloadlights = true;
221 void r_shadow_shutdown(void)
223 R_Shadow_ClearWorldLights();
224 r_shadow_reloadlights = true;
225 r_shadow_normalcubetexture = NULL;
226 r_shadow_attenuation2dtexture = NULL;
227 r_shadow_attenuation3dtexture = NULL;
228 r_shadow_blankbumptexture = NULL;
229 r_shadow_blankglosstexture = NULL;
230 r_shadow_blankwhitetexture = NULL;
231 R_FreeTexturePool(&r_shadow_texturepool);
232 R_FreeTexturePool(&r_shadow_filters_texturepool);
233 maxshadowelements = 0;
234 shadowelements = NULL;
242 shadowmarklist = NULL;
244 Mem_FreePool(&r_shadow_mempool);
247 void r_shadow_newmap(void)
249 R_Shadow_ClearWorldLights();
250 r_shadow_reloadlights = true;
253 void R_Shadow_Help_f(void)
256 "Documentation on r_shadow system:\n"
258 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
259 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
260 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
261 "r_shadow_realtime_world : use realtime world light rendering\n"
262 "r_shadow_realtime_dlight : use high quality dlight rendering\n"
263 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to rtlights\n"
264 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
265 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
266 "r_shadow_glossintensity : brightness of textured gloss\n"
267 "r_shadow_gloss2intensity : brightness of forced gloss\n"
268 "r_shadow_debuglight : render only this light number (-1 = all)\n"
269 "r_shadow_scissor : use scissor optimization\n"
270 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
271 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
272 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
273 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
274 "r_shadow_portallight : use portal visibility for static light precomputation\n"
275 "r_shadow_projectdistance : shadow volume projection distance\n"
276 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
277 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
278 "r_shadow_worldshadows : enable world shadows\n"
279 "r_shadow_dlightshadows : enable dlight shadows\n"
281 "r_shadow_help : this help\n"
285 void R_Shadow_Init(void)
287 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
288 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
289 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
290 Cvar_RegisterVariable(&r_shadow_realtime_world);
291 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
292 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
293 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
294 Cvar_RegisterVariable(&r_shadow_gloss);
295 Cvar_RegisterVariable(&r_shadow_glossintensity);
296 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
297 Cvar_RegisterVariable(&r_shadow_debuglight);
298 Cvar_RegisterVariable(&r_shadow_scissor);
299 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
300 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
301 Cvar_RegisterVariable(&r_shadow_polygonfactor);
302 Cvar_RegisterVariable(&r_shadow_polygonoffset);
303 Cvar_RegisterVariable(&r_shadow_portallight);
304 Cvar_RegisterVariable(&r_shadow_projectdistance);
305 Cvar_RegisterVariable(&r_shadow_texture3d);
306 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
307 Cvar_RegisterVariable(&r_shadow_worldshadows);
308 Cvar_RegisterVariable(&r_shadow_dlightshadows);
309 Cvar_RegisterVariable(&r_shadow_showtris);
310 Cvar_RegisterVariable(&r_shadow_staticworldlights);
311 Cvar_RegisterVariable(&r_shadow_cull);
312 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
313 if (gamemode == GAME_TENEBRAE)
315 Cvar_SetValue("r_shadow_gloss", 2);
316 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
318 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
319 R_Shadow_EditLights_Init();
320 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
323 matrix4x4_t matrix_attenuationxyz =
326 {0.5, 0.0, 0.0, 0.5},
327 {0.0, 0.5, 0.0, 0.5},
328 {0.0, 0.0, 0.5, 0.5},
333 matrix4x4_t matrix_attenuationz =
336 {0.0, 0.0, 0.5, 0.5},
337 {0.0, 0.0, 0.0, 0.0},
338 {0.0, 0.0, 0.0, 0.0},
343 int *R_Shadow_ResizeShadowElements(int numtris)
345 // make sure shadowelements is big enough for this volume
346 if (maxshadowelements < numtris * 24)
348 maxshadowelements = numtris * 24;
350 Mem_Free(shadowelements);
351 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
353 return shadowelements;
356 void R_Shadow_PrepareShadowMark(int numtris)
358 // make sure shadowmark is big enough for this volume
359 if (maxshadowmark < numtris)
361 maxshadowmark = numtris;
363 Mem_Free(shadowmark);
365 Mem_Free(shadowmarklist);
366 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
367 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
371 // if shadowmarkcount wrapped we clear the array and adjust accordingly
372 if (shadowmarkcount == 0)
375 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
380 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)
382 int i, j, tris = 0, vr[3], t, outvertices = 0;
386 if (maxvertexupdate < innumvertices)
388 maxvertexupdate = innumvertices;
390 Mem_Free(vertexupdate);
392 Mem_Free(vertexremap);
393 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
394 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
398 if (vertexupdatenum == 0)
401 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
402 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
405 for (i = 0;i < numshadowmarktris;i++)
407 t = shadowmarktris[i];
408 shadowmark[t] = shadowmarkcount;
409 e = inelement3i + t * 3;
410 // make sure the vertices are created
411 for (j = 0;j < 3;j++)
413 if (vertexupdate[e[j]] != vertexupdatenum)
415 vertexupdate[e[j]] = vertexupdatenum;
416 vertexremap[e[j]] = outvertices;
417 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
418 f = projectdistance / VectorLength(temp);
419 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
420 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
425 // output the front and back triangles
426 outelement3i[0] = vertexremap[e[0]];
427 outelement3i[1] = vertexremap[e[1]];
428 outelement3i[2] = vertexremap[e[2]];
429 outelement3i[3] = vertexremap[e[2]] + 1;
430 outelement3i[4] = vertexremap[e[1]] + 1;
431 outelement3i[5] = vertexremap[e[0]] + 1;
436 for (i = 0;i < numshadowmarktris;i++)
438 t = shadowmarktris[i];
439 e = inelement3i + t * 3;
440 n = inneighbor3i + t * 3;
441 // output the sides (facing outward from this triangle)
442 if (shadowmark[n[0]] != shadowmarkcount)
444 vr[0] = vertexremap[e[0]];
445 vr[1] = vertexremap[e[1]];
446 outelement3i[0] = vr[1];
447 outelement3i[1] = vr[0];
448 outelement3i[2] = vr[0] + 1;
449 outelement3i[3] = vr[1];
450 outelement3i[4] = vr[0] + 1;
451 outelement3i[5] = vr[1] + 1;
455 if (shadowmark[n[1]] != shadowmarkcount)
457 vr[1] = vertexremap[e[1]];
458 vr[2] = vertexremap[e[2]];
459 outelement3i[0] = vr[2];
460 outelement3i[1] = vr[1];
461 outelement3i[2] = vr[1] + 1;
462 outelement3i[3] = vr[2];
463 outelement3i[4] = vr[1] + 1;
464 outelement3i[5] = vr[2] + 1;
468 if (shadowmark[n[2]] != shadowmarkcount)
470 vr[0] = vertexremap[e[0]];
471 vr[2] = vertexremap[e[2]];
472 outelement3i[0] = vr[0];
473 outelement3i[1] = vr[2];
474 outelement3i[2] = vr[2] + 1;
475 outelement3i[3] = vr[0];
476 outelement3i[4] = vr[2] + 1;
477 outelement3i[5] = vr[0] + 1;
483 *outnumvertices = outvertices;
487 float varray_vertex3f2[65536*3];
489 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)
492 if (projectdistance < 0.1)
494 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
497 if (!numverts || !nummarktris)
499 // make sure shadowelements is big enough for this volume
500 if (maxshadowelements < nummarktris * 24)
501 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
502 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
503 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
506 void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs)
511 // check which triangles are facing the , and then output
512 // triangle elements and vertices... by clever use of elements we
513 // can construct the whole shadow from the unprojected vertices and
514 // the projected vertices
516 // identify lit faces within the bounding box
517 R_Shadow_PrepareShadowMark(numtris);
518 for (i = 0;i < numtris;i++)
520 v[0] = invertex3f + elements[i*3+0] * 3;
521 v[1] = invertex3f + elements[i*3+1] * 3;
522 v[2] = invertex3f + elements[i*3+2] * 3;
523 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) && maxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && mins[0] < max(v[0][0], max(v[1][0], v[2][0])) && maxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && mins[1] < max(v[0][1], max(v[1][1], v[2][1])) && maxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && mins[2] < max(v[0][2], max(v[1][2], v[2][2])))
524 shadowmarklist[numshadowmark++] = i;
526 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
529 void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius)
532 mins[0] = projectorigin[0] - radius;
533 mins[1] = projectorigin[1] - radius;
534 mins[2] = projectorigin[2] - radius;
535 maxs[0] = projectorigin[0] + radius;
536 maxs[1] = projectorigin[1] + radius;
537 maxs[2] = projectorigin[2] + radius;
538 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
541 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
543 GL_VertexPointer(vertex3f);
544 if (r_shadowstage == SHADOWSTAGE_STENCIL)
546 // decrement stencil if frontface is behind depthbuffer
547 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
548 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
549 R_Mesh_Draw(numvertices, numtriangles, element3i);
551 c_rt_shadowtris += numtriangles;
552 // increment stencil if backface is behind depthbuffer
553 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
554 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
556 R_Mesh_Draw(numvertices, numtriangles, element3i);
558 c_rt_shadowtris += numtriangles;
561 void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
564 if (r_shadowstage == SHADOWSTAGE_STENCIL)
566 // decrement stencil if frontface is behind depthbuffer
567 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
568 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
569 for (mesh = firstmesh;mesh;mesh = mesh->next)
571 GL_VertexPointer(mesh->vertex3f);
572 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
573 c_rtcached_shadowmeshes++;
574 c_rtcached_shadowtris += mesh->numtriangles;
576 // increment stencil if backface is behind depthbuffer
577 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
578 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
580 for (mesh = firstmesh;mesh;mesh = mesh->next)
582 GL_VertexPointer(mesh->vertex3f);
583 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
584 c_rtcached_shadowmeshes++;
585 c_rtcached_shadowtris += mesh->numtriangles;
589 float r_shadow_attenpower, r_shadow_attenscale;
590 static void R_Shadow_MakeTextures(void)
592 int x, y, z, d, side;
593 float v[3], s, t, intensity;
595 R_FreeTexturePool(&r_shadow_texturepool);
596 r_shadow_texturepool = R_AllocTexturePool();
597 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
598 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
600 #define ATTEN2DSIZE 64
601 #define ATTEN3DSIZE 32
602 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
607 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
612 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
617 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
618 if (gl_texturecubemap)
620 for (side = 0;side < 6;side++)
622 for (y = 0;y < NORMSIZE;y++)
624 for (x = 0;x < NORMSIZE;x++)
626 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
627 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
661 intensity = 127.0f / sqrt(DotProduct(v, v));
662 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
663 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
664 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
665 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
669 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
672 r_shadow_normalcubetexture = NULL;
673 for (y = 0;y < ATTEN2DSIZE;y++)
675 for (x = 0;x < ATTEN2DSIZE;x++)
677 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
678 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
680 intensity = 1.0f - sqrt(DotProduct(v, v));
682 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
683 d = bound(0, intensity, 255);
684 data[(y*ATTEN2DSIZE+x)*4+0] = d;
685 data[(y*ATTEN2DSIZE+x)*4+1] = d;
686 data[(y*ATTEN2DSIZE+x)*4+2] = d;
687 data[(y*ATTEN2DSIZE+x)*4+3] = d;
690 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
691 if (r_shadow_texture3d.integer)
693 for (z = 0;z < ATTEN3DSIZE;z++)
695 for (y = 0;y < ATTEN3DSIZE;y++)
697 for (x = 0;x < ATTEN3DSIZE;x++)
699 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
700 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
701 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
702 intensity = 1.0f - sqrt(DotProduct(v, v));
704 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
705 d = bound(0, intensity, 255);
706 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
707 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
708 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
709 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
713 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
718 void R_Shadow_Stage_Begin(void)
722 if (r_shadow_texture3d.integer && !gl_texture3d)
723 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
724 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
725 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
727 if (!r_shadow_attenuation2dtexture
728 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
729 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
730 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
731 R_Shadow_MakeTextures();
733 memset(&m, 0, sizeof(m));
734 GL_BlendFunc(GL_ONE, GL_ZERO);
737 R_Mesh_State_Texture(&m);
738 GL_ColorPointer(NULL);
739 GL_Color(0, 0, 0, 1);
740 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
741 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
742 r_shadowstage = SHADOWSTAGE_NONE;
744 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
745 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
746 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
749 void R_Shadow_LoadWorldLightsIfNeeded(void)
751 if (r_shadow_reloadlights && cl.worldmodel)
753 R_Shadow_ClearWorldLights();
754 r_shadow_reloadlights = false;
755 R_Shadow_LoadWorldLights();
756 if (r_shadow_worldlightchain == NULL)
758 R_Shadow_LoadLightsFile();
759 if (r_shadow_worldlightchain == NULL)
760 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
765 void R_Shadow_Stage_ShadowVolumes(void)
768 memset(&m, 0, sizeof(m));
769 R_Mesh_State_Texture(&m);
770 GL_ColorPointer(NULL);
771 GL_Color(1, 1, 1, 1);
772 GL_ColorMask(0, 0, 0, 0);
773 GL_BlendFunc(GL_ONE, GL_ZERO);
776 qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
777 //if (r_shadow_polygonoffset.value != 0)
779 // qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
780 // qglEnable(GL_POLYGON_OFFSET_FILL);
783 // qglDisable(GL_POLYGON_OFFSET_FILL);
784 qglDepthFunc(GL_LESS);
785 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
786 qglEnable(GL_STENCIL_TEST);
787 qglStencilFunc(GL_ALWAYS, 128, ~0);
788 if (gl_ext_stenciltwoside.integer)
790 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
791 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
792 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
794 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
795 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
797 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
801 r_shadowstage = SHADOWSTAGE_STENCIL;
803 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
805 GL_Clear(GL_STENCIL_BUFFER_BIT);
807 // LordHavoc note: many shadow volumes reside entirely inside the world
808 // (that is to say they are entirely bounded by their lit surfaces),
809 // which can be optimized by handling things as an inverted light volume,
810 // with the shadow boundaries of the world being simulated by an altered
811 // (129) bias to stencil clearing on such lights
812 // FIXME: generate inverted light volumes for use as shadow volumes and
813 // optimize for them as noted above
816 void R_Shadow_Stage_LightWithoutShadows(void)
819 memset(&m, 0, sizeof(m));
820 R_Mesh_State_Texture(&m);
821 GL_BlendFunc(GL_ONE, GL_ONE);
824 qglPolygonOffset(0, 0);
825 //qglDisable(GL_POLYGON_OFFSET_FILL);
826 GL_ColorPointer(NULL);
827 GL_Color(1, 1, 1, 1);
828 GL_ColorMask(1, 1, 1, 1);
829 qglDepthFunc(GL_EQUAL);
830 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
831 qglDisable(GL_STENCIL_TEST);
832 if (gl_support_stenciltwoside)
833 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
835 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
836 qglStencilFunc(GL_EQUAL, 128, 0xFF);
837 r_shadowstage = SHADOWSTAGE_LIGHT;
841 void R_Shadow_Stage_LightWithShadows(void)
844 memset(&m, 0, sizeof(m));
845 R_Mesh_State_Texture(&m);
846 GL_BlendFunc(GL_ONE, GL_ONE);
849 qglPolygonOffset(0, 0);
850 //qglDisable(GL_POLYGON_OFFSET_FILL);
851 GL_ColorPointer(NULL);
852 GL_Color(1, 1, 1, 1);
853 GL_ColorMask(1, 1, 1, 1);
854 qglDepthFunc(GL_EQUAL);
855 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
856 qglEnable(GL_STENCIL_TEST);
857 if (gl_support_stenciltwoside)
858 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
860 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
861 // only draw light where this geometry was already rendered AND the
862 // stencil is 128 (values other than this mean shadow)
863 qglStencilFunc(GL_EQUAL, 128, 0xFF);
864 r_shadowstage = SHADOWSTAGE_LIGHT;
868 void R_Shadow_Stage_End(void)
871 memset(&m, 0, sizeof(m));
872 R_Mesh_State_Texture(&m);
873 GL_BlendFunc(GL_ONE, GL_ZERO);
876 qglPolygonOffset(0, 0);
877 //qglDisable(GL_POLYGON_OFFSET_FILL);
878 GL_ColorPointer(NULL);
879 GL_Color(1, 1, 1, 1);
880 GL_ColorMask(1, 1, 1, 1);
881 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
882 qglDepthFunc(GL_LEQUAL);
883 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
884 qglDisable(GL_STENCIL_TEST);
885 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
886 if (gl_support_stenciltwoside)
887 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
889 qglStencilFunc(GL_ALWAYS, 128, 0xFF);
890 r_shadowstage = SHADOWSTAGE_NONE;
893 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
895 int i, ix1, iy1, ix2, iy2;
896 float x1, y1, x2, y2, x, y, f;
899 if (!r_shadow_scissor.integer)
901 // if view is inside the box, just say yes it's visible
902 // LordHavoc: for some odd reason scissor seems broken without stencil
903 // (?!? seems like a driver bug) so abort if gl_stencil is false
904 if (!gl_stencil || BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
906 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
909 for (i = 0;i < 3;i++)
911 if (r_viewforward[i] >= 0)
922 f = DotProduct(r_viewforward, r_vieworigin) + 1;
923 if (DotProduct(r_viewforward, v2) <= f)
925 // entirely behind nearclip plane
928 if (DotProduct(r_viewforward, v) >= f)
930 // entirely infront of nearclip plane
931 x1 = y1 = x2 = y2 = 0;
932 for (i = 0;i < 8;i++)
934 v[0] = (i & 1) ? mins[0] : maxs[0];
935 v[1] = (i & 2) ? mins[1] : maxs[1];
936 v[2] = (i & 4) ? mins[2] : maxs[2];
938 GL_TransformToScreen(v, v2);
939 //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]);
958 // clipped by nearclip plane
959 // this is nasty and crude...
960 // create viewspace bbox
961 for (i = 0;i < 8;i++)
963 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
964 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
965 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
966 v2[0] = -DotProduct(v, r_viewleft);
967 v2[1] = DotProduct(v, r_viewup);
968 v2[2] = DotProduct(v, r_viewforward);
971 if (smins[0] > v2[0]) smins[0] = v2[0];
972 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
973 if (smins[1] > v2[1]) smins[1] = v2[1];
974 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
975 if (smins[2] > v2[2]) smins[2] = v2[2];
976 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
980 smins[0] = smaxs[0] = v2[0];
981 smins[1] = smaxs[1] = v2[1];
982 smins[2] = smaxs[2] = v2[2];
985 // now we have a bbox in viewspace
986 // clip it to the view plane
989 // return true if that culled the box
990 if (smins[2] >= smaxs[2])
992 // ok some of it is infront of the view, transform each corner back to
993 // worldspace and then to screenspace and make screen rect
994 // initialize these variables just to avoid compiler warnings
995 x1 = y1 = x2 = y2 = 0;
996 for (i = 0;i < 8;i++)
998 v2[0] = (i & 1) ? smins[0] : smaxs[0];
999 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1000 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1001 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1002 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1003 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1005 GL_TransformToScreen(v, v2);
1006 //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]);
1023 // this code doesn't handle boxes with any points behind view properly
1024 x1 = 1000;x2 = -1000;
1025 y1 = 1000;y2 = -1000;
1026 for (i = 0;i < 8;i++)
1028 v[0] = (i & 1) ? mins[0] : maxs[0];
1029 v[1] = (i & 2) ? mins[1] : maxs[1];
1030 v[2] = (i & 4) ? mins[2] : maxs[2];
1032 GL_TransformToScreen(v, v2);
1033 //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]);
1051 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1052 if (ix1 < r_view_x) ix1 = r_view_x;
1053 if (iy1 < r_view_y) iy1 = r_view_y;
1054 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1055 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1056 if (ix2 <= ix1 || iy2 <= iy1)
1058 // set up the scissor rectangle
1059 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1060 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1061 //qglEnable(GL_SCISSOR_TEST);
1066 void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1068 float *color4f = varray_color4f;
1069 float dist, dot, intensity, v[3], n[3];
1070 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1072 Matrix4x4_Transform(m, vertex3f, v);
1073 if ((dist = DotProduct(v, v)) < 1)
1075 Matrix4x4_Transform3x3(m, normal3f, n);
1076 if ((dot = DotProduct(n, v)) > 0)
1079 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1080 VectorScale(lightcolor, intensity, color4f);
1085 VectorClear(color4f);
1091 VectorClear(color4f);
1097 void R_Shadow_VertexLightingWithXYAttenuationTexture(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1099 float *color4f = varray_color4f;
1100 float dist, dot, intensity, v[3], n[3];
1101 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1103 Matrix4x4_Transform(m, vertex3f, v);
1104 if ((dist = fabs(v[2])) < 1)
1106 Matrix4x4_Transform3x3(m, normal3f, n);
1107 if ((dot = DotProduct(n, v)) > 0)
1109 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1110 VectorScale(lightcolor, intensity, color4f);
1115 VectorClear(color4f);
1121 VectorClear(color4f);
1127 // FIXME: this should be done in a vertex program when possible
1128 // FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
1129 void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1133 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1134 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1135 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1142 void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1146 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1147 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1154 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)
1158 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1160 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1161 // the cubemap normalizes this for us
1162 out3f[0] = DotProduct(svector3f, lightdir);
1163 out3f[1] = DotProduct(tvector3f, lightdir);
1164 out3f[2] = DotProduct(normal3f, lightdir);
1168 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)
1171 float lightdir[3], eyedir[3], halfdir[3];
1172 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1174 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1175 VectorNormalizeFast(lightdir);
1176 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1177 VectorNormalizeFast(eyedir);
1178 VectorAdd(lightdir, eyedir, halfdir);
1179 // the cubemap normalizes this for us
1180 out3f[0] = DotProduct(svector3f, halfdir);
1181 out3f[1] = DotProduct(tvector3f, halfdir);
1182 out3f[2] = DotProduct(normal3f, halfdir);
1186 void R_Shadow_DiffuseLighting(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 *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
1189 float color[3], color2[3];
1191 GL_VertexPointer(vertex3f);
1192 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1195 bumptexture = r_shadow_blankbumptexture;
1196 GL_ColorPointer(NULL);
1198 // colorscale accounts for how much we multiply the brightness during combine
1199 // mult is how many times the final pass of the lighting will be
1200 // performed to get more brightness than otherwise possible
1201 // limit mult to 64 for sanity sake
1202 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1204 // 3/2 3D combine path (Geforce3, Radeon 8500)
1205 memset(&m, 0, sizeof(m));
1206 m.tex[0] = R_GetTexture(bumptexture);
1207 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1208 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1209 m.texcombinergb[0] = GL_REPLACE;
1210 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1211 m.pointer_texcoord[0] = texcoord2f;
1212 m.pointer_texcoord[1] = varray_texcoord3f[1];
1213 m.pointer_texcoord[2] = varray_texcoord3f[2];
1214 R_Mesh_State_Texture(&m);
1215 GL_ColorMask(0,0,0,1);
1216 GL_BlendFunc(GL_ONE, GL_ZERO);
1217 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1218 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1219 R_Mesh_Draw(numverts, numtriangles, elements);
1221 c_rt_lighttris += numtriangles;
1223 memset(&m, 0, sizeof(m));
1224 m.tex[0] = R_GetTexture(basetexture);
1225 m.pointer_texcoord[0] = texcoord2f;
1228 m.texcubemap[1] = R_GetTexture(lightcubemap);
1229 m.pointer_texcoord[1] = varray_texcoord3f[1];
1230 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1232 R_Mesh_State_Texture(&m);
1233 GL_ColorMask(1,1,1,0);
1234 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1235 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1236 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1238 color[0] = bound(0, color2[0], 1);
1239 color[1] = bound(0, color2[1], 1);
1240 color[2] = bound(0, color2[2], 1);
1241 GL_Color(color[0], color[1], color[2], 1);
1242 R_Mesh_Draw(numverts, numtriangles, elements);
1244 c_rt_lighttris += numtriangles;
1247 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1249 // 1/2/2 3D combine path (original Radeon)
1250 memset(&m, 0, sizeof(m));
1251 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1252 m.pointer_texcoord[0] = varray_texcoord3f[0];
1253 R_Mesh_State_Texture(&m);
1254 GL_ColorMask(0,0,0,1);
1255 GL_BlendFunc(GL_ONE, GL_ZERO);
1256 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1257 R_Mesh_Draw(numverts, numtriangles, elements);
1259 c_rt_lighttris += numtriangles;
1261 memset(&m, 0, sizeof(m));
1262 m.tex[0] = R_GetTexture(bumptexture);
1263 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1264 m.texcombinergb[0] = GL_REPLACE;
1265 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1266 m.pointer_texcoord[0] = texcoord2f;
1267 m.pointer_texcoord[1] = varray_texcoord3f[1];
1268 R_Mesh_State_Texture(&m);
1269 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1270 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1271 R_Mesh_Draw(numverts, numtriangles, elements);
1273 c_rt_lighttris += numtriangles;
1275 memset(&m, 0, sizeof(m));
1276 m.tex[0] = R_GetTexture(basetexture);
1277 m.pointer_texcoord[0] = texcoord2f;
1280 m.texcubemap[1] = R_GetTexture(lightcubemap);
1281 m.pointer_texcoord[1] = varray_texcoord3f[1];
1282 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1284 R_Mesh_State_Texture(&m);
1285 GL_ColorMask(1,1,1,0);
1286 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1287 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1288 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1290 color[0] = bound(0, color2[0], 1);
1291 color[1] = bound(0, color2[1], 1);
1292 color[2] = bound(0, color2[2], 1);
1293 GL_Color(color[0], color[1], color[2], 1);
1294 R_Mesh_Draw(numverts, numtriangles, elements);
1296 c_rt_lighttris += numtriangles;
1299 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1301 // 2/2 3D combine path (original Radeon)
1302 memset(&m, 0, sizeof(m));
1303 m.tex[0] = R_GetTexture(bumptexture);
1304 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1305 m.texcombinergb[0] = GL_REPLACE;
1306 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1307 m.pointer_texcoord[0] = texcoord2f;
1308 m.pointer_texcoord[1] = varray_texcoord3f[1];
1309 R_Mesh_State_Texture(&m);
1310 GL_ColorMask(0,0,0,1);
1311 GL_BlendFunc(GL_ONE, GL_ZERO);
1312 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1313 R_Mesh_Draw(numverts, numtriangles, elements);
1315 c_rt_lighttris += numtriangles;
1317 memset(&m, 0, sizeof(m));
1318 m.tex[0] = R_GetTexture(basetexture);
1319 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1320 m.pointer_texcoord[0] = texcoord2f;
1321 m.pointer_texcoord[1] = varray_texcoord3f[1];
1322 R_Mesh_State_Texture(&m);
1323 GL_ColorMask(1,1,1,0);
1324 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1325 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1326 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1327 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1329 color[0] = bound(0, color2[0], 1);
1330 color[1] = bound(0, color2[1], 1);
1331 color[2] = bound(0, color2[2], 1);
1332 GL_Color(color[0], color[1], color[2], 1);
1333 R_Mesh_Draw(numverts, numtriangles, elements);
1335 c_rt_lighttris += numtriangles;
1338 else if (r_textureunits.integer >= 4)
1340 // 4/2 2D combine path (Geforce3, Radeon 8500)
1341 memset(&m, 0, sizeof(m));
1342 m.tex[0] = R_GetTexture(bumptexture);
1343 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1344 m.texcombinergb[0] = GL_REPLACE;
1345 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1346 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1347 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1348 m.pointer_texcoord[0] = texcoord2f;
1349 m.pointer_texcoord[1] = varray_texcoord3f[1];
1350 m.pointer_texcoord[2] = varray_texcoord2f[2];
1351 m.pointer_texcoord[3] = varray_texcoord2f[3];
1352 R_Mesh_State_Texture(&m);
1353 GL_ColorMask(0,0,0,1);
1354 GL_BlendFunc(GL_ONE, GL_ZERO);
1355 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1356 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1357 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1358 R_Mesh_Draw(numverts, numtriangles, elements);
1360 c_rt_lighttris += numtriangles;
1362 memset(&m, 0, sizeof(m));
1363 m.tex[0] = R_GetTexture(basetexture);
1364 m.pointer_texcoord[0] = texcoord2f;
1367 m.texcubemap[1] = R_GetTexture(lightcubemap);
1368 m.pointer_texcoord[1] = varray_texcoord3f[1];
1369 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1371 R_Mesh_State_Texture(&m);
1372 GL_ColorMask(1,1,1,0);
1373 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1374 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1375 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1377 color[0] = bound(0, color2[0], 1);
1378 color[1] = bound(0, color2[1], 1);
1379 color[2] = bound(0, color2[2], 1);
1380 GL_Color(color[0], color[1], color[2], 1);
1381 R_Mesh_Draw(numverts, numtriangles, elements);
1383 c_rt_lighttris += numtriangles;
1388 // 2/2/2 2D combine path (any dot3 card)
1389 memset(&m, 0, sizeof(m));
1390 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1391 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1392 m.pointer_texcoord[0] = varray_texcoord2f[0];
1393 m.pointer_texcoord[1] = varray_texcoord2f[1];
1394 R_Mesh_State_Texture(&m);
1395 GL_ColorMask(0,0,0,1);
1396 GL_BlendFunc(GL_ONE, GL_ZERO);
1397 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1398 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1399 R_Mesh_Draw(numverts, numtriangles, elements);
1401 c_rt_lighttris += numtriangles;
1403 memset(&m, 0, sizeof(m));
1404 m.tex[0] = R_GetTexture(bumptexture);
1405 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1406 m.texcombinergb[0] = GL_REPLACE;
1407 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1408 m.pointer_texcoord[0] = texcoord2f;
1409 m.pointer_texcoord[1] = varray_texcoord3f[1];
1410 R_Mesh_State_Texture(&m);
1411 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1412 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1413 R_Mesh_Draw(numverts, numtriangles, elements);
1415 c_rt_lighttris += numtriangles;
1417 memset(&m, 0, sizeof(m));
1418 m.tex[0] = R_GetTexture(basetexture);
1419 m.pointer_texcoord[0] = texcoord2f;
1422 m.texcubemap[1] = R_GetTexture(lightcubemap);
1423 m.pointer_texcoord[1] = varray_texcoord3f[1];
1424 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1426 R_Mesh_State_Texture(&m);
1427 GL_ColorMask(1,1,1,0);
1428 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1429 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1430 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1432 color[0] = bound(0, color2[0], 1);
1433 color[1] = bound(0, color2[1], 1);
1434 color[2] = bound(0, color2[2], 1);
1435 GL_Color(color[0], color[1], color[2], 1);
1436 R_Mesh_Draw(numverts, numtriangles, elements);
1438 c_rt_lighttris += numtriangles;
1444 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1445 GL_DepthMask(false);
1447 GL_ColorPointer(varray_color4f);
1448 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1449 memset(&m, 0, sizeof(m));
1450 m.tex[0] = R_GetTexture(basetexture);
1451 m.pointer_texcoord[0] = texcoord2f;
1452 if (r_textureunits.integer >= 2)
1455 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1456 m.pointer_texcoord[1] = varray_texcoord2f[1];
1457 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1459 R_Mesh_State_Texture(&m);
1460 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1462 color[0] = bound(0, color2[0], 1);
1463 color[1] = bound(0, color2[1], 1);
1464 color[2] = bound(0, color2[2], 1);
1465 if (r_textureunits.integer >= 2)
1466 R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1468 R_Shadow_VertexLighting(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1469 R_Mesh_Draw(numverts, numtriangles, elements);
1471 c_rt_lighttris += numtriangles;
1476 void R_Shadow_SpecularLighting(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 *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
1479 float color[3], color2[3], colorscale;
1481 if (!gl_dot3arb || !gl_texturecubemap || !gl_combine.integer || !gl_stencil)
1484 glosstexture = r_shadow_blankglosstexture;
1485 if (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))
1487 colorscale = r_shadow_glossintensity.value;
1489 bumptexture = r_shadow_blankbumptexture;
1490 if (glosstexture == r_shadow_blankglosstexture)
1491 colorscale *= r_shadow_gloss2intensity.value;
1492 GL_VertexPointer(vertex3f);
1493 GL_ColorPointer(NULL);
1495 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1497 // 2/0/0/1/2 3D combine blendsquare path
1498 memset(&m, 0, sizeof(m));
1499 m.tex[0] = R_GetTexture(bumptexture);
1500 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1501 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1502 m.pointer_texcoord[0] = texcoord2f;
1503 m.pointer_texcoord[1] = varray_texcoord3f[1];
1504 R_Mesh_State_Texture(&m);
1505 GL_ColorMask(0,0,0,1);
1506 // this squares the result
1507 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1508 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1509 R_Mesh_Draw(numverts, numtriangles, elements);
1511 c_rt_lighttris += numtriangles;
1513 memset(&m, 0, sizeof(m));
1514 R_Mesh_State_Texture(&m);
1515 // square alpha in framebuffer a few times to make it shiny
1516 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1517 // these comments are a test run through this math for intensity 0.5
1518 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1519 // 0.25 * 0.25 = 0.0625 (this is another pass)
1520 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1521 R_Mesh_Draw(numverts, numtriangles, elements);
1523 c_rt_lighttris += numtriangles;
1524 R_Mesh_Draw(numverts, numtriangles, elements);
1526 c_rt_lighttris += numtriangles;
1528 memset(&m, 0, sizeof(m));
1529 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1530 m.pointer_texcoord[0] = varray_texcoord3f[0];
1531 R_Mesh_State_Texture(&m);
1532 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1533 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1534 R_Mesh_Draw(numverts, numtriangles, elements);
1536 c_rt_lighttris += numtriangles;
1538 memset(&m, 0, sizeof(m));
1539 m.tex[0] = R_GetTexture(glosstexture);
1542 m.texcubemap[1] = R_GetTexture(lightcubemap);
1543 m.pointer_texcoord[1] = varray_texcoord3f[1];
1544 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1546 m.pointer_texcoord[0] = texcoord2f;
1547 R_Mesh_State_Texture(&m);
1548 GL_ColorMask(1,1,1,0);
1549 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1550 VectorScale(lightcolor, colorscale, color2);
1551 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1553 color[0] = bound(0, color2[0], 1);
1554 color[1] = bound(0, color2[1], 1);
1555 color[2] = bound(0, color2[2], 1);
1556 GL_Color(color[0], color[1], color[2], 1);
1557 R_Mesh_Draw(numverts, numtriangles, elements);
1559 c_rt_lighttris += numtriangles;
1562 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1564 // 2/0/0/2 3D combine blendsquare path
1565 memset(&m, 0, sizeof(m));
1566 m.tex[0] = R_GetTexture(bumptexture);
1567 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1568 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1569 m.pointer_texcoord[0] = texcoord2f;
1570 m.pointer_texcoord[1] = varray_texcoord3f[1];
1571 R_Mesh_State_Texture(&m);
1572 GL_ColorMask(0,0,0,1);
1573 // this squares the result
1574 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1575 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1576 R_Mesh_Draw(numverts, numtriangles, elements);
1578 c_rt_lighttris += numtriangles;
1580 memset(&m, 0, sizeof(m));
1581 R_Mesh_State_Texture(&m);
1582 // square alpha in framebuffer a few times to make it shiny
1583 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1584 // these comments are a test run through this math for intensity 0.5
1585 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1586 // 0.25 * 0.25 = 0.0625 (this is another pass)
1587 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1588 R_Mesh_Draw(numverts, numtriangles, elements);
1590 c_rt_lighttris += numtriangles;
1591 R_Mesh_Draw(numverts, numtriangles, elements);
1593 c_rt_lighttris += numtriangles;
1595 memset(&m, 0, sizeof(m));
1596 m.tex[0] = R_GetTexture(glosstexture);
1597 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1598 m.pointer_texcoord[0] = texcoord2f;
1599 m.pointer_texcoord[1] = varray_texcoord3f[1];
1600 R_Mesh_State_Texture(&m);
1601 GL_ColorMask(1,1,1,0);
1602 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1603 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1604 VectorScale(lightcolor, colorscale, color2);
1605 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1607 color[0] = bound(0, color2[0], 1);
1608 color[1] = bound(0, color2[1], 1);
1609 color[2] = bound(0, color2[2], 1);
1610 GL_Color(color[0], color[1], color[2], 1);
1611 R_Mesh_Draw(numverts, numtriangles, elements);
1613 c_rt_lighttris += numtriangles;
1616 else if (r_textureunits.integer >= 2 /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1618 // 2/0/0/2/2 2D combine blendsquare path
1619 memset(&m, 0, sizeof(m));
1620 m.tex[0] = R_GetTexture(bumptexture);
1621 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1622 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1623 m.pointer_texcoord[0] = texcoord2f;
1624 m.pointer_texcoord[1] = varray_texcoord3f[1];
1625 R_Mesh_State_Texture(&m);
1626 GL_ColorMask(0,0,0,1);
1627 // this squares the result
1628 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1629 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1630 R_Mesh_Draw(numverts, numtriangles, elements);
1632 c_rt_lighttris += numtriangles;
1634 memset(&m, 0, sizeof(m));
1635 R_Mesh_State_Texture(&m);
1636 // square alpha in framebuffer a few times to make it shiny
1637 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1638 // these comments are a test run through this math for intensity 0.5
1639 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1640 // 0.25 * 0.25 = 0.0625 (this is another pass)
1641 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1642 R_Mesh_Draw(numverts, numtriangles, elements);
1644 c_rt_lighttris += numtriangles;
1645 R_Mesh_Draw(numverts, numtriangles, elements);
1647 c_rt_lighttris += numtriangles;
1649 memset(&m, 0, sizeof(m));
1650 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1651 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1652 m.pointer_texcoord[0] = varray_texcoord2f[0];
1653 m.pointer_texcoord[1] = varray_texcoord2f[1];
1654 R_Mesh_State_Texture(&m);
1655 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1656 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1657 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1658 R_Mesh_Draw(numverts, numtriangles, elements);
1660 c_rt_lighttris += numtriangles;
1662 memset(&m, 0, sizeof(m));
1663 m.tex[0] = R_GetTexture(glosstexture);
1666 m.texcubemap[1] = R_GetTexture(lightcubemap);
1667 m.pointer_texcoord[1] = varray_texcoord3f[1];
1668 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1670 m.pointer_texcoord[0] = texcoord2f;
1671 R_Mesh_State_Texture(&m);
1672 GL_ColorMask(1,1,1,0);
1673 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1674 VectorScale(lightcolor, colorscale, color2);
1675 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1677 color[0] = bound(0, color2[0], 1);
1678 color[1] = bound(0, color2[1], 1);
1679 color[2] = bound(0, color2[2], 1);
1680 GL_Color(color[0], color[1], color[2], 1);
1681 R_Mesh_Draw(numverts, numtriangles, elements);
1683 c_rt_lighttris += numtriangles;
1689 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1693 R_RTLight_Uncompile(rtlight);
1694 memset(rtlight, 0, sizeof(*rtlight));
1696 VectorCopy(light->origin, rtlight->shadoworigin);
1697 VectorCopy(light->color, rtlight->color);
1698 rtlight->radius = light->radius;
1699 rtlight->cullradius = rtlight->radius;
1700 rtlight->cullradius2 = rtlight->cullradius * rtlight->cullradius;
1701 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->cullradius;
1702 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->cullradius;
1703 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->cullradius;
1704 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->cullradius;
1705 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->cullradius;
1706 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->cullradius;
1707 rtlight->cubemapname[0] = 0;
1708 if (light->cubemapname[0])
1709 strcpy(rtlight->cubemapname, light->cubemapname);
1710 else if (light->cubemapnum > 0)
1711 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1712 rtlight->shadow = light->shadow;
1713 rtlight->corona = light->corona;
1714 rtlight->style = light->style;
1715 rtlight->isstatic = isstatic;
1716 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1717 // ConcatScale won't work here because this needs to scale rotate and
1718 // translate, not just rotate
1719 scale = 1.0f / rtlight->radius;
1720 for (k = 0;k < 3;k++)
1721 for (j = 0;j < 4;j++)
1722 rtlight->matrix_worldtolight.m[k][j] *= scale;
1723 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1724 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1726 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1727 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1728 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.25f, rtlight->lightmap_light);
1729 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1732 // compiles rtlight geometry
1733 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1734 void R_RTLight_Compile(rtlight_t *rtlight)
1736 int i, j, k, l, maxverts = 256, tris;
1737 float *vertex3f = NULL, mins[3], maxs[3];
1738 shadowmesh_t *mesh, *castmesh = NULL;
1740 qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8];
1741 qbyte lightfullpvs[(MAX_MAP_LEAFS + 7)/ 8];
1743 // compile the light
1744 rtlight->compiled = true;
1745 VectorCopy(rtlight->cullmins, mins);
1746 VectorCopy(rtlight->cullmaxs, maxs);
1747 if (rtlight->shadow)
1748 castmesh = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1749 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1752 lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, rtlight->shadoworigin, 0, lightfullpvs, sizeof(lightfullpvs));
1753 memset(lightpvs, 0, lightpvsbytes);
1754 if (cl.worldmodel->brushq3.num_leafs)
1759 // make a pvs that only includes things within the box
1760 for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
1761 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1762 SETPVSBIT(lightpvs, leaf->clusterindex);
1764 // make a cluster list for fast visibility checking during rendering
1765 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1766 if (CHECKPVSBIT(lightpvs, i))
1767 rtlight->static_numclusters++;
1768 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1769 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1770 if (CHECKPVSBIT(lightpvs, i))
1771 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1773 VectorCopy(rtlight->shadoworigin, rtlight->cullmins);
1774 VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs);
1775 for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
1776 face->lighttemp_castshadow = false;
1777 for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
1779 if (CHECKPVSBIT(lightpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1781 for (k = 0;k < 3;k++)
1783 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1784 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1786 for (j = 0;j < leaf->numleaffaces;j++)
1788 face = leaf->firstleafface[j];
1789 if (BoxesOverlap(face->mins, face->maxs, mins, maxs))
1790 face->lighttemp_castshadow = true;
1795 // add surfaces to shadow casting mesh and light mesh
1796 for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
1798 if (face->lighttemp_castshadow)
1800 face->lighttemp_castshadow = false;
1801 if (!(face->texture->surfaceflags & (Q3SURFACEFLAG_NODRAW | Q3SURFACEFLAG_SKY)))
1803 if (rtlight->shadow)
1804 if (!(face->texture->nativecontents & CONTENTSQ3_TRANSLUCENT))
1805 Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, face->data_vertex3f, NULL, NULL, NULL, NULL, face->num_triangles, face->data_element3i);
1806 if (!(face->texture->surfaceflags & Q3SURFACEFLAG_SKY))
1807 Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_light, face->texture->skin.base, face->texture->skin.gloss, face->texture->skin.nmap, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, face->num_triangles, face->data_element3i);
1812 else if (cl.worldmodel->brushq1.num_leafs)
1816 VectorCopy(rtlight->shadoworigin, rtlight->cullmins);
1817 VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs);
1818 i = CL_PointQ1Contents(rtlight->shadoworigin);
1820 for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
1821 surf->lighttemp_castshadow = false;
1823 if (r_shadow_portallight.integer && i != CONTENTS_SOLID && i != CONTENTS_SKY)
1826 qbyte *bytesurfacepvs;
1828 byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.num_leafs);
1829 bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numsurfaces);
1831 Portal_Visibility(cl.worldmodel, rtlight->shadoworigin, byteleafpvs, bytesurfacepvs, NULL, 0, true, mins, maxs, rtlight->cullmins, rtlight->cullmaxs);
1833 // make a pvs that only includes things within the box
1834 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1836 if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1838 SETPVSBIT(lightpvs, leaf->clusterindex);
1839 for (k = 0;k < 3;k++)
1841 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1842 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1847 for (i = 0, surf = cl.worldmodel->brushq1.surfaces;i < cl.worldmodel->brushq1.numsurfaces;i++, surf++)
1848 if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
1849 surf->lighttemp_castshadow = true;
1851 Mem_Free(byteleafpvs);
1852 Mem_Free(bytesurfacepvs);
1854 // make a cluster list for fast visibility checking during rendering
1855 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1856 if (CHECKPVSBIT(lightpvs, i))
1857 rtlight->static_numclusters++;
1858 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1859 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1860 if (CHECKPVSBIT(lightpvs, i))
1861 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1865 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1867 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1869 // make a pvs that only includes things within the box
1870 SETPVSBIT(lightpvs, leaf->clusterindex);
1871 for (k = 0;k < 3;k++)
1873 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1874 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1876 for (j = 0;j < leaf->nummarksurfaces;j++)
1878 surf = cl.worldmodel->brushq1.surfaces + leaf->firstmarksurface[j];
1879 if (!surf->lighttemp_castshadow && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
1880 surf->lighttemp_castshadow = true;
1885 // make a pvs that only includes things within the box
1886 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1887 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1888 SETPVSBIT(lightpvs, leaf->clusterindex);
1890 // make a cluster list for fast visibility checking during rendering
1891 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1892 if (CHECKPVSBIT(lightpvs, i))
1893 rtlight->static_numclusters++;
1894 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1895 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1896 if (CHECKPVSBIT(lightpvs, i))
1897 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1900 // add surfaces to shadow casting mesh and light mesh
1901 for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
1903 if (surf->lighttemp_castshadow)
1905 surf->lighttemp_castshadow = false;
1906 if (rtlight->shadow && (surf->flags & SURF_SHADOWCAST))
1907 Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, surf->mesh.data_vertex3f, NULL, NULL, NULL, NULL, surf->mesh.num_triangles, surf->mesh.data_element3i);
1908 if (!(surf->flags & SURF_DRAWSKY))
1909 Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_light, surf->texinfo->texture->skin.base, surf->texinfo->texture->skin.gloss, surf->texinfo->texture->skin.nmap, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, surf->mesh.num_triangles, surf->mesh.data_element3i);
1915 // limit box to light bounds (in case it grew larger)
1916 for (k = 0;k < 3;k++)
1918 if (rtlight->cullmins[k] < rtlight->shadoworigin[k] - rtlight->radius) rtlight->cullmins[k] = rtlight->shadoworigin[k] - rtlight->radius;
1919 if (rtlight->cullmaxs[k] > rtlight->shadoworigin[k] + rtlight->radius) rtlight->cullmaxs[k] = rtlight->shadoworigin[k] + rtlight->radius;
1921 rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1922 rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1924 // cast shadow volume from castmesh
1925 castmesh = Mod_ShadowMesh_Finish(r_shadow_mempool, castmesh, false, true);
1929 for (mesh = castmesh;mesh;mesh = mesh->next)
1931 R_Shadow_ResizeShadowElements(mesh->numtriangles);
1932 maxverts = max(maxverts, mesh->numverts * 2);
1937 vertex3f = Mem_Alloc(r_shadow_mempool, maxverts * sizeof(float[3]));
1938 // now that we have the buffers big enough, construct and add
1939 // the shadow volume mesh
1940 if (rtlight->shadow)
1941 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1942 for (mesh = castmesh;mesh;mesh = mesh->next)
1944 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1945 R_Shadow_PrepareShadowMark(mesh->numtriangles);
1946 for (i = 0;i < mesh->numtriangles;i++)
1949 v[0] = mesh->vertex3f + mesh->element3i[i*3+0] * 3;
1950 v[1] = mesh->vertex3f + mesh->element3i[i*3+1] * 3;
1951 v[2] = mesh->vertex3f + mesh->element3i[i*3+2] * 3;
1952 if (PointInfrontOfTriangle(rtlight->shadoworigin, v[0], v[1], v[2]) && rtlight->cullmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && rtlight->cullmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && rtlight->cullmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && rtlight->cullmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && rtlight->cullmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && rtlight->cullmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
1953 shadowmarklist[numshadowmark++] = i;
1955 if (maxshadowelements < numshadowmark * 24)
1956 R_Shadow_ResizeShadowElements((numshadowmark + 256) * 24);
1957 if ((tris = R_Shadow_ConstructShadowVolume(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->neighbor3i, mesh->vertex3f, NULL, shadowelements, vertex3f, rtlight->shadoworigin, r_shadow_projectdistance.value, numshadowmark, shadowmarklist)))
1958 Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1963 // we're done with castmesh now
1964 Mod_ShadowMesh_Free(castmesh);
1967 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1968 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1971 if (rtlight->static_meshchain_shadow)
1972 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1973 k += mesh->numtriangles;
1975 if (rtlight->static_meshchain_light)
1976 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1977 l += mesh->numtriangles;
1978 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles, %i light triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], k, l);
1981 void R_RTLight_Uncompile(rtlight_t *rtlight)
1983 if (rtlight->compiled)
1985 if (rtlight->static_meshchain_shadow)
1986 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1987 rtlight->static_meshchain_shadow = NULL;
1988 if (rtlight->static_meshchain_light)
1989 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1990 rtlight->static_meshchain_light = NULL;
1991 if (rtlight->static_clusterindices)
1992 Mem_Free(rtlight->static_clusterindices);
1993 rtlight->static_clusterindices = NULL;
1994 rtlight->static_numclusters = 0;
1995 rtlight->compiled = false;
1999 int shadowframecount = 0;
2001 void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t shadoworigin, vec_t shadowradius, vec3_t cullmins, vec3_t cullmaxs)
2004 if ((BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) || !r_shadow_cull.integer) && (ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume)
2006 vec3_t relativeshadoworigin;
2007 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativeshadoworigin);
2008 ent->model->DrawShadowVolume (ent, relativeshadoworigin, shadowradius);
2012 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
2014 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2017 entity_render_t *ent;
2019 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
2020 rtexture_t *cubemaptexture;
2021 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2023 if (d_lightstylevalue[rtlight->style] <= 0)
2025 if (rtlight->compiled)
2027 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2029 for (i = 0;i < rtlight->static_numclusters;i++)
2030 if (CHECKPVSBIT(r_pvsbits, rtlight->static_clusterindices[i]))
2032 if (i == rtlight->static_numclusters)
2035 else if (VIS_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2037 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2040 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2041 R_RTLight_Compile(rtlight);
2043 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2044 VectorScale(rtlight->color, f, lightcolor);
2046 if (rtlight->selected)
2048 f = 2 + sin(realtime * M_PI * 4.0);
2049 VectorScale(lightcolor, f, lightcolor);
2053 if (rtlight->cubemapname[0])
2054 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2056 cubemaptexture = NULL;
2058 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_worldshadows.integer : r_shadow_dlightshadows.integer);
2059 if (shadow && (gl_stencil || visiblevolumes))
2061 if (!visiblevolumes)
2062 R_Shadow_Stage_ShadowVolumes();
2063 ent = &cl_entities[0].render;
2064 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2066 R_Mesh_Matrix(&ent->matrix);
2067 if (r_shadow_showtris.integer)
2071 int depthenabled = qglIsEnabled(GL_DEPTH_TEST);
2072 int stencilenabled = qglIsEnabled(GL_STENCIL_TEST);
2073 qglDisable(GL_DEPTH_TEST);
2074 qglDisable(GL_STENCIL_TEST);
2075 //qglDisable(GL_CULL_FACE);
2076 GL_ColorMask(1,1,1,1);
2077 memset(&m, 0, sizeof(m));
2078 R_Mesh_State_Texture(&m);
2079 GL_ColorPointer(NULL);
2080 GL_Color(0,0.1,0,1);
2081 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2082 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2084 GL_VertexPointer(mesh->vertex3f);
2085 R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i);
2087 //qglEnable(GL_CULL_FACE);
2089 qglEnable(GL_DEPTH_TEST);
2092 qglEnable(GL_STENCIL_TEST);
2093 GL_ColorMask(0,0,0,0);
2096 R_Shadow_RenderShadowMeshVolume(rtlight->static_meshchain_shadow);
2099 R_TestAndDrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs);
2100 if (r_drawentities.integer)
2101 for (i = 0;i < r_refdef.numentities;i++)
2102 if (r_refdef.entities[i]->flags & RENDER_SHADOW)
2103 R_TestAndDrawShadowVolume(r_refdef.entities[i], rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs);
2106 if (!visiblevolumes)
2108 if (shadow && gl_stencil)
2109 R_Shadow_Stage_LightWithShadows();
2111 R_Shadow_Stage_LightWithoutShadows();
2113 ent = &cl_entities[0].render;
2114 if (ent->model && ent->model->DrawLight)
2116 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2117 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2118 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2119 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2120 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2121 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2123 //R_Shadow_DrawStaticWorldLight_Light(rtlight, &ent->matrix, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2125 R_Mesh_Matrix(&ent->matrix);
2126 if (r_shadow_showtris.integer)
2129 int depthenabled = qglIsEnabled(GL_DEPTH_TEST);
2130 int stencilenabled = qglIsEnabled(GL_STENCIL_TEST);
2131 qglDisable(GL_DEPTH_TEST);
2132 qglDisable(GL_STENCIL_TEST);
2133 //qglDisable(GL_CULL_FACE);
2134 memset(&m, 0, sizeof(m));
2135 R_Mesh_State_Texture(&m);
2136 GL_ColorPointer(NULL);
2137 GL_Color(0.2,0,0,1);
2138 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2139 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2141 GL_VertexPointer(mesh->vertex3f);
2142 R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i);
2144 //qglEnable(GL_CULL_FACE);
2146 qglEnable(GL_DEPTH_TEST);
2148 qglEnable(GL_STENCIL_TEST);
2150 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2152 R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, cubemaptexture);
2153 R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_specular, mesh->map_normal, cubemaptexture);
2157 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2159 if (r_drawentities.integer)
2161 for (i = 0;i < r_refdef.numentities;i++)
2163 ent = r_refdef.entities[i];
2164 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
2165 && BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2166 && (ent->flags & RENDER_LIGHT))
2168 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2169 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2170 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2171 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2172 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2173 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2180 void R_ShadowVolumeLighting(int visiblevolumes)
2188 memset(&m, 0, sizeof(m));
2189 R_Mesh_State_Texture(&m);
2191 GL_BlendFunc(GL_ONE, GL_ONE);
2192 GL_DepthMask(false);
2193 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2194 qglDisable(GL_CULL_FACE);
2195 GL_ColorPointer(NULL);
2196 GL_Color(0.0, 0.0125, 0.1, 1);
2199 R_Shadow_Stage_Begin();
2201 if (r_shadow_realtime_world.integer)
2203 R_Shadow_LoadWorldLightsIfNeeded();
2204 if (r_shadow_debuglight.integer >= 0)
2206 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2207 if (lnum == r_shadow_debuglight.integer)
2208 R_DrawRTLight(&light->rtlight, visiblevolumes);
2211 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2212 R_DrawRTLight(&light->rtlight, visiblevolumes);
2214 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2215 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2216 R_DrawRTLight(&light->rtlight, visiblevolumes);
2220 qglEnable(GL_CULL_FACE);
2221 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2224 R_Shadow_Stage_End();
2227 cvar_t r_editlights = {0, "r_editlights", "0"};
2228 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
2229 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
2230 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
2231 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
2232 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
2233 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
2234 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
2235 dlight_t *r_shadow_worldlightchain;
2236 dlight_t *r_shadow_selectedlight;
2237 vec3_t r_editlights_cursorlocation;
2239 typedef struct cubemapinfo_s
2242 rtexture_t *texture;
2246 #define MAX_CUBEMAPS 128
2247 static int numcubemaps;
2248 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
2250 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2251 typedef struct suffixinfo_s
2254 int flipx, flipy, flipdiagonal;
2257 static suffixinfo_t suffix[3][6] =
2260 {"posx", false, false, false},
2261 {"negx", false, false, false},
2262 {"posy", false, false, false},
2263 {"negy", false, false, false},
2264 {"posz", false, false, false},
2265 {"negz", false, false, false}
2268 {"px", false, false, false},
2269 {"nx", false, false, false},
2270 {"py", false, false, false},
2271 {"ny", false, false, false},
2272 {"pz", false, false, false},
2273 {"nz", false, false, false}
2276 {"ft", true, false, true},
2277 {"bk", false, true, true},
2278 {"lf", true, true, false},
2279 {"rt", false, false, false},
2280 {"up", false, false, false},
2281 {"dn", false, false, false}
2285 static int componentorder[4] = {0, 1, 2, 3};
2287 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2289 int i, j, cubemapsize;
2290 qbyte *cubemappixels, *image_rgba;
2291 rtexture_t *cubemaptexture;
2293 // must start 0 so the first loadimagepixels has no requested width/height
2295 cubemappixels = NULL;
2296 cubemaptexture = NULL;
2297 for (j = 0;j < 3 && !cubemappixels;j++)
2299 for (i = 0;i < 6;i++)
2301 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2302 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2304 if (image_width == image_height)
2306 if (!cubemappixels && image_width >= 1)
2308 cubemapsize = image_width;
2309 // note this clears to black, so unavailable sizes are black
2310 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2313 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);
2316 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2317 Mem_Free(image_rgba);
2323 if (!r_shadow_filters_texturepool)
2324 r_shadow_filters_texturepool = R_AllocTexturePool();
2325 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2326 Mem_Free(cubemappixels);
2330 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2331 for (j = 0;j < 3;j++)
2332 for (i = 0;i < 6;i++)
2333 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2334 Con_Print(" and was unable to find any of them.\n");
2336 return cubemaptexture;
2339 rtexture_t *R_Shadow_Cubemap(const char *basename)
2342 for (i = 0;i < numcubemaps;i++)
2343 if (!strcasecmp(cubemaps[i].basename, basename))
2344 return cubemaps[i].texture;
2345 if (i >= MAX_CUBEMAPS)
2348 strcpy(cubemaps[i].basename, basename);
2349 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2350 return cubemaps[i].texture;
2353 void R_Shadow_FreeCubemaps(void)
2356 R_FreeTexturePool(&r_shadow_filters_texturepool);
2359 void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname)
2363 if (radius < 15 || DotProduct(color, color) < 0.03)
2365 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2369 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2370 VectorCopy(origin, light->origin);
2371 VectorCopy(angles, light->angles);
2372 VectorCopy(color, light->color);
2373 light->radius = radius;
2374 light->style = style;
2375 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2377 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2380 light->shadow = shadowenable;
2381 light->corona = corona;
2382 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2383 strcpy(light->cubemapname, cubemapname);
2384 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2385 light->next = r_shadow_worldlightchain;
2386 r_shadow_worldlightchain = light;
2388 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2389 if (r_shadow_staticworldlights.integer)
2390 R_RTLight_Compile(&light->rtlight);
2393 void R_Shadow_FreeWorldLight(dlight_t *light)
2395 dlight_t **lightpointer;
2396 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2397 if (*lightpointer != light)
2398 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2399 *lightpointer = light->next;
2400 R_RTLight_Uncompile(&light->rtlight);
2404 void R_Shadow_ClearWorldLights(void)
2406 while (r_shadow_worldlightchain)
2407 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2408 r_shadow_selectedlight = NULL;
2409 R_Shadow_FreeCubemaps();
2412 void R_Shadow_SelectLight(dlight_t *light)
2414 if (r_shadow_selectedlight)
2415 r_shadow_selectedlight->selected = false;
2416 r_shadow_selectedlight = light;
2417 if (r_shadow_selectedlight)
2418 r_shadow_selectedlight->selected = true;
2421 rtexture_t *lighttextures[5];
2423 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2425 float scale = r_editlights_cursorgrid.value * 0.5f;
2426 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);
2429 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2432 const dlight_t *light;
2435 if (light->selected)
2436 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2439 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);
2442 void R_Shadow_DrawLightSprites(void)
2448 for (i = 0;i < 5;i++)
2450 lighttextures[i] = NULL;
2451 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2452 lighttextures[i] = pic->tex;
2455 for (light = r_shadow_worldlightchain;light;light = light->next)
2456 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2457 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2460 void R_Shadow_SelectLightInView(void)
2462 float bestrating, rating, temp[3];
2463 dlight_t *best, *light;
2466 for (light = r_shadow_worldlightchain;light;light = light->next)
2468 VectorSubtract(light->origin, r_vieworigin, temp);
2469 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2472 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2473 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2475 bestrating = rating;
2480 R_Shadow_SelectLight(best);
2483 void R_Shadow_LoadWorldLights(void)
2485 int n, a, style, shadow;
2486 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2487 float origin[3], radius, color[3], angles[3], corona;
2488 if (cl.worldmodel == NULL)
2490 Con_Print("No map loaded.\n");
2493 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2494 strlcat (name, ".rtlights", sizeof (name));
2495 lightsstring = FS_LoadFile(name, false);
2505 for (;COM_Parse(t, true) && strcmp(
2506 if (COM_Parse(t, true))
2508 if (com_token[0] == '!')
2511 origin[0] = atof(com_token+1);
2514 origin[0] = atof(com_token);
2519 while (*s && *s != '\n')
2525 // check for modifier flags
2531 a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2]);
2533 VectorClear(angles);
2536 if (a < 9 || !strcmp(cubemapname, "\"\""))
2541 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])\n", a, n + 1);
2544 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2545 radius *= r_editlights_rtlightssizescale.value;
2546 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2551 Con_Printf("invalid rtlights file \"%s\"\n", name);
2552 Mem_Free(lightsstring);
2556 void R_Shadow_SaveWorldLights(void)
2559 int bufchars, bufmaxchars;
2561 char name[MAX_QPATH];
2563 if (!r_shadow_worldlightchain)
2565 if (cl.worldmodel == NULL)
2567 Con_Print("No map loaded.\n");
2570 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2571 strlcat (name, ".rtlights", sizeof (name));
2572 bufchars = bufmaxchars = 0;
2574 for (light = r_shadow_worldlightchain;light;light = light->next)
2576 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[0] ? light->cubemapname : "\"\"", light->corona, light->angles[0], light->angles[1], light->angles[2]);
2577 if (bufchars + (int) strlen(line) > bufmaxchars)
2579 bufmaxchars = bufchars + strlen(line) + 2048;
2581 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2585 memcpy(buf, oldbuf, bufchars);
2591 memcpy(buf + bufchars, line, strlen(line));
2592 bufchars += strlen(line);
2596 FS_WriteFile(name, buf, bufchars);
2601 void R_Shadow_LoadLightsFile(void)
2604 char name[MAX_QPATH], *lightsstring, *s, *t;
2605 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2606 if (cl.worldmodel == NULL)
2608 Con_Print("No map loaded.\n");
2611 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2612 strlcat (name, ".lights", sizeof (name));
2613 lightsstring = FS_LoadFile(name, false);
2621 while (*s && *s != '\n')
2626 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);
2630 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);
2633 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2634 radius = bound(15, radius, 4096);
2635 VectorScale(color, (2.0f / (8388608.0f)), color);
2636 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2641 Con_Printf("invalid lights file \"%s\"\n", name);
2642 Mem_Free(lightsstring);
2646 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2648 int entnum, style, islight, skin, pflags, effects;
2649 char key[256], value[1024];
2650 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2653 if (cl.worldmodel == NULL)
2655 Con_Print("No map loaded.\n");
2658 data = cl.worldmodel->brush.entities;
2661 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2664 origin[0] = origin[1] = origin[2] = 0;
2665 originhack[0] = originhack[1] = originhack[2] = 0;
2666 angles[0] = angles[1] = angles[2] = 0;
2667 color[0] = color[1] = color[2] = 1;
2668 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2678 if (!COM_ParseToken(&data, false))
2680 if (com_token[0] == '}')
2681 break; // end of entity
2682 if (com_token[0] == '_')
2683 strcpy(key, com_token + 1);
2685 strcpy(key, com_token);
2686 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2687 key[strlen(key)-1] = 0;
2688 if (!COM_ParseToken(&data, false))
2690 strcpy(value, com_token);
2692 // now that we have the key pair worked out...
2693 if (!strcmp("light", key))
2694 light = atof(value);
2695 else if (!strcmp("origin", key))
2696 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2697 else if (!strcmp("angle", key))
2698 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2699 else if (!strcmp("angles", key))
2700 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2701 else if (!strcmp("color", key))
2702 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2703 else if (!strcmp("wait", key))
2704 fadescale = atof(value);
2705 else if (!strcmp("classname", key))
2707 if (!strncmp(value, "light", 5))
2710 if (!strcmp(value, "light_fluoro"))
2715 overridecolor[0] = 1;
2716 overridecolor[1] = 1;
2717 overridecolor[2] = 1;
2719 if (!strcmp(value, "light_fluorospark"))
2724 overridecolor[0] = 1;
2725 overridecolor[1] = 1;
2726 overridecolor[2] = 1;
2728 if (!strcmp(value, "light_globe"))
2733 overridecolor[0] = 1;
2734 overridecolor[1] = 0.8;
2735 overridecolor[2] = 0.4;
2737 if (!strcmp(value, "light_flame_large_yellow"))
2742 overridecolor[0] = 1;
2743 overridecolor[1] = 0.5;
2744 overridecolor[2] = 0.1;
2746 if (!strcmp(value, "light_flame_small_yellow"))
2751 overridecolor[0] = 1;
2752 overridecolor[1] = 0.5;
2753 overridecolor[2] = 0.1;
2755 if (!strcmp(value, "light_torch_small_white"))
2760 overridecolor[0] = 1;
2761 overridecolor[1] = 0.5;
2762 overridecolor[2] = 0.1;
2764 if (!strcmp(value, "light_torch_small_walltorch"))
2769 overridecolor[0] = 1;
2770 overridecolor[1] = 0.5;
2771 overridecolor[2] = 0.1;
2775 else if (!strcmp("style", key))
2776 style = atoi(value);
2777 else if (cl.worldmodel->type == mod_brushq3)
2779 if (!strcmp("scale", key))
2780 lightscale = atof(value);
2781 if (!strcmp("fade", key))
2782 fadescale = atof(value);
2784 else if (!strcmp("skin", key))
2785 skin = (int)atof(value);
2786 else if (!strcmp("pflags", key))
2787 pflags = (int)atof(value);
2788 else if (!strcmp("effects", key))
2789 effects = (int)atof(value);
2791 if (light <= 0 && islight)
2793 if (lightscale <= 0)
2797 if (gamemode == GAME_TENEBRAE)
2799 if (effects & EF_NODRAW)
2801 pflags |= PFLAGS_FULLDYNAMIC;
2802 effects &= ~EF_NODRAW;
2805 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2806 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2807 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2808 VectorCopy(overridecolor, color);
2809 VectorScale(color, light, color);
2810 VectorAdd(origin, originhack, origin);
2811 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2812 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2817 void R_Shadow_SetCursorLocationForView(void)
2819 vec_t dist, push, frac;
2820 vec3_t dest, endpos, normal;
2821 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2822 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2825 dist = frac * r_editlights_cursordistance.value;
2826 push = r_editlights_cursorpushback.value;
2830 VectorMA(endpos, push, r_viewforward, endpos);
2831 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2833 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2834 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2835 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2838 void R_Shadow_UpdateWorldLightSelection(void)
2840 if (r_editlights.integer)
2842 R_Shadow_SetCursorLocationForView();
2843 R_Shadow_SelectLightInView();
2844 R_Shadow_DrawLightSprites();
2847 R_Shadow_SelectLight(NULL);
2850 void R_Shadow_EditLights_Clear_f(void)
2852 R_Shadow_ClearWorldLights();
2855 void R_Shadow_EditLights_Reload_f(void)
2857 r_shadow_reloadlights = true;
2860 void R_Shadow_EditLights_Save_f(void)
2863 R_Shadow_SaveWorldLights();
2866 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2868 R_Shadow_ClearWorldLights();
2869 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2872 void R_Shadow_EditLights_ImportLightsFile_f(void)
2874 R_Shadow_ClearWorldLights();
2875 R_Shadow_LoadLightsFile();
2878 void R_Shadow_EditLights_Spawn_f(void)
2881 if (!r_editlights.integer)
2883 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2886 if (Cmd_Argc() != 1)
2888 Con_Print("r_editlights_spawn does not take parameters\n");
2891 color[0] = color[1] = color[2] = 1;
2892 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2895 void R_Shadow_EditLights_Edit_f(void)
2897 vec3_t origin, angles, color;
2898 vec_t radius, corona;
2900 char cubemapname[1024];
2901 if (!r_editlights.integer)
2903 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2906 if (!r_shadow_selectedlight)
2908 Con_Print("No selected light.\n");
2911 VectorCopy(r_shadow_selectedlight->origin, origin);
2912 VectorCopy(r_shadow_selectedlight->angles, angles);
2913 VectorCopy(r_shadow_selectedlight->color, color);
2914 radius = r_shadow_selectedlight->radius;
2915 style = r_shadow_selectedlight->style;
2916 if (r_shadow_selectedlight->cubemapname)
2917 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2920 shadows = r_shadow_selectedlight->shadow;
2921 corona = r_shadow_selectedlight->corona;
2922 if (!strcmp(Cmd_Argv(1), "origin"))
2924 if (Cmd_Argc() != 5)
2926 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2929 origin[0] = atof(Cmd_Argv(2));
2930 origin[1] = atof(Cmd_Argv(3));
2931 origin[2] = atof(Cmd_Argv(4));
2933 else if (!strcmp(Cmd_Argv(1), "originx"))
2935 if (Cmd_Argc() != 3)
2937 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2940 origin[0] = atof(Cmd_Argv(2));
2942 else if (!strcmp(Cmd_Argv(1), "originy"))
2944 if (Cmd_Argc() != 3)
2946 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2949 origin[1] = atof(Cmd_Argv(2));
2951 else if (!strcmp(Cmd_Argv(1), "originz"))
2953 if (Cmd_Argc() != 3)
2955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2958 origin[2] = atof(Cmd_Argv(2));
2960 else if (!strcmp(Cmd_Argv(1), "move"))
2962 if (Cmd_Argc() != 5)
2964 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2967 origin[0] += atof(Cmd_Argv(2));
2968 origin[1] += atof(Cmd_Argv(3));
2969 origin[2] += atof(Cmd_Argv(4));
2971 else if (!strcmp(Cmd_Argv(1), "movex"))
2973 if (Cmd_Argc() != 3)
2975 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2978 origin[0] += atof(Cmd_Argv(2));
2980 else if (!strcmp(Cmd_Argv(1), "movey"))
2982 if (Cmd_Argc() != 3)
2984 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2987 origin[1] += atof(Cmd_Argv(2));
2989 else if (!strcmp(Cmd_Argv(1), "movez"))
2991 if (Cmd_Argc() != 3)
2993 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2996 origin[2] += atof(Cmd_Argv(2));
2998 else if (!strcmp(Cmd_Argv(1), "angles"))
3000 if (Cmd_Argc() != 5)
3002 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3005 angles[0] = atof(Cmd_Argv(2));
3006 angles[1] = atof(Cmd_Argv(3));
3007 angles[2] = atof(Cmd_Argv(4));
3009 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3011 if (Cmd_Argc() != 3)
3013 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3016 angles[0] = atof(Cmd_Argv(2));
3018 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3020 if (Cmd_Argc() != 3)
3022 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3025 angles[1] = atof(Cmd_Argv(2));
3027 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3029 if (Cmd_Argc() != 3)
3031 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3034 angles[2] = atof(Cmd_Argv(2));
3036 else if (!strcmp(Cmd_Argv(1), "color"))
3038 if (Cmd_Argc() != 5)
3040 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3043 color[0] = atof(Cmd_Argv(2));
3044 color[1] = atof(Cmd_Argv(3));
3045 color[2] = atof(Cmd_Argv(4));
3047 else if (!strcmp(Cmd_Argv(1), "radius"))
3049 if (Cmd_Argc() != 3)
3051 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3054 radius = atof(Cmd_Argv(2));
3056 else if (!strcmp(Cmd_Argv(1), "style"))
3058 if (Cmd_Argc() != 3)
3060 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3063 style = atoi(Cmd_Argv(2));
3065 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3069 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3072 if (Cmd_Argc() == 3)
3073 strcpy(cubemapname, Cmd_Argv(2));
3077 else if (!strcmp(Cmd_Argv(1), "shadows"))
3079 if (Cmd_Argc() != 3)
3081 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3084 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3086 else if (!strcmp(Cmd_Argv(1), "corona"))
3088 if (Cmd_Argc() != 3)
3090 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3093 corona = atof(Cmd_Argv(2));
3097 Con_Print("usage: r_editlights_edit [property] [value]\n");
3098 Con_Print("Selected light's properties:\n");
3099 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3100 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3101 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3102 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3103 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3104 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3105 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3106 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3109 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3110 r_shadow_selectedlight = NULL;
3111 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3114 extern int con_vislines;
3115 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3119 if (r_shadow_selectedlight == NULL)
3123 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3124 sprintf(temp, "Origin %f %f %f", 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;
3125 sprintf(temp, "Angles %f %f %f", 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;
3126 sprintf(temp, "Color %f %f %f", 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;
3127 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3128 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3129 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3130 sprintf(temp, "Shadows %s", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3131 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3134 void R_Shadow_EditLights_ToggleShadow_f(void)
3136 if (!r_editlights.integer)
3138 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3141 if (!r_shadow_selectedlight)
3143 Con_Print("No selected light.\n");
3146 R_Shadow_NewWorldLight(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);
3147 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3148 r_shadow_selectedlight = NULL;
3151 void R_Shadow_EditLights_ToggleCorona_f(void)
3153 if (!r_editlights.integer)
3155 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3158 if (!r_shadow_selectedlight)
3160 Con_Print("No selected light.\n");
3163 R_Shadow_NewWorldLight(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);
3164 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3165 r_shadow_selectedlight = NULL;
3168 void R_Shadow_EditLights_Remove_f(void)
3170 if (!r_editlights.integer)
3172 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3175 if (!r_shadow_selectedlight)
3177 Con_Print("No selected light.\n");
3180 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3181 r_shadow_selectedlight = NULL;
3184 void R_Shadow_EditLights_Help_f(void)
3187 "Documentation on r_editlights system:\n"
3189 "r_editlights : enable/disable editing mode\n"
3190 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3191 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3192 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3193 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3194 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3195 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3196 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3198 "r_editlights_help : this help\n"
3199 "r_editlights_clear : remove all lights\n"
3200 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3201 "r_editlights_save : save to .rtlights file\n"
3202 "r_editlights_spawn : create a light with default settings\n"
3203 "r_editlights_edit command : edit selected light - more documentation below\n"
3204 "r_editlights_remove : remove selected light\n"
3205 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3206 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3207 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3209 "origin x y z : set light location\n"
3210 "originx x: set x component of light location\n"
3211 "originy y: set y component of light location\n"
3212 "originz z: set z component of light location\n"
3213 "move x y z : adjust light location\n"
3214 "movex x: adjust x component of light location\n"
3215 "movey y: adjust y component of light location\n"
3216 "movez z: adjust z component of light location\n"
3217 "angles x y z : set light angles\n"
3218 "anglesx x: set x component of light angles\n"
3219 "anglesy y: set y component of light angles\n"
3220 "anglesz z: set z component of light angles\n"
3221 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3222 "radius radius : set radius (size) of light\n"
3223 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3224 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3225 "shadows 1/0 : turn on/off shadows\n"
3226 "corona n : set corona intensity\n"
3227 "<nothing> : print light properties to console\n"
3231 void R_Shadow_EditLights_Init(void)
3233 Cvar_RegisterVariable(&r_editlights);
3234 Cvar_RegisterVariable(&r_editlights_cursordistance);
3235 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3236 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3237 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3238 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3239 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3240 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3241 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3242 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3243 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3244 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3245 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3246 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3247 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3248 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3249 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3250 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3251 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);