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_Color(0, 0, 0, 1);
739 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
740 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
741 r_shadowstage = SHADOWSTAGE_NONE;
743 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
744 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
745 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
748 void R_Shadow_LoadWorldLightsIfNeeded(void)
750 if (r_shadow_reloadlights && cl.worldmodel)
752 R_Shadow_ClearWorldLights();
753 r_shadow_reloadlights = false;
754 R_Shadow_LoadWorldLights();
755 if (r_shadow_worldlightchain == NULL)
757 R_Shadow_LoadLightsFile();
758 if (r_shadow_worldlightchain == NULL)
759 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
764 void R_Shadow_Stage_ShadowVolumes(void)
767 memset(&m, 0, sizeof(m));
768 R_Mesh_State_Texture(&m);
769 GL_Color(1, 1, 1, 1);
770 GL_ColorMask(0, 0, 0, 0);
771 GL_BlendFunc(GL_ONE, GL_ZERO);
774 qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
775 //if (r_shadow_polygonoffset.value != 0)
777 // qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
778 // qglEnable(GL_POLYGON_OFFSET_FILL);
781 // qglDisable(GL_POLYGON_OFFSET_FILL);
782 qglDepthFunc(GL_LESS);
783 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
784 qglEnable(GL_STENCIL_TEST);
785 qglStencilFunc(GL_ALWAYS, 128, ~0);
786 if (gl_ext_stenciltwoside.integer)
788 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
789 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
790 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
792 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
793 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
795 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
799 r_shadowstage = SHADOWSTAGE_STENCIL;
801 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
803 GL_Clear(GL_STENCIL_BUFFER_BIT);
805 // LordHavoc note: many shadow volumes reside entirely inside the world
806 // (that is to say they are entirely bounded by their lit surfaces),
807 // which can be optimized by handling things as an inverted light volume,
808 // with the shadow boundaries of the world being simulated by an altered
809 // (129) bias to stencil clearing on such lights
810 // FIXME: generate inverted light volumes for use as shadow volumes and
811 // optimize for them as noted above
814 void R_Shadow_Stage_LightWithoutShadows(void)
817 memset(&m, 0, sizeof(m));
818 R_Mesh_State_Texture(&m);
819 GL_BlendFunc(GL_ONE, GL_ONE);
822 qglPolygonOffset(0, 0);
823 //qglDisable(GL_POLYGON_OFFSET_FILL);
824 GL_Color(1, 1, 1, 1);
825 GL_ColorMask(1, 1, 1, 1);
826 qglDepthFunc(GL_EQUAL);
827 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
828 qglDisable(GL_STENCIL_TEST);
829 if (gl_support_stenciltwoside)
830 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
832 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
833 qglStencilFunc(GL_EQUAL, 128, 0xFF);
834 r_shadowstage = SHADOWSTAGE_LIGHT;
838 void R_Shadow_Stage_LightWithShadows(void)
841 memset(&m, 0, sizeof(m));
842 R_Mesh_State_Texture(&m);
843 GL_BlendFunc(GL_ONE, GL_ONE);
846 qglPolygonOffset(0, 0);
847 //qglDisable(GL_POLYGON_OFFSET_FILL);
848 GL_Color(1, 1, 1, 1);
849 GL_ColorMask(1, 1, 1, 1);
850 qglDepthFunc(GL_EQUAL);
851 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
852 qglEnable(GL_STENCIL_TEST);
853 if (gl_support_stenciltwoside)
854 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
856 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
857 // only draw light where this geometry was already rendered AND the
858 // stencil is 128 (values other than this mean shadow)
859 qglStencilFunc(GL_EQUAL, 128, 0xFF);
860 r_shadowstage = SHADOWSTAGE_LIGHT;
864 void R_Shadow_Stage_End(void)
867 memset(&m, 0, sizeof(m));
868 R_Mesh_State_Texture(&m);
869 GL_BlendFunc(GL_ONE, GL_ZERO);
872 qglPolygonOffset(0, 0);
873 //qglDisable(GL_POLYGON_OFFSET_FILL);
874 GL_Color(1, 1, 1, 1);
875 GL_ColorMask(1, 1, 1, 1);
876 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
877 qglDepthFunc(GL_LEQUAL);
878 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
879 qglDisable(GL_STENCIL_TEST);
880 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
881 if (gl_support_stenciltwoside)
882 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
884 qglStencilFunc(GL_ALWAYS, 128, 0xFF);
885 r_shadowstage = SHADOWSTAGE_NONE;
888 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
890 int i, ix1, iy1, ix2, iy2;
891 float x1, y1, x2, y2, x, y, f;
894 if (!r_shadow_scissor.integer)
896 // if view is inside the box, just say yes it's visible
897 // LordHavoc: for some odd reason scissor seems broken without stencil
898 // (?!? seems like a driver bug) so abort if gl_stencil is false
899 if (!gl_stencil || BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
901 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
904 for (i = 0;i < 3;i++)
906 if (r_viewforward[i] >= 0)
917 f = DotProduct(r_viewforward, r_vieworigin) + 1;
918 if (DotProduct(r_viewforward, v2) <= f)
920 // entirely behind nearclip plane
923 if (DotProduct(r_viewforward, v) >= f)
925 // entirely infront of nearclip plane
926 x1 = y1 = x2 = y2 = 0;
927 for (i = 0;i < 8;i++)
929 v[0] = (i & 1) ? mins[0] : maxs[0];
930 v[1] = (i & 2) ? mins[1] : maxs[1];
931 v[2] = (i & 4) ? mins[2] : maxs[2];
933 GL_TransformToScreen(v, v2);
934 //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]);
953 // clipped by nearclip plane
954 // this is nasty and crude...
955 // create viewspace bbox
956 for (i = 0;i < 8;i++)
958 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
959 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
960 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
961 v2[0] = -DotProduct(v, r_viewleft);
962 v2[1] = DotProduct(v, r_viewup);
963 v2[2] = DotProduct(v, r_viewforward);
966 if (smins[0] > v2[0]) smins[0] = v2[0];
967 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
968 if (smins[1] > v2[1]) smins[1] = v2[1];
969 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
970 if (smins[2] > v2[2]) smins[2] = v2[2];
971 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
975 smins[0] = smaxs[0] = v2[0];
976 smins[1] = smaxs[1] = v2[1];
977 smins[2] = smaxs[2] = v2[2];
980 // now we have a bbox in viewspace
981 // clip it to the view plane
984 // return true if that culled the box
985 if (smins[2] >= smaxs[2])
987 // ok some of it is infront of the view, transform each corner back to
988 // worldspace and then to screenspace and make screen rect
989 // initialize these variables just to avoid compiler warnings
990 x1 = y1 = x2 = y2 = 0;
991 for (i = 0;i < 8;i++)
993 v2[0] = (i & 1) ? smins[0] : smaxs[0];
994 v2[1] = (i & 2) ? smins[1] : smaxs[1];
995 v2[2] = (i & 4) ? smins[2] : smaxs[2];
996 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
997 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
998 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1000 GL_TransformToScreen(v, v2);
1001 //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]);
1018 // this code doesn't handle boxes with any points behind view properly
1019 x1 = 1000;x2 = -1000;
1020 y1 = 1000;y2 = -1000;
1021 for (i = 0;i < 8;i++)
1023 v[0] = (i & 1) ? mins[0] : maxs[0];
1024 v[1] = (i & 2) ? mins[1] : maxs[1];
1025 v[2] = (i & 4) ? mins[2] : maxs[2];
1027 GL_TransformToScreen(v, v2);
1028 //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]);
1046 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1047 if (ix1 < r_view_x) ix1 = r_view_x;
1048 if (iy1 < r_view_y) iy1 = r_view_y;
1049 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1050 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1051 if (ix2 <= ix1 || iy2 <= iy1)
1053 // set up the scissor rectangle
1054 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1055 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1056 //qglEnable(GL_SCISSOR_TEST);
1061 void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1063 float *color4f = varray_color4f;
1064 float dist, dot, intensity, v[3], n[3];
1065 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1067 Matrix4x4_Transform(m, vertex3f, v);
1068 if ((dist = DotProduct(v, v)) < 1)
1070 Matrix4x4_Transform3x3(m, normal3f, n);
1071 if ((dot = DotProduct(n, v)) > 0)
1074 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1075 VectorScale(lightcolor, intensity, color4f);
1080 VectorClear(color4f);
1086 VectorClear(color4f);
1092 void R_Shadow_VertexLightingWithXYAttenuationTexture(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1094 float *color4f = varray_color4f;
1095 float dist, dot, intensity, v[3], n[3];
1096 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1098 Matrix4x4_Transform(m, vertex3f, v);
1099 if ((dist = fabs(v[2])) < 1)
1101 Matrix4x4_Transform3x3(m, normal3f, n);
1102 if ((dot = DotProduct(n, v)) > 0)
1104 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1105 VectorScale(lightcolor, intensity, color4f);
1110 VectorClear(color4f);
1116 VectorClear(color4f);
1122 // FIXME: this should be done in a vertex program when possible
1123 // FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
1124 void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1128 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1129 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1130 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1137 void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1141 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1142 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1149 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)
1153 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1155 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1156 // the cubemap normalizes this for us
1157 out3f[0] = DotProduct(svector3f, lightdir);
1158 out3f[1] = DotProduct(tvector3f, lightdir);
1159 out3f[2] = DotProduct(normal3f, lightdir);
1163 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)
1166 float lightdir[3], eyedir[3], halfdir[3];
1167 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1169 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1170 VectorNormalizeFast(lightdir);
1171 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1172 VectorNormalizeFast(eyedir);
1173 VectorAdd(lightdir, eyedir, halfdir);
1174 // the cubemap normalizes this for us
1175 out3f[0] = DotProduct(svector3f, halfdir);
1176 out3f[1] = DotProduct(tvector3f, halfdir);
1177 out3f[2] = DotProduct(normal3f, halfdir);
1181 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)
1184 float color[3], color2[3];
1186 GL_VertexPointer(vertex3f);
1187 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1190 bumptexture = r_shadow_blankbumptexture;
1192 // colorscale accounts for how much we multiply the brightness during combine
1193 // mult is how many times the final pass of the lighting will be
1194 // performed to get more brightness than otherwise possible
1195 // limit mult to 64 for sanity sake
1196 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1198 // 3/2 3D combine path (Geforce3, Radeon 8500)
1199 memset(&m, 0, sizeof(m));
1200 m.tex[0] = R_GetTexture(bumptexture);
1201 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1202 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1203 m.texcombinergb[0] = GL_REPLACE;
1204 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1205 m.pointer_texcoord[0] = texcoord2f;
1206 m.pointer_texcoord[1] = varray_texcoord3f[1];
1207 m.pointer_texcoord[2] = varray_texcoord3f[2];
1208 R_Mesh_State_Texture(&m);
1209 GL_ColorMask(0,0,0,1);
1210 GL_BlendFunc(GL_ONE, GL_ZERO);
1211 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1212 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1213 R_Mesh_Draw(numverts, numtriangles, elements);
1215 c_rt_lighttris += numtriangles;
1217 memset(&m, 0, sizeof(m));
1218 m.tex[0] = R_GetTexture(basetexture);
1219 m.pointer_texcoord[0] = texcoord2f;
1222 m.texcubemap[1] = R_GetTexture(lightcubemap);
1223 m.pointer_texcoord[1] = varray_texcoord3f[1];
1224 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1226 R_Mesh_State_Texture(&m);
1227 GL_ColorMask(1,1,1,0);
1228 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1229 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1230 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1232 color[0] = bound(0, color2[0], 1);
1233 color[1] = bound(0, color2[1], 1);
1234 color[2] = bound(0, color2[2], 1);
1235 GL_Color(color[0], color[1], color[2], 1);
1236 R_Mesh_Draw(numverts, numtriangles, elements);
1238 c_rt_lighttris += numtriangles;
1241 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1243 // 1/2/2 3D combine path (original Radeon)
1244 memset(&m, 0, sizeof(m));
1245 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1246 m.pointer_texcoord[0] = varray_texcoord3f[0];
1247 R_Mesh_State_Texture(&m);
1248 GL_ColorMask(0,0,0,1);
1249 GL_BlendFunc(GL_ONE, GL_ZERO);
1250 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1251 R_Mesh_Draw(numverts, numtriangles, elements);
1253 c_rt_lighttris += numtriangles;
1255 memset(&m, 0, sizeof(m));
1256 m.tex[0] = R_GetTexture(bumptexture);
1257 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1258 m.texcombinergb[0] = GL_REPLACE;
1259 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1260 m.pointer_texcoord[0] = texcoord2f;
1261 m.pointer_texcoord[1] = varray_texcoord3f[1];
1262 R_Mesh_State_Texture(&m);
1263 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1264 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1265 R_Mesh_Draw(numverts, numtriangles, elements);
1267 c_rt_lighttris += numtriangles;
1269 memset(&m, 0, sizeof(m));
1270 m.tex[0] = R_GetTexture(basetexture);
1271 m.pointer_texcoord[0] = texcoord2f;
1274 m.texcubemap[1] = R_GetTexture(lightcubemap);
1275 m.pointer_texcoord[1] = varray_texcoord3f[1];
1276 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1278 R_Mesh_State_Texture(&m);
1279 GL_ColorMask(1,1,1,0);
1280 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1281 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1282 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1284 color[0] = bound(0, color2[0], 1);
1285 color[1] = bound(0, color2[1], 1);
1286 color[2] = bound(0, color2[2], 1);
1287 GL_Color(color[0], color[1], color[2], 1);
1288 R_Mesh_Draw(numverts, numtriangles, elements);
1290 c_rt_lighttris += numtriangles;
1293 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1295 // 2/2 3D combine path (original Radeon)
1296 memset(&m, 0, sizeof(m));
1297 m.tex[0] = R_GetTexture(bumptexture);
1298 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1299 m.texcombinergb[0] = GL_REPLACE;
1300 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1301 m.pointer_texcoord[0] = texcoord2f;
1302 m.pointer_texcoord[1] = varray_texcoord3f[1];
1303 R_Mesh_State_Texture(&m);
1304 GL_ColorMask(0,0,0,1);
1305 GL_BlendFunc(GL_ONE, GL_ZERO);
1306 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1307 R_Mesh_Draw(numverts, numtriangles, elements);
1309 c_rt_lighttris += numtriangles;
1311 memset(&m, 0, sizeof(m));
1312 m.tex[0] = R_GetTexture(basetexture);
1313 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1314 m.pointer_texcoord[0] = texcoord2f;
1315 m.pointer_texcoord[1] = varray_texcoord3f[1];
1316 R_Mesh_State_Texture(&m);
1317 GL_ColorMask(1,1,1,0);
1318 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1319 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1320 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1321 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1323 color[0] = bound(0, color2[0], 1);
1324 color[1] = bound(0, color2[1], 1);
1325 color[2] = bound(0, color2[2], 1);
1326 GL_Color(color[0], color[1], color[2], 1);
1327 R_Mesh_Draw(numverts, numtriangles, elements);
1329 c_rt_lighttris += numtriangles;
1332 else if (r_textureunits.integer >= 4)
1334 // 4/2 2D combine path (Geforce3, Radeon 8500)
1335 memset(&m, 0, sizeof(m));
1336 m.tex[0] = R_GetTexture(bumptexture);
1337 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1338 m.texcombinergb[0] = GL_REPLACE;
1339 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1340 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1341 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1342 m.pointer_texcoord[0] = texcoord2f;
1343 m.pointer_texcoord[1] = varray_texcoord3f[1];
1344 m.pointer_texcoord[2] = varray_texcoord2f[2];
1345 m.pointer_texcoord[3] = varray_texcoord2f[3];
1346 R_Mesh_State_Texture(&m);
1347 GL_ColorMask(0,0,0,1);
1348 GL_BlendFunc(GL_ONE, GL_ZERO);
1349 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1350 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1351 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1352 R_Mesh_Draw(numverts, numtriangles, elements);
1354 c_rt_lighttris += numtriangles;
1356 memset(&m, 0, sizeof(m));
1357 m.tex[0] = R_GetTexture(basetexture);
1358 m.pointer_texcoord[0] = texcoord2f;
1361 m.texcubemap[1] = R_GetTexture(lightcubemap);
1362 m.pointer_texcoord[1] = varray_texcoord3f[1];
1363 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1365 R_Mesh_State_Texture(&m);
1366 GL_ColorMask(1,1,1,0);
1367 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1368 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1369 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1371 color[0] = bound(0, color2[0], 1);
1372 color[1] = bound(0, color2[1], 1);
1373 color[2] = bound(0, color2[2], 1);
1374 GL_Color(color[0], color[1], color[2], 1);
1375 R_Mesh_Draw(numverts, numtriangles, elements);
1377 c_rt_lighttris += numtriangles;
1382 // 2/2/2 2D combine path (any dot3 card)
1383 memset(&m, 0, sizeof(m));
1384 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1385 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1386 m.pointer_texcoord[0] = varray_texcoord2f[0];
1387 m.pointer_texcoord[1] = varray_texcoord2f[1];
1388 R_Mesh_State_Texture(&m);
1389 GL_ColorMask(0,0,0,1);
1390 GL_BlendFunc(GL_ONE, GL_ZERO);
1391 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1392 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1393 R_Mesh_Draw(numverts, numtriangles, elements);
1395 c_rt_lighttris += numtriangles;
1397 memset(&m, 0, sizeof(m));
1398 m.tex[0] = R_GetTexture(bumptexture);
1399 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1400 m.texcombinergb[0] = GL_REPLACE;
1401 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1402 m.pointer_texcoord[0] = texcoord2f;
1403 m.pointer_texcoord[1] = varray_texcoord3f[1];
1404 R_Mesh_State_Texture(&m);
1405 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1406 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1407 R_Mesh_Draw(numverts, numtriangles, elements);
1409 c_rt_lighttris += numtriangles;
1411 memset(&m, 0, sizeof(m));
1412 m.tex[0] = R_GetTexture(basetexture);
1413 m.pointer_texcoord[0] = texcoord2f;
1416 m.texcubemap[1] = R_GetTexture(lightcubemap);
1417 m.pointer_texcoord[1] = varray_texcoord3f[1];
1418 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1420 R_Mesh_State_Texture(&m);
1421 GL_ColorMask(1,1,1,0);
1422 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1423 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1424 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1426 color[0] = bound(0, color2[0], 1);
1427 color[1] = bound(0, color2[1], 1);
1428 color[2] = bound(0, color2[2], 1);
1429 GL_Color(color[0], color[1], color[2], 1);
1430 R_Mesh_Draw(numverts, numtriangles, elements);
1432 c_rt_lighttris += numtriangles;
1438 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1439 GL_DepthMask(false);
1441 GL_ColorPointer(varray_color4f);
1442 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1443 memset(&m, 0, sizeof(m));
1444 m.tex[0] = R_GetTexture(basetexture);
1445 m.pointer_texcoord[0] = texcoord2f;
1446 if (r_textureunits.integer >= 2)
1449 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1450 m.pointer_texcoord[1] = varray_texcoord2f[1];
1451 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1453 R_Mesh_State_Texture(&m);
1454 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1456 color[0] = bound(0, color2[0], 1);
1457 color[1] = bound(0, color2[1], 1);
1458 color[2] = bound(0, color2[2], 1);
1459 if (r_textureunits.integer >= 2)
1460 R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1462 R_Shadow_VertexLighting(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1463 R_Mesh_Draw(numverts, numtriangles, elements);
1465 c_rt_lighttris += numtriangles;
1470 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)
1473 float color[3], color2[3], colorscale;
1475 if (!gl_dot3arb || !gl_texturecubemap || !gl_combine.integer || !gl_stencil)
1478 glosstexture = r_shadow_blankglosstexture;
1479 if (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))
1481 colorscale = r_shadow_glossintensity.value;
1483 bumptexture = r_shadow_blankbumptexture;
1484 if (glosstexture == r_shadow_blankglosstexture)
1485 colorscale *= r_shadow_gloss2intensity.value;
1486 GL_VertexPointer(vertex3f);
1488 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1490 // 2/0/0/1/2 3D combine blendsquare path
1491 memset(&m, 0, sizeof(m));
1492 m.tex[0] = R_GetTexture(bumptexture);
1493 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1494 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1495 m.pointer_texcoord[0] = texcoord2f;
1496 m.pointer_texcoord[1] = varray_texcoord3f[1];
1497 R_Mesh_State_Texture(&m);
1498 GL_ColorMask(0,0,0,1);
1499 // this squares the result
1500 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1501 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1502 R_Mesh_Draw(numverts, numtriangles, elements);
1504 c_rt_lighttris += numtriangles;
1506 memset(&m, 0, sizeof(m));
1507 R_Mesh_State_Texture(&m);
1508 // square alpha in framebuffer a few times to make it shiny
1509 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1510 // these comments are a test run through this math for intensity 0.5
1511 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1512 // 0.25 * 0.25 = 0.0625 (this is another pass)
1513 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1514 R_Mesh_Draw(numverts, numtriangles, elements);
1516 c_rt_lighttris += numtriangles;
1517 R_Mesh_Draw(numverts, numtriangles, elements);
1519 c_rt_lighttris += numtriangles;
1521 memset(&m, 0, sizeof(m));
1522 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1523 m.pointer_texcoord[0] = varray_texcoord3f[0];
1524 R_Mesh_State_Texture(&m);
1525 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1526 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1527 R_Mesh_Draw(numverts, numtriangles, elements);
1529 c_rt_lighttris += numtriangles;
1531 memset(&m, 0, sizeof(m));
1532 m.tex[0] = R_GetTexture(glosstexture);
1535 m.texcubemap[1] = R_GetTexture(lightcubemap);
1536 m.pointer_texcoord[1] = varray_texcoord3f[1];
1537 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1539 m.pointer_texcoord[0] = texcoord2f;
1540 R_Mesh_State_Texture(&m);
1541 GL_ColorMask(1,1,1,0);
1542 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1543 VectorScale(lightcolor, colorscale, color2);
1544 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1546 color[0] = bound(0, color2[0], 1);
1547 color[1] = bound(0, color2[1], 1);
1548 color[2] = bound(0, color2[2], 1);
1549 GL_Color(color[0], color[1], color[2], 1);
1550 R_Mesh_Draw(numverts, numtriangles, elements);
1552 c_rt_lighttris += numtriangles;
1555 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1557 // 2/0/0/2 3D combine blendsquare path
1558 memset(&m, 0, sizeof(m));
1559 m.tex[0] = R_GetTexture(bumptexture);
1560 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1561 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1562 m.pointer_texcoord[0] = texcoord2f;
1563 m.pointer_texcoord[1] = varray_texcoord3f[1];
1564 R_Mesh_State_Texture(&m);
1565 GL_ColorMask(0,0,0,1);
1566 // this squares the result
1567 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1568 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1569 R_Mesh_Draw(numverts, numtriangles, elements);
1571 c_rt_lighttris += numtriangles;
1573 memset(&m, 0, sizeof(m));
1574 R_Mesh_State_Texture(&m);
1575 // square alpha in framebuffer a few times to make it shiny
1576 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1577 // these comments are a test run through this math for intensity 0.5
1578 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1579 // 0.25 * 0.25 = 0.0625 (this is another pass)
1580 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1581 R_Mesh_Draw(numverts, numtriangles, elements);
1583 c_rt_lighttris += numtriangles;
1584 R_Mesh_Draw(numverts, numtriangles, elements);
1586 c_rt_lighttris += numtriangles;
1588 memset(&m, 0, sizeof(m));
1589 m.tex[0] = R_GetTexture(glosstexture);
1590 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1591 m.pointer_texcoord[0] = texcoord2f;
1592 m.pointer_texcoord[1] = varray_texcoord3f[1];
1593 R_Mesh_State_Texture(&m);
1594 GL_ColorMask(1,1,1,0);
1595 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1596 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1597 VectorScale(lightcolor, colorscale, color2);
1598 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1600 color[0] = bound(0, color2[0], 1);
1601 color[1] = bound(0, color2[1], 1);
1602 color[2] = bound(0, color2[2], 1);
1603 GL_Color(color[0], color[1], color[2], 1);
1604 R_Mesh_Draw(numverts, numtriangles, elements);
1606 c_rt_lighttris += numtriangles;
1609 else if (r_textureunits.integer >= 2 /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1611 // 2/0/0/2/2 2D combine blendsquare path
1612 memset(&m, 0, sizeof(m));
1613 m.tex[0] = R_GetTexture(bumptexture);
1614 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1615 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1616 m.pointer_texcoord[0] = texcoord2f;
1617 m.pointer_texcoord[1] = varray_texcoord3f[1];
1618 R_Mesh_State_Texture(&m);
1619 GL_ColorMask(0,0,0,1);
1620 // this squares the result
1621 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1622 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1623 R_Mesh_Draw(numverts, numtriangles, elements);
1625 c_rt_lighttris += numtriangles;
1627 memset(&m, 0, sizeof(m));
1628 R_Mesh_State_Texture(&m);
1629 // square alpha in framebuffer a few times to make it shiny
1630 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1631 // these comments are a test run through this math for intensity 0.5
1632 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1633 // 0.25 * 0.25 = 0.0625 (this is another pass)
1634 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1635 R_Mesh_Draw(numverts, numtriangles, elements);
1637 c_rt_lighttris += numtriangles;
1638 R_Mesh_Draw(numverts, numtriangles, elements);
1640 c_rt_lighttris += numtriangles;
1642 memset(&m, 0, sizeof(m));
1643 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1644 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1645 m.pointer_texcoord[0] = varray_texcoord2f[0];
1646 m.pointer_texcoord[1] = varray_texcoord2f[1];
1647 R_Mesh_State_Texture(&m);
1648 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1649 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1650 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1651 R_Mesh_Draw(numverts, numtriangles, elements);
1653 c_rt_lighttris += numtriangles;
1655 memset(&m, 0, sizeof(m));
1656 m.tex[0] = R_GetTexture(glosstexture);
1659 m.texcubemap[1] = R_GetTexture(lightcubemap);
1660 m.pointer_texcoord[1] = varray_texcoord3f[1];
1661 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1663 m.pointer_texcoord[0] = texcoord2f;
1664 R_Mesh_State_Texture(&m);
1665 GL_ColorMask(1,1,1,0);
1666 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1667 VectorScale(lightcolor, colorscale, color2);
1668 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1670 color[0] = bound(0, color2[0], 1);
1671 color[1] = bound(0, color2[1], 1);
1672 color[2] = bound(0, color2[2], 1);
1673 GL_Color(color[0], color[1], color[2], 1);
1674 R_Mesh_Draw(numverts, numtriangles, elements);
1676 c_rt_lighttris += numtriangles;
1682 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1686 R_RTLight_Uncompile(rtlight);
1687 memset(rtlight, 0, sizeof(*rtlight));
1689 VectorCopy(light->origin, rtlight->shadoworigin);
1690 VectorCopy(light->color, rtlight->color);
1691 rtlight->radius = light->radius;
1692 rtlight->cullradius = rtlight->radius;
1693 rtlight->cullradius2 = rtlight->cullradius * rtlight->cullradius;
1694 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->cullradius;
1695 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->cullradius;
1696 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->cullradius;
1697 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->cullradius;
1698 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->cullradius;
1699 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->cullradius;
1700 rtlight->cubemapname[0] = 0;
1701 if (light->cubemapname[0])
1702 strcpy(rtlight->cubemapname, light->cubemapname);
1703 else if (light->cubemapnum > 0)
1704 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1705 rtlight->shadow = light->shadow;
1706 rtlight->corona = light->corona;
1707 rtlight->style = light->style;
1708 rtlight->isstatic = isstatic;
1709 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1710 // ConcatScale won't work here because this needs to scale rotate and
1711 // translate, not just rotate
1712 scale = 1.0f / rtlight->radius;
1713 for (k = 0;k < 3;k++)
1714 for (j = 0;j < 4;j++)
1715 rtlight->matrix_worldtolight.m[k][j] *= scale;
1716 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1717 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1719 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1720 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1721 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.25f, rtlight->lightmap_light);
1722 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1725 // compiles rtlight geometry
1726 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1727 void R_RTLight_Compile(rtlight_t *rtlight)
1729 int i, j, k, l, maxverts = 256, tris;
1730 float *vertex3f = NULL, mins[3], maxs[3];
1731 shadowmesh_t *mesh, *castmesh = NULL;
1733 qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8];
1734 qbyte lightfullpvs[(MAX_MAP_LEAFS + 7)/ 8];
1736 // compile the light
1737 rtlight->compiled = true;
1738 VectorCopy(rtlight->cullmins, mins);
1739 VectorCopy(rtlight->cullmaxs, maxs);
1740 if (rtlight->shadow)
1741 castmesh = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1742 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1745 lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, rtlight->shadoworigin, 0, lightfullpvs, sizeof(lightfullpvs));
1746 memset(lightpvs, 0, lightpvsbytes);
1747 if (cl.worldmodel->brushq3.num_leafs)
1752 // make a pvs that only includes things within the box
1753 for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
1754 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1755 SETPVSBIT(lightpvs, leaf->clusterindex);
1757 // make a cluster list for fast visibility checking during rendering
1758 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1759 if (CHECKPVSBIT(lightpvs, i))
1760 rtlight->static_numclusters++;
1761 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1762 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1763 if (CHECKPVSBIT(lightpvs, i))
1764 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1766 VectorCopy(rtlight->shadoworigin, rtlight->cullmins);
1767 VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs);
1768 for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
1769 face->lighttemp_castshadow = false;
1770 for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
1772 if (CHECKPVSBIT(lightpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1774 for (k = 0;k < 3;k++)
1776 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1777 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1779 for (j = 0;j < leaf->numleaffaces;j++)
1781 face = leaf->firstleafface[j];
1782 if (BoxesOverlap(face->mins, face->maxs, mins, maxs))
1783 face->lighttemp_castshadow = true;
1788 // add surfaces to shadow casting mesh and light mesh
1789 for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
1791 if (face->lighttemp_castshadow)
1793 face->lighttemp_castshadow = false;
1794 if (!(face->texture->surfaceflags & (Q3SURFACEFLAG_NODRAW | Q3SURFACEFLAG_SKY)))
1796 if (rtlight->shadow)
1797 if (!(face->texture->nativecontents & CONTENTSQ3_TRANSLUCENT))
1798 Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, face->data_vertex3f, NULL, NULL, NULL, NULL, face->num_triangles, face->data_element3i);
1799 if (!(face->texture->surfaceflags & Q3SURFACEFLAG_SKY))
1800 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);
1805 else if (cl.worldmodel->brushq1.num_leafs)
1809 VectorCopy(rtlight->shadoworigin, rtlight->cullmins);
1810 VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs);
1811 i = CL_PointQ1Contents(rtlight->shadoworigin);
1813 for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
1814 surf->lighttemp_castshadow = false;
1816 if (r_shadow_portallight.integer && i != CONTENTS_SOLID && i != CONTENTS_SKY)
1819 qbyte *bytesurfacepvs;
1821 byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.num_leafs);
1822 bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numsurfaces);
1824 Portal_Visibility(cl.worldmodel, rtlight->shadoworigin, byteleafpvs, bytesurfacepvs, NULL, 0, true, mins, maxs, rtlight->cullmins, rtlight->cullmaxs);
1826 // make a pvs that only includes things within the box
1827 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1829 if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1831 SETPVSBIT(lightpvs, leaf->clusterindex);
1832 for (k = 0;k < 3;k++)
1834 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1835 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1840 for (i = 0, surf = cl.worldmodel->brushq1.surfaces;i < cl.worldmodel->brushq1.numsurfaces;i++, surf++)
1841 if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
1842 surf->lighttemp_castshadow = true;
1844 Mem_Free(byteleafpvs);
1845 Mem_Free(bytesurfacepvs);
1847 // make a cluster list for fast visibility checking during rendering
1848 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1849 if (CHECKPVSBIT(lightpvs, i))
1850 rtlight->static_numclusters++;
1851 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1852 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1853 if (CHECKPVSBIT(lightpvs, i))
1854 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1858 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1860 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1862 // make a pvs that only includes things within the box
1863 SETPVSBIT(lightpvs, leaf->clusterindex);
1864 for (k = 0;k < 3;k++)
1866 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1867 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1869 for (j = 0;j < leaf->nummarksurfaces;j++)
1871 surf = cl.worldmodel->brushq1.surfaces + leaf->firstmarksurface[j];
1872 if (!surf->lighttemp_castshadow && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
1873 surf->lighttemp_castshadow = true;
1878 // make a pvs that only includes things within the box
1879 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1880 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1881 SETPVSBIT(lightpvs, leaf->clusterindex);
1883 // make a cluster list for fast visibility checking during rendering
1884 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1885 if (CHECKPVSBIT(lightpvs, i))
1886 rtlight->static_numclusters++;
1887 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1888 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1889 if (CHECKPVSBIT(lightpvs, i))
1890 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1893 // add surfaces to shadow casting mesh and light mesh
1894 for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
1896 if (surf->lighttemp_castshadow)
1898 surf->lighttemp_castshadow = false;
1899 if (rtlight->shadow && (surf->flags & SURF_SHADOWCAST))
1900 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);
1901 if (!(surf->flags & SURF_DRAWSKY))
1902 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);
1908 // limit box to light bounds (in case it grew larger)
1909 for (k = 0;k < 3;k++)
1911 if (rtlight->cullmins[k] < rtlight->shadoworigin[k] - rtlight->radius) rtlight->cullmins[k] = rtlight->shadoworigin[k] - rtlight->radius;
1912 if (rtlight->cullmaxs[k] > rtlight->shadoworigin[k] + rtlight->radius) rtlight->cullmaxs[k] = rtlight->shadoworigin[k] + rtlight->radius;
1914 rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1915 rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1917 // cast shadow volume from castmesh
1918 castmesh = Mod_ShadowMesh_Finish(r_shadow_mempool, castmesh, false, true);
1922 for (mesh = castmesh;mesh;mesh = mesh->next)
1924 R_Shadow_ResizeShadowElements(mesh->numtriangles);
1925 maxverts = max(maxverts, mesh->numverts * 2);
1930 vertex3f = Mem_Alloc(r_shadow_mempool, maxverts * sizeof(float[3]));
1931 // now that we have the buffers big enough, construct and add
1932 // the shadow volume mesh
1933 if (rtlight->shadow)
1934 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1935 for (mesh = castmesh;mesh;mesh = mesh->next)
1937 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1938 R_Shadow_PrepareShadowMark(mesh->numtriangles);
1939 for (i = 0;i < mesh->numtriangles;i++)
1942 v[0] = mesh->vertex3f + mesh->element3i[i*3+0] * 3;
1943 v[1] = mesh->vertex3f + mesh->element3i[i*3+1] * 3;
1944 v[2] = mesh->vertex3f + mesh->element3i[i*3+2] * 3;
1945 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])))
1946 shadowmarklist[numshadowmark++] = i;
1948 if (maxshadowelements < numshadowmark * 24)
1949 R_Shadow_ResizeShadowElements((numshadowmark + 256) * 24);
1950 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)))
1951 Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1956 // we're done with castmesh now
1957 Mod_ShadowMesh_Free(castmesh);
1960 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1961 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1964 if (rtlight->static_meshchain_shadow)
1965 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1966 k += mesh->numtriangles;
1968 if (rtlight->static_meshchain_light)
1969 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1970 l += mesh->numtriangles;
1971 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);
1974 void R_RTLight_Uncompile(rtlight_t *rtlight)
1976 if (rtlight->compiled)
1978 if (rtlight->static_meshchain_shadow)
1979 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1980 rtlight->static_meshchain_shadow = NULL;
1981 if (rtlight->static_meshchain_light)
1982 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1983 rtlight->static_meshchain_light = NULL;
1984 if (rtlight->static_clusterindices)
1985 Mem_Free(rtlight->static_clusterindices);
1986 rtlight->static_clusterindices = NULL;
1987 rtlight->static_numclusters = 0;
1988 rtlight->compiled = false;
1992 int shadowframecount = 0;
1994 void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t shadoworigin, vec_t shadowradius, vec3_t cullmins, vec3_t cullmaxs)
1997 if ((BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) || !r_shadow_cull.integer) && (ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume)
1999 vec3_t relativeshadoworigin;
2000 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativeshadoworigin);
2001 ent->model->DrawShadowVolume (ent, relativeshadoworigin, shadowradius);
2005 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
2007 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2010 entity_render_t *ent;
2012 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
2013 rtexture_t *cubemaptexture;
2014 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2016 if (d_lightstylevalue[rtlight->style] <= 0)
2018 if (rtlight->compiled)
2020 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2022 for (i = 0;i < rtlight->static_numclusters;i++)
2023 if (CHECKPVSBIT(r_pvsbits, rtlight->static_clusterindices[i]))
2025 if (i == rtlight->static_numclusters)
2028 else if (VIS_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2030 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2033 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2034 R_RTLight_Compile(rtlight);
2036 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2037 VectorScale(rtlight->color, f, lightcolor);
2039 if (rtlight->selected)
2041 f = 2 + sin(realtime * M_PI * 4.0);
2042 VectorScale(lightcolor, f, lightcolor);
2046 if (rtlight->cubemapname[0])
2047 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2049 cubemaptexture = NULL;
2051 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_worldshadows.integer : r_shadow_dlightshadows.integer);
2052 if (shadow && (gl_stencil || visiblevolumes))
2054 if (!visiblevolumes)
2055 R_Shadow_Stage_ShadowVolumes();
2056 ent = &cl_entities[0].render;
2057 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2059 R_Mesh_Matrix(&ent->matrix);
2060 if (r_shadow_showtris.integer)
2064 int depthenabled = qglIsEnabled(GL_DEPTH_TEST);
2065 int stencilenabled = qglIsEnabled(GL_STENCIL_TEST);
2066 qglDisable(GL_DEPTH_TEST);
2067 qglDisable(GL_STENCIL_TEST);
2068 //qglDisable(GL_CULL_FACE);
2069 GL_ColorMask(1,1,1,1);
2070 memset(&m, 0, sizeof(m));
2071 R_Mesh_State_Texture(&m);
2072 GL_Color(0,0.1,0,1);
2073 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2074 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2076 GL_VertexPointer(mesh->vertex3f);
2077 R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i);
2079 //qglEnable(GL_CULL_FACE);
2081 qglEnable(GL_DEPTH_TEST);
2084 qglEnable(GL_STENCIL_TEST);
2085 GL_ColorMask(0,0,0,0);
2088 R_Shadow_RenderShadowMeshVolume(rtlight->static_meshchain_shadow);
2091 R_TestAndDrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs);
2092 if (r_drawentities.integer)
2093 for (i = 0;i < r_refdef.numentities;i++)
2094 if (r_refdef.entities[i]->flags & RENDER_SHADOW)
2095 R_TestAndDrawShadowVolume(r_refdef.entities[i], rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs);
2098 if (!visiblevolumes)
2100 if (shadow && gl_stencil)
2101 R_Shadow_Stage_LightWithShadows();
2103 R_Shadow_Stage_LightWithoutShadows();
2105 ent = &cl_entities[0].render;
2106 if (ent->model && ent->model->DrawLight)
2108 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2109 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2110 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2111 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2112 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2113 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2115 //R_Shadow_DrawStaticWorldLight_Light(rtlight, &ent->matrix, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2117 R_Mesh_Matrix(&ent->matrix);
2118 if (r_shadow_showtris.integer)
2121 int depthenabled = qglIsEnabled(GL_DEPTH_TEST);
2122 int stencilenabled = qglIsEnabled(GL_STENCIL_TEST);
2123 qglDisable(GL_DEPTH_TEST);
2124 qglDisable(GL_STENCIL_TEST);
2125 //qglDisable(GL_CULL_FACE);
2126 memset(&m, 0, sizeof(m));
2127 R_Mesh_State_Texture(&m);
2128 GL_Color(0.2,0,0,1);
2129 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2130 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2132 GL_VertexPointer(mesh->vertex3f);
2133 R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i);
2135 //qglEnable(GL_CULL_FACE);
2137 qglEnable(GL_DEPTH_TEST);
2139 qglEnable(GL_STENCIL_TEST);
2141 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2143 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);
2144 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);
2148 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2150 if (r_drawentities.integer)
2152 for (i = 0;i < r_refdef.numentities;i++)
2154 ent = r_refdef.entities[i];
2155 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
2156 && BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2157 && (ent->flags & RENDER_LIGHT))
2159 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2160 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2161 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2162 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2163 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2164 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2171 void R_ShadowVolumeLighting(int visiblevolumes)
2179 memset(&m, 0, sizeof(m));
2180 R_Mesh_State_Texture(&m);
2182 GL_BlendFunc(GL_ONE, GL_ONE);
2183 GL_DepthMask(false);
2184 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2185 qglDisable(GL_CULL_FACE);
2186 GL_Color(0.0, 0.0125, 0.1, 1);
2189 R_Shadow_Stage_Begin();
2191 if (r_shadow_realtime_world.integer)
2193 R_Shadow_LoadWorldLightsIfNeeded();
2194 if (r_shadow_debuglight.integer >= 0)
2196 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2197 if (lnum == r_shadow_debuglight.integer)
2198 R_DrawRTLight(&light->rtlight, visiblevolumes);
2201 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2202 R_DrawRTLight(&light->rtlight, visiblevolumes);
2204 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2205 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2206 R_DrawRTLight(&light->rtlight, visiblevolumes);
2210 qglEnable(GL_CULL_FACE);
2211 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2214 R_Shadow_Stage_End();
2217 cvar_t r_editlights = {0, "r_editlights", "0"};
2218 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
2219 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
2220 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
2221 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
2222 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
2223 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
2224 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
2225 dlight_t *r_shadow_worldlightchain;
2226 dlight_t *r_shadow_selectedlight;
2227 vec3_t r_editlights_cursorlocation;
2229 typedef struct cubemapinfo_s
2232 rtexture_t *texture;
2236 #define MAX_CUBEMAPS 128
2237 static int numcubemaps;
2238 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
2240 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2241 typedef struct suffixinfo_s
2244 int flipx, flipy, flipdiagonal;
2247 static suffixinfo_t suffix[3][6] =
2250 {"posx", false, false, false},
2251 {"negx", false, false, false},
2252 {"posy", false, false, false},
2253 {"negy", false, false, false},
2254 {"posz", false, false, false},
2255 {"negz", false, false, false}
2258 {"px", false, false, false},
2259 {"nx", false, false, false},
2260 {"py", false, false, false},
2261 {"ny", false, false, false},
2262 {"pz", false, false, false},
2263 {"nz", false, false, false}
2266 {"ft", true, false, true},
2267 {"bk", false, true, true},
2268 {"lf", true, true, false},
2269 {"rt", false, false, false},
2270 {"up", false, false, false},
2271 {"dn", false, false, false}
2275 static int componentorder[4] = {0, 1, 2, 3};
2277 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2279 int i, j, cubemapsize;
2280 qbyte *cubemappixels, *image_rgba;
2281 rtexture_t *cubemaptexture;
2283 // must start 0 so the first loadimagepixels has no requested width/height
2285 cubemappixels = NULL;
2286 cubemaptexture = NULL;
2287 for (j = 0;j < 3 && !cubemappixels;j++)
2289 for (i = 0;i < 6;i++)
2291 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2292 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2294 if (image_width == image_height)
2296 if (!cubemappixels && image_width >= 1)
2298 cubemapsize = image_width;
2299 // note this clears to black, so unavailable sizes are black
2300 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2303 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);
2306 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2307 Mem_Free(image_rgba);
2313 if (!r_shadow_filters_texturepool)
2314 r_shadow_filters_texturepool = R_AllocTexturePool();
2315 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2316 Mem_Free(cubemappixels);
2320 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2321 for (j = 0;j < 3;j++)
2322 for (i = 0;i < 6;i++)
2323 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2324 Con_Print(" and was unable to find any of them.\n");
2326 return cubemaptexture;
2329 rtexture_t *R_Shadow_Cubemap(const char *basename)
2332 for (i = 0;i < numcubemaps;i++)
2333 if (!strcasecmp(cubemaps[i].basename, basename))
2334 return cubemaps[i].texture;
2335 if (i >= MAX_CUBEMAPS)
2338 strcpy(cubemaps[i].basename, basename);
2339 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2340 return cubemaps[i].texture;
2343 void R_Shadow_FreeCubemaps(void)
2346 R_FreeTexturePool(&r_shadow_filters_texturepool);
2349 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)
2353 if (radius < 15 || DotProduct(color, color) < 0.03)
2355 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2359 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2360 VectorCopy(origin, light->origin);
2361 VectorCopy(angles, light->angles);
2362 VectorCopy(color, light->color);
2363 light->radius = radius;
2364 light->style = style;
2365 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2367 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2370 light->shadow = shadowenable;
2371 light->corona = corona;
2372 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2373 strcpy(light->cubemapname, cubemapname);
2374 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2375 light->next = r_shadow_worldlightchain;
2376 r_shadow_worldlightchain = light;
2378 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2379 if (r_shadow_staticworldlights.integer)
2380 R_RTLight_Compile(&light->rtlight);
2383 void R_Shadow_FreeWorldLight(dlight_t *light)
2385 dlight_t **lightpointer;
2386 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2387 if (*lightpointer != light)
2388 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2389 *lightpointer = light->next;
2390 R_RTLight_Uncompile(&light->rtlight);
2394 void R_Shadow_ClearWorldLights(void)
2396 while (r_shadow_worldlightchain)
2397 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2398 r_shadow_selectedlight = NULL;
2399 R_Shadow_FreeCubemaps();
2402 void R_Shadow_SelectLight(dlight_t *light)
2404 if (r_shadow_selectedlight)
2405 r_shadow_selectedlight->selected = false;
2406 r_shadow_selectedlight = light;
2407 if (r_shadow_selectedlight)
2408 r_shadow_selectedlight->selected = true;
2411 rtexture_t *lighttextures[5];
2413 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2415 float scale = r_editlights_cursorgrid.value * 0.5f;
2416 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);
2419 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2422 const dlight_t *light;
2425 if (light->selected)
2426 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2429 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);
2432 void R_Shadow_DrawLightSprites(void)
2438 for (i = 0;i < 5;i++)
2440 lighttextures[i] = NULL;
2441 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2442 lighttextures[i] = pic->tex;
2445 for (light = r_shadow_worldlightchain;light;light = light->next)
2446 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2447 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2450 void R_Shadow_SelectLightInView(void)
2452 float bestrating, rating, temp[3];
2453 dlight_t *best, *light;
2456 for (light = r_shadow_worldlightchain;light;light = light->next)
2458 VectorSubtract(light->origin, r_vieworigin, temp);
2459 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2462 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2463 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2465 bestrating = rating;
2470 R_Shadow_SelectLight(best);
2473 void R_Shadow_LoadWorldLights(void)
2475 int n, a, style, shadow;
2476 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2477 float origin[3], radius, color[3], angles[3], corona;
2478 if (cl.worldmodel == NULL)
2480 Con_Print("No map loaded.\n");
2483 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2484 strlcat (name, ".rtlights", sizeof (name));
2485 lightsstring = FS_LoadFile(name, false);
2495 for (;COM_Parse(t, true) && strcmp(
2496 if (COM_Parse(t, true))
2498 if (com_token[0] == '!')
2501 origin[0] = atof(com_token+1);
2504 origin[0] = atof(com_token);
2509 while (*s && *s != '\n')
2515 // check for modifier flags
2521 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]);
2523 VectorClear(angles);
2526 if (a < 9 || !strcmp(cubemapname, "\"\""))
2531 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);
2534 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2535 radius *= r_editlights_rtlightssizescale.value;
2536 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2541 Con_Printf("invalid rtlights file \"%s\"\n", name);
2542 Mem_Free(lightsstring);
2546 void R_Shadow_SaveWorldLights(void)
2549 int bufchars, bufmaxchars;
2551 char name[MAX_QPATH];
2553 if (!r_shadow_worldlightchain)
2555 if (cl.worldmodel == NULL)
2557 Con_Print("No map loaded.\n");
2560 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2561 strlcat (name, ".rtlights", sizeof (name));
2562 bufchars = bufmaxchars = 0;
2564 for (light = r_shadow_worldlightchain;light;light = light->next)
2566 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]);
2567 if (bufchars + (int) strlen(line) > bufmaxchars)
2569 bufmaxchars = bufchars + strlen(line) + 2048;
2571 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2575 memcpy(buf, oldbuf, bufchars);
2581 memcpy(buf + bufchars, line, strlen(line));
2582 bufchars += strlen(line);
2586 FS_WriteFile(name, buf, bufchars);
2591 void R_Shadow_LoadLightsFile(void)
2594 char name[MAX_QPATH], *lightsstring, *s, *t;
2595 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2596 if (cl.worldmodel == NULL)
2598 Con_Print("No map loaded.\n");
2601 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2602 strlcat (name, ".lights", sizeof (name));
2603 lightsstring = FS_LoadFile(name, false);
2611 while (*s && *s != '\n')
2616 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);
2620 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);
2623 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2624 radius = bound(15, radius, 4096);
2625 VectorScale(color, (2.0f / (8388608.0f)), color);
2626 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2631 Con_Printf("invalid lights file \"%s\"\n", name);
2632 Mem_Free(lightsstring);
2636 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2638 int entnum, style, islight, skin, pflags, effects;
2639 char key[256], value[1024];
2640 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2643 if (cl.worldmodel == NULL)
2645 Con_Print("No map loaded.\n");
2648 data = cl.worldmodel->brush.entities;
2651 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2654 origin[0] = origin[1] = origin[2] = 0;
2655 originhack[0] = originhack[1] = originhack[2] = 0;
2656 angles[0] = angles[1] = angles[2] = 0;
2657 color[0] = color[1] = color[2] = 1;
2658 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2668 if (!COM_ParseToken(&data, false))
2670 if (com_token[0] == '}')
2671 break; // end of entity
2672 if (com_token[0] == '_')
2673 strcpy(key, com_token + 1);
2675 strcpy(key, com_token);
2676 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2677 key[strlen(key)-1] = 0;
2678 if (!COM_ParseToken(&data, false))
2680 strcpy(value, com_token);
2682 // now that we have the key pair worked out...
2683 if (!strcmp("light", key))
2684 light = atof(value);
2685 else if (!strcmp("origin", key))
2686 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2687 else if (!strcmp("angle", key))
2688 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2689 else if (!strcmp("angles", key))
2690 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2691 else if (!strcmp("color", key))
2692 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2693 else if (!strcmp("wait", key))
2694 fadescale = atof(value);
2695 else if (!strcmp("classname", key))
2697 if (!strncmp(value, "light", 5))
2700 if (!strcmp(value, "light_fluoro"))
2705 overridecolor[0] = 1;
2706 overridecolor[1] = 1;
2707 overridecolor[2] = 1;
2709 if (!strcmp(value, "light_fluorospark"))
2714 overridecolor[0] = 1;
2715 overridecolor[1] = 1;
2716 overridecolor[2] = 1;
2718 if (!strcmp(value, "light_globe"))
2723 overridecolor[0] = 1;
2724 overridecolor[1] = 0.8;
2725 overridecolor[2] = 0.4;
2727 if (!strcmp(value, "light_flame_large_yellow"))
2732 overridecolor[0] = 1;
2733 overridecolor[1] = 0.5;
2734 overridecolor[2] = 0.1;
2736 if (!strcmp(value, "light_flame_small_yellow"))
2741 overridecolor[0] = 1;
2742 overridecolor[1] = 0.5;
2743 overridecolor[2] = 0.1;
2745 if (!strcmp(value, "light_torch_small_white"))
2750 overridecolor[0] = 1;
2751 overridecolor[1] = 0.5;
2752 overridecolor[2] = 0.1;
2754 if (!strcmp(value, "light_torch_small_walltorch"))
2759 overridecolor[0] = 1;
2760 overridecolor[1] = 0.5;
2761 overridecolor[2] = 0.1;
2765 else if (!strcmp("style", key))
2766 style = atoi(value);
2767 else if (cl.worldmodel->type == mod_brushq3)
2769 if (!strcmp("scale", key))
2770 lightscale = atof(value);
2771 if (!strcmp("fade", key))
2772 fadescale = atof(value);
2774 else if (!strcmp("skin", key))
2775 skin = (int)atof(value);
2776 else if (!strcmp("pflags", key))
2777 pflags = (int)atof(value);
2778 else if (!strcmp("effects", key))
2779 effects = (int)atof(value);
2781 if (light <= 0 && islight)
2783 if (lightscale <= 0)
2787 if (gamemode == GAME_TENEBRAE)
2789 if (effects & EF_NODRAW)
2791 pflags |= PFLAGS_FULLDYNAMIC;
2792 effects &= ~EF_NODRAW;
2795 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2796 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2797 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2798 VectorCopy(overridecolor, color);
2799 VectorScale(color, light, color);
2800 VectorAdd(origin, originhack, origin);
2801 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2802 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2807 void R_Shadow_SetCursorLocationForView(void)
2809 vec_t dist, push, frac;
2810 vec3_t dest, endpos, normal;
2811 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2812 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2815 dist = frac * r_editlights_cursordistance.value;
2816 push = r_editlights_cursorpushback.value;
2820 VectorMA(endpos, push, r_viewforward, endpos);
2821 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2823 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2824 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2825 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2828 void R_Shadow_UpdateWorldLightSelection(void)
2830 if (r_editlights.integer)
2832 R_Shadow_SetCursorLocationForView();
2833 R_Shadow_SelectLightInView();
2834 R_Shadow_DrawLightSprites();
2837 R_Shadow_SelectLight(NULL);
2840 void R_Shadow_EditLights_Clear_f(void)
2842 R_Shadow_ClearWorldLights();
2845 void R_Shadow_EditLights_Reload_f(void)
2847 r_shadow_reloadlights = true;
2850 void R_Shadow_EditLights_Save_f(void)
2853 R_Shadow_SaveWorldLights();
2856 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2858 R_Shadow_ClearWorldLights();
2859 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2862 void R_Shadow_EditLights_ImportLightsFile_f(void)
2864 R_Shadow_ClearWorldLights();
2865 R_Shadow_LoadLightsFile();
2868 void R_Shadow_EditLights_Spawn_f(void)
2871 if (!r_editlights.integer)
2873 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2876 if (Cmd_Argc() != 1)
2878 Con_Print("r_editlights_spawn does not take parameters\n");
2881 color[0] = color[1] = color[2] = 1;
2882 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2885 void R_Shadow_EditLights_Edit_f(void)
2887 vec3_t origin, angles, color;
2888 vec_t radius, corona;
2890 char cubemapname[1024];
2891 if (!r_editlights.integer)
2893 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2896 if (!r_shadow_selectedlight)
2898 Con_Print("No selected light.\n");
2901 VectorCopy(r_shadow_selectedlight->origin, origin);
2902 VectorCopy(r_shadow_selectedlight->angles, angles);
2903 VectorCopy(r_shadow_selectedlight->color, color);
2904 radius = r_shadow_selectedlight->radius;
2905 style = r_shadow_selectedlight->style;
2906 if (r_shadow_selectedlight->cubemapname)
2907 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2910 shadows = r_shadow_selectedlight->shadow;
2911 corona = r_shadow_selectedlight->corona;
2912 if (!strcmp(Cmd_Argv(1), "origin"))
2914 if (Cmd_Argc() != 5)
2916 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2919 origin[0] = atof(Cmd_Argv(2));
2920 origin[1] = atof(Cmd_Argv(3));
2921 origin[2] = atof(Cmd_Argv(4));
2923 else if (!strcmp(Cmd_Argv(1), "originx"))
2925 if (Cmd_Argc() != 3)
2927 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2930 origin[0] = atof(Cmd_Argv(2));
2932 else if (!strcmp(Cmd_Argv(1), "originy"))
2934 if (Cmd_Argc() != 3)
2936 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2939 origin[1] = atof(Cmd_Argv(2));
2941 else if (!strcmp(Cmd_Argv(1), "originz"))
2943 if (Cmd_Argc() != 3)
2945 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2948 origin[2] = atof(Cmd_Argv(2));
2950 else if (!strcmp(Cmd_Argv(1), "move"))
2952 if (Cmd_Argc() != 5)
2954 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2957 origin[0] += atof(Cmd_Argv(2));
2958 origin[1] += atof(Cmd_Argv(3));
2959 origin[2] += atof(Cmd_Argv(4));
2961 else if (!strcmp(Cmd_Argv(1), "movex"))
2963 if (Cmd_Argc() != 3)
2965 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2968 origin[0] += atof(Cmd_Argv(2));
2970 else if (!strcmp(Cmd_Argv(1), "movey"))
2972 if (Cmd_Argc() != 3)
2974 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2977 origin[1] += atof(Cmd_Argv(2));
2979 else if (!strcmp(Cmd_Argv(1), "movez"))
2981 if (Cmd_Argc() != 3)
2983 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2986 origin[2] += atof(Cmd_Argv(2));
2988 else if (!strcmp(Cmd_Argv(1), "angles"))
2990 if (Cmd_Argc() != 5)
2992 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2995 angles[0] = atof(Cmd_Argv(2));
2996 angles[1] = atof(Cmd_Argv(3));
2997 angles[2] = atof(Cmd_Argv(4));
2999 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3001 if (Cmd_Argc() != 3)
3003 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3006 angles[0] = atof(Cmd_Argv(2));
3008 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3010 if (Cmd_Argc() != 3)
3012 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3015 angles[1] = atof(Cmd_Argv(2));
3017 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3019 if (Cmd_Argc() != 3)
3021 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3024 angles[2] = atof(Cmd_Argv(2));
3026 else if (!strcmp(Cmd_Argv(1), "color"))
3028 if (Cmd_Argc() != 5)
3030 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3033 color[0] = atof(Cmd_Argv(2));
3034 color[1] = atof(Cmd_Argv(3));
3035 color[2] = atof(Cmd_Argv(4));
3037 else if (!strcmp(Cmd_Argv(1), "radius"))
3039 if (Cmd_Argc() != 3)
3041 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3044 radius = atof(Cmd_Argv(2));
3046 else if (!strcmp(Cmd_Argv(1), "style"))
3048 if (Cmd_Argc() != 3)
3050 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3053 style = atoi(Cmd_Argv(2));
3055 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3059 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3062 if (Cmd_Argc() == 3)
3063 strcpy(cubemapname, Cmd_Argv(2));
3067 else if (!strcmp(Cmd_Argv(1), "shadows"))
3069 if (Cmd_Argc() != 3)
3071 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3074 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3076 else if (!strcmp(Cmd_Argv(1), "corona"))
3078 if (Cmd_Argc() != 3)
3080 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3083 corona = atof(Cmd_Argv(2));
3087 Con_Print("usage: r_editlights_edit [property] [value]\n");
3088 Con_Print("Selected light's properties:\n");
3089 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3090 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3091 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3092 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3093 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3094 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3095 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3096 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3099 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3100 r_shadow_selectedlight = NULL;
3101 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3104 extern int con_vislines;
3105 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3109 if (r_shadow_selectedlight == NULL)
3113 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3114 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;
3115 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;
3116 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;
3117 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3118 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3119 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3120 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;
3121 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3124 void R_Shadow_EditLights_ToggleShadow_f(void)
3126 if (!r_editlights.integer)
3128 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3131 if (!r_shadow_selectedlight)
3133 Con_Print("No selected light.\n");
3136 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);
3137 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3138 r_shadow_selectedlight = NULL;
3141 void R_Shadow_EditLights_ToggleCorona_f(void)
3143 if (!r_editlights.integer)
3145 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3148 if (!r_shadow_selectedlight)
3150 Con_Print("No selected light.\n");
3153 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);
3154 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3155 r_shadow_selectedlight = NULL;
3158 void R_Shadow_EditLights_Remove_f(void)
3160 if (!r_editlights.integer)
3162 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3165 if (!r_shadow_selectedlight)
3167 Con_Print("No selected light.\n");
3170 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3171 r_shadow_selectedlight = NULL;
3174 void R_Shadow_EditLights_Help_f(void)
3177 "Documentation on r_editlights system:\n"
3179 "r_editlights : enable/disable editing mode\n"
3180 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3181 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3182 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3183 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3184 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3185 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3186 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3188 "r_editlights_help : this help\n"
3189 "r_editlights_clear : remove all lights\n"
3190 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3191 "r_editlights_save : save to .rtlights file\n"
3192 "r_editlights_spawn : create a light with default settings\n"
3193 "r_editlights_edit command : edit selected light - more documentation below\n"
3194 "r_editlights_remove : remove selected light\n"
3195 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3196 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3197 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3199 "origin x y z : set light location\n"
3200 "originx x: set x component of light location\n"
3201 "originy y: set y component of light location\n"
3202 "originz z: set z component of light location\n"
3203 "move x y z : adjust light location\n"
3204 "movex x: adjust x component of light location\n"
3205 "movey y: adjust y component of light location\n"
3206 "movez z: adjust z component of light location\n"
3207 "angles x y z : set light angles\n"
3208 "anglesx x: set x component of light angles\n"
3209 "anglesy y: set y component of light angles\n"
3210 "anglesz z: set z component of light angles\n"
3211 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3212 "radius radius : set radius (size) of light\n"
3213 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3214 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3215 "shadows 1/0 : turn on/off shadows\n"
3216 "corona n : set corona intensity\n"
3217 "<nothing> : print light properties to console\n"
3221 void R_Shadow_EditLights_Init(void)
3223 Cvar_RegisterVariable(&r_editlights);
3224 Cvar_RegisterVariable(&r_editlights_cursordistance);
3225 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3226 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3227 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3228 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3229 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3230 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3231 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3232 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3233 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3234 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3235 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3236 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3237 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3238 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3239 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3240 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3241 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);