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_ERASESTENCIL 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"};
183 int c_rt_lights, c_rt_clears, c_rt_scissored;
184 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
185 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
187 void R_Shadow_ClearWorldLights(void);
188 void R_Shadow_SaveWorldLights(void);
189 void R_Shadow_LoadWorldLights(void);
190 void R_Shadow_LoadLightsFile(void);
191 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
193 void r_shadow_start(void)
195 // allocate vertex processing arrays
196 r_shadow_mempool = Mem_AllocPool("R_Shadow");
197 maxshadowelements = 0;
198 shadowelements = NULL;
206 shadowmarklist = NULL;
208 r_shadow_normalcubetexture = NULL;
209 r_shadow_attenuation2dtexture = NULL;
210 r_shadow_attenuation3dtexture = NULL;
211 r_shadow_blankbumptexture = NULL;
212 r_shadow_blankglosstexture = NULL;
213 r_shadow_blankwhitetexture = NULL;
214 r_shadow_texturepool = NULL;
215 r_shadow_filters_texturepool = NULL;
216 R_Shadow_ClearWorldLights();
217 r_shadow_reloadlights = true;
220 void r_shadow_shutdown(void)
222 R_Shadow_ClearWorldLights();
223 r_shadow_reloadlights = true;
224 r_shadow_normalcubetexture = NULL;
225 r_shadow_attenuation2dtexture = NULL;
226 r_shadow_attenuation3dtexture = NULL;
227 r_shadow_blankbumptexture = NULL;
228 r_shadow_blankglosstexture = NULL;
229 r_shadow_blankwhitetexture = NULL;
230 R_FreeTexturePool(&r_shadow_texturepool);
231 R_FreeTexturePool(&r_shadow_filters_texturepool);
232 maxshadowelements = 0;
233 shadowelements = NULL;
241 shadowmarklist = NULL;
243 Mem_FreePool(&r_shadow_mempool);
246 void r_shadow_newmap(void)
248 R_Shadow_ClearWorldLights();
249 r_shadow_reloadlights = true;
252 void R_Shadow_Help_f(void)
255 "Documentation on r_shadow system:\n"
257 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
258 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
259 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
260 "r_shadow_realtime_world : use realtime world light rendering\n"
261 "r_shadow_realtime_dlight : use high quality dlight rendering\n"
262 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to rtlights\n"
263 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
264 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
265 "r_shadow_glossintensity : brightness of textured gloss\n"
266 "r_shadow_gloss2intensity : brightness of forced gloss\n"
267 "r_shadow_debuglight : render only this light number (-1 = all)\n"
268 "r_shadow_scissor : use scissor optimization\n"
269 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
270 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
271 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
272 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
273 "r_shadow_portallight : use portal visibility for static light precomputation\n"
274 "r_shadow_projectdistance : shadow volume projection distance\n"
275 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
276 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
277 "r_shadow_worldshadows : enable world shadows\n"
278 "r_shadow_dlightshadows : enable dlight shadows\n"
280 "r_shadow_help : this help\n"
284 void R_Shadow_Init(void)
286 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
287 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
288 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
289 Cvar_RegisterVariable(&r_shadow_realtime_world);
290 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
291 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
292 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
293 Cvar_RegisterVariable(&r_shadow_gloss);
294 Cvar_RegisterVariable(&r_shadow_glossintensity);
295 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
296 Cvar_RegisterVariable(&r_shadow_debuglight);
297 Cvar_RegisterVariable(&r_shadow_scissor);
298 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
299 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
300 Cvar_RegisterVariable(&r_shadow_polygonfactor);
301 Cvar_RegisterVariable(&r_shadow_polygonoffset);
302 Cvar_RegisterVariable(&r_shadow_portallight);
303 Cvar_RegisterVariable(&r_shadow_projectdistance);
304 Cvar_RegisterVariable(&r_shadow_texture3d);
305 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
306 Cvar_RegisterVariable(&r_shadow_worldshadows);
307 Cvar_RegisterVariable(&r_shadow_dlightshadows);
308 Cvar_RegisterVariable(&r_shadow_showtris);
309 Cvar_RegisterVariable(&r_shadow_staticworldlights);
310 Cvar_RegisterVariable(&r_shadow_cull);
311 if (gamemode == GAME_TENEBRAE)
313 Cvar_SetValue("r_shadow_gloss", 2);
314 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
316 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
317 R_Shadow_EditLights_Init();
318 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
321 matrix4x4_t matrix_attenuationxyz =
324 {0.5, 0.0, 0.0, 0.5},
325 {0.0, 0.5, 0.0, 0.5},
326 {0.0, 0.0, 0.5, 0.5},
331 matrix4x4_t matrix_attenuationz =
334 {0.0, 0.0, 0.5, 0.5},
335 {0.0, 0.0, 0.0, 0.0},
336 {0.0, 0.0, 0.0, 0.0},
341 int *R_Shadow_ResizeShadowElements(int numtris)
343 // make sure shadowelements is big enough for this volume
344 if (maxshadowelements < numtris * 24)
346 maxshadowelements = numtris * 24;
348 Mem_Free(shadowelements);
349 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
351 return shadowelements;
354 void R_Shadow_PrepareShadowMark(int numtris)
356 // make sure shadowmark is big enough for this volume
357 if (maxshadowmark < numtris)
359 maxshadowmark = numtris;
361 Mem_Free(shadowmark);
363 Mem_Free(shadowmarklist);
364 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
365 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
369 // if shadowmarkcount wrapped we clear the array and adjust accordingly
370 if (shadowmarkcount == 0)
373 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
378 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)
380 int i, j, tris = 0, vr[3], t, outvertices = 0;
384 if (maxvertexupdate < innumvertices)
386 maxvertexupdate = innumvertices;
388 Mem_Free(vertexupdate);
390 Mem_Free(vertexremap);
391 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
392 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
396 if (vertexupdatenum == 0)
399 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
400 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
403 for (i = 0;i < numshadowmarktris;i++)
405 t = shadowmarktris[i];
406 shadowmark[t] = shadowmarkcount;
407 e = inelement3i + t * 3;
408 // make sure the vertices are created
409 for (j = 0;j < 3;j++)
411 if (vertexupdate[e[j]] != vertexupdatenum)
413 vertexupdate[e[j]] = vertexupdatenum;
414 vertexremap[e[j]] = outvertices;
415 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
416 f = projectdistance / VectorLength(temp);
417 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
418 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
423 // output the front and back triangles
424 outelement3i[0] = vertexremap[e[0]];
425 outelement3i[1] = vertexremap[e[1]];
426 outelement3i[2] = vertexremap[e[2]];
427 outelement3i[3] = vertexremap[e[2]] + 1;
428 outelement3i[4] = vertexremap[e[1]] + 1;
429 outelement3i[5] = vertexremap[e[0]] + 1;
434 for (i = 0;i < numshadowmarktris;i++)
436 t = shadowmarktris[i];
437 e = inelement3i + t * 3;
438 n = inneighbor3i + t * 3;
439 // output the sides (facing outward from this triangle)
440 if (shadowmark[n[0]] != shadowmarkcount)
442 vr[0] = vertexremap[e[0]];
443 vr[1] = vertexremap[e[1]];
444 outelement3i[0] = vr[1];
445 outelement3i[1] = vr[0];
446 outelement3i[2] = vr[0] + 1;
447 outelement3i[3] = vr[1];
448 outelement3i[4] = vr[0] + 1;
449 outelement3i[5] = vr[1] + 1;
453 if (shadowmark[n[1]] != shadowmarkcount)
455 vr[1] = vertexremap[e[1]];
456 vr[2] = vertexremap[e[2]];
457 outelement3i[0] = vr[2];
458 outelement3i[1] = vr[1];
459 outelement3i[2] = vr[1] + 1;
460 outelement3i[3] = vr[2];
461 outelement3i[4] = vr[1] + 1;
462 outelement3i[5] = vr[2] + 1;
466 if (shadowmark[n[2]] != shadowmarkcount)
468 vr[0] = vertexremap[e[0]];
469 vr[2] = vertexremap[e[2]];
470 outelement3i[0] = vr[0];
471 outelement3i[1] = vr[2];
472 outelement3i[2] = vr[2] + 1;
473 outelement3i[3] = vr[0];
474 outelement3i[4] = vr[2] + 1;
475 outelement3i[5] = vr[0] + 1;
481 *outnumvertices = outvertices;
485 float varray_vertex3f2[65536*3];
487 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)
490 if (projectdistance < 0.1)
492 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
495 if (!numverts || !nummarktris)
497 // make sure shadowelements is big enough for this volume
498 if (maxshadowelements < nummarktris * 24)
499 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
500 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
501 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
504 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)
509 // check which triangles are facing the , and then output
510 // triangle elements and vertices... by clever use of elements we
511 // can construct the whole shadow from the unprojected vertices and
512 // the projected vertices
514 // identify lit faces within the bounding box
515 R_Shadow_PrepareShadowMark(numtris);
516 for (i = 0;i < numtris;i++)
518 v[0] = invertex3f + elements[i*3+0] * 3;
519 v[1] = invertex3f + elements[i*3+1] * 3;
520 v[2] = invertex3f + elements[i*3+2] * 3;
521 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])))
522 shadowmarklist[numshadowmark++] = i;
524 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
527 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)
530 mins[0] = projectorigin[0] - radius;
531 mins[1] = projectorigin[1] - radius;
532 mins[2] = projectorigin[2] - radius;
533 maxs[0] = projectorigin[0] + radius;
534 maxs[1] = projectorigin[1] + radius;
535 maxs[2] = projectorigin[2] + radius;
536 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
539 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
541 GL_VertexPointer(vertex3f);
542 if (r_shadowstage == SHADOWSTAGE_STENCIL)
544 // decrement stencil if frontface is behind depthbuffer
545 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
546 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
547 R_Mesh_Draw(numvertices, numtriangles, element3i);
549 c_rt_shadowtris += numtriangles;
550 // increment stencil if backface is behind depthbuffer
551 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
552 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
554 R_Mesh_Draw(numvertices, numtriangles, element3i);
556 c_rt_shadowtris += numtriangles;
559 void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
562 if (r_shadowstage == SHADOWSTAGE_STENCIL)
564 // decrement stencil if frontface is behind depthbuffer
565 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
566 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
567 for (mesh = firstmesh;mesh;mesh = mesh->next)
569 GL_VertexPointer(mesh->vertex3f);
570 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
571 c_rtcached_shadowmeshes++;
572 c_rtcached_shadowtris += mesh->numtriangles;
574 // increment stencil if backface is behind depthbuffer
575 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
576 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
578 for (mesh = firstmesh;mesh;mesh = mesh->next)
580 GL_VertexPointer(mesh->vertex3f);
581 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
582 c_rtcached_shadowmeshes++;
583 c_rtcached_shadowtris += mesh->numtriangles;
587 float r_shadow_attenpower, r_shadow_attenscale;
588 static void R_Shadow_MakeTextures(void)
590 int x, y, z, d, side;
591 float v[3], s, t, intensity;
593 R_FreeTexturePool(&r_shadow_texturepool);
594 r_shadow_texturepool = R_AllocTexturePool();
595 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
596 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
598 #define ATTEN2DSIZE 64
599 #define ATTEN3DSIZE 32
600 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
605 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
610 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
615 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
616 if (gl_texturecubemap)
618 for (side = 0;side < 6;side++)
620 for (y = 0;y < NORMSIZE;y++)
622 for (x = 0;x < NORMSIZE;x++)
624 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
625 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
659 intensity = 127.0f / sqrt(DotProduct(v, v));
660 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
661 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
662 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
663 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
667 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
670 r_shadow_normalcubetexture = NULL;
671 for (y = 0;y < ATTEN2DSIZE;y++)
673 for (x = 0;x < ATTEN2DSIZE;x++)
675 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
676 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
678 intensity = 1.0f - sqrt(DotProduct(v, v));
680 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
681 d = bound(0, intensity, 255);
682 data[(y*ATTEN2DSIZE+x)*4+0] = d;
683 data[(y*ATTEN2DSIZE+x)*4+1] = d;
684 data[(y*ATTEN2DSIZE+x)*4+2] = d;
685 data[(y*ATTEN2DSIZE+x)*4+3] = d;
688 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
689 if (r_shadow_texture3d.integer)
691 for (z = 0;z < ATTEN3DSIZE;z++)
693 for (y = 0;y < ATTEN3DSIZE;y++)
695 for (x = 0;x < ATTEN3DSIZE;x++)
697 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
698 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
699 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
700 intensity = 1.0f - sqrt(DotProduct(v, v));
702 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
703 d = bound(0, intensity, 255);
704 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
705 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
706 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
707 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
711 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
716 void R_Shadow_Stage_Begin(void)
720 if (r_shadow_texture3d.integer && !gl_texture3d)
721 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
723 if (!r_shadow_attenuation2dtexture
724 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
725 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
726 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
727 R_Shadow_MakeTextures();
729 memset(&m, 0, sizeof(m));
730 GL_BlendFunc(GL_ONE, GL_ZERO);
733 R_Mesh_State_Texture(&m);
734 GL_Color(0, 0, 0, 1);
735 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
736 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
737 r_shadowstage = SHADOWSTAGE_NONE;
739 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
740 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
741 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
744 void R_Shadow_LoadWorldLightsIfNeeded(void)
746 if (r_shadow_reloadlights && cl.worldmodel)
748 R_Shadow_ClearWorldLights();
749 r_shadow_reloadlights = false;
750 R_Shadow_LoadWorldLights();
751 if (r_shadow_worldlightchain == NULL)
753 R_Shadow_LoadLightsFile();
754 if (r_shadow_worldlightchain == NULL)
755 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
760 void R_Shadow_Stage_ShadowVolumes(void)
763 memset(&m, 0, sizeof(m));
764 R_Mesh_State_Texture(&m);
765 GL_Color(1, 1, 1, 1);
766 GL_ColorMask(0, 0, 0, 0);
767 GL_BlendFunc(GL_ONE, GL_ZERO);
770 qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
771 //if (r_shadow_polygonoffset.value != 0)
773 // qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
774 // qglEnable(GL_POLYGON_OFFSET_FILL);
777 // qglDisable(GL_POLYGON_OFFSET_FILL);
778 qglDepthFunc(GL_LESS);
779 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
780 qglEnable(GL_STENCIL_TEST);
781 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
782 qglStencilFunc(GL_ALWAYS, 128, 0xFF);
783 r_shadowstage = SHADOWSTAGE_STENCIL;
784 GL_Clear(GL_STENCIL_BUFFER_BIT);
786 // LordHavoc note: many shadow volumes reside entirely inside the world
787 // (that is to say they are entirely bounded by their lit surfaces),
788 // which can be optimized by handling things as an inverted light volume,
789 // with the shadow boundaries of the world being simulated by an altered
790 // (129) bias to stencil clearing on such lights
791 // FIXME: generate inverted light volumes for use as shadow volumes and
792 // optimize for them as noted above
795 void R_Shadow_Stage_LightWithoutShadows(void)
798 memset(&m, 0, sizeof(m));
799 R_Mesh_State_Texture(&m);
800 GL_BlendFunc(GL_ONE, GL_ONE);
803 qglPolygonOffset(0, 0);
804 //qglDisable(GL_POLYGON_OFFSET_FILL);
805 GL_Color(1, 1, 1, 1);
806 GL_ColorMask(1, 1, 1, 1);
807 qglDepthFunc(GL_EQUAL);
808 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
809 qglDisable(GL_STENCIL_TEST);
810 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
811 qglStencilFunc(GL_EQUAL, 128, 0xFF);
812 r_shadowstage = SHADOWSTAGE_LIGHT;
816 void R_Shadow_Stage_LightWithShadows(void)
819 memset(&m, 0, sizeof(m));
820 R_Mesh_State_Texture(&m);
821 GL_BlendFunc(GL_ONE, GL_ONE);
824 qglPolygonOffset(0, 0);
825 //qglDisable(GL_POLYGON_OFFSET_FILL);
826 GL_Color(1, 1, 1, 1);
827 GL_ColorMask(1, 1, 1, 1);
828 qglDepthFunc(GL_EQUAL);
829 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
830 qglEnable(GL_STENCIL_TEST);
831 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
832 // only draw light where this geometry was already rendered AND the
833 // stencil is 128 (values other than this mean shadow)
834 qglStencilFunc(GL_EQUAL, 128, 0xFF);
835 r_shadowstage = SHADOWSTAGE_LIGHT;
839 void R_Shadow_Stage_End(void)
842 memset(&m, 0, sizeof(m));
843 R_Mesh_State_Texture(&m);
844 GL_BlendFunc(GL_ONE, GL_ZERO);
847 qglPolygonOffset(0, 0);
848 //qglDisable(GL_POLYGON_OFFSET_FILL);
849 GL_Color(1, 1, 1, 1);
850 GL_ColorMask(1, 1, 1, 1);
851 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
852 qglDepthFunc(GL_LEQUAL);
853 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
854 qglDisable(GL_STENCIL_TEST);
855 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
856 qglStencilFunc(GL_ALWAYS, 128, 0xFF);
857 r_shadowstage = SHADOWSTAGE_NONE;
860 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
862 int i, ix1, iy1, ix2, iy2;
863 float x1, y1, x2, y2, x, y, f;
866 if (!r_shadow_scissor.integer)
868 // if view is inside the box, just say yes it's visible
869 // LordHavoc: for some odd reason scissor seems broken without stencil
870 // (?!? seems like a driver bug) so abort if gl_stencil is false
871 if (!gl_stencil || BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
873 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
876 for (i = 0;i < 3;i++)
878 if (r_viewforward[i] >= 0)
889 f = DotProduct(r_viewforward, r_vieworigin) + 1;
890 if (DotProduct(r_viewforward, v2) <= f)
892 // entirely behind nearclip plane
895 if (DotProduct(r_viewforward, v) >= f)
897 // entirely infront of nearclip plane
898 x1 = y1 = x2 = y2 = 0;
899 for (i = 0;i < 8;i++)
901 v[0] = (i & 1) ? mins[0] : maxs[0];
902 v[1] = (i & 2) ? mins[1] : maxs[1];
903 v[2] = (i & 4) ? mins[2] : maxs[2];
905 GL_TransformToScreen(v, v2);
906 //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]);
925 // clipped by nearclip plane
926 // this is nasty and crude...
927 // create viewspace bbox
928 for (i = 0;i < 8;i++)
930 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
931 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
932 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
933 v2[0] = -DotProduct(v, r_viewleft);
934 v2[1] = DotProduct(v, r_viewup);
935 v2[2] = DotProduct(v, r_viewforward);
938 if (smins[0] > v2[0]) smins[0] = v2[0];
939 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
940 if (smins[1] > v2[1]) smins[1] = v2[1];
941 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
942 if (smins[2] > v2[2]) smins[2] = v2[2];
943 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
947 smins[0] = smaxs[0] = v2[0];
948 smins[1] = smaxs[1] = v2[1];
949 smins[2] = smaxs[2] = v2[2];
952 // now we have a bbox in viewspace
953 // clip it to the view plane
956 // return true if that culled the box
957 if (smins[2] >= smaxs[2])
959 // ok some of it is infront of the view, transform each corner back to
960 // worldspace and then to screenspace and make screen rect
961 // initialize these variables just to avoid compiler warnings
962 x1 = y1 = x2 = y2 = 0;
963 for (i = 0;i < 8;i++)
965 v2[0] = (i & 1) ? smins[0] : smaxs[0];
966 v2[1] = (i & 2) ? smins[1] : smaxs[1];
967 v2[2] = (i & 4) ? smins[2] : smaxs[2];
968 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
969 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
970 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
972 GL_TransformToScreen(v, v2);
973 //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]);
990 // this code doesn't handle boxes with any points behind view properly
991 x1 = 1000;x2 = -1000;
992 y1 = 1000;y2 = -1000;
993 for (i = 0;i < 8;i++)
995 v[0] = (i & 1) ? mins[0] : maxs[0];
996 v[1] = (i & 2) ? mins[1] : maxs[1];
997 v[2] = (i & 4) ? mins[2] : maxs[2];
999 GL_TransformToScreen(v, v2);
1000 //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 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1019 if (ix1 < r_view_x) ix1 = r_view_x;
1020 if (iy1 < r_view_y) iy1 = r_view_y;
1021 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1022 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1023 if (ix2 <= ix1 || iy2 <= iy1)
1025 // set up the scissor rectangle
1026 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1027 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1028 //qglEnable(GL_SCISSOR_TEST);
1033 void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1035 float *color4f = varray_color4f;
1036 float dist, dot, intensity, v[3], n[3];
1037 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1039 Matrix4x4_Transform(m, vertex3f, v);
1040 if ((dist = DotProduct(v, v)) < 1)
1042 Matrix4x4_Transform3x3(m, normal3f, n);
1043 if ((dot = DotProduct(n, v)) > 0)
1046 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1047 VectorScale(lightcolor, intensity, color4f);
1052 VectorClear(color4f);
1058 VectorClear(color4f);
1064 void R_Shadow_VertexLightingWithXYAttenuationTexture(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1066 float *color4f = varray_color4f;
1067 float dist, dot, intensity, v[3], n[3];
1068 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1070 Matrix4x4_Transform(m, vertex3f, v);
1071 if ((dist = fabs(v[2])) < 1)
1073 Matrix4x4_Transform3x3(m, normal3f, n);
1074 if ((dot = DotProduct(n, v)) > 0)
1076 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1077 VectorScale(lightcolor, intensity, color4f);
1082 VectorClear(color4f);
1088 VectorClear(color4f);
1094 // FIXME: this should be done in a vertex program when possible
1095 // FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
1096 void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1100 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1101 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1102 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1109 void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1113 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1114 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1121 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)
1125 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1127 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1128 // the cubemap normalizes this for us
1129 out3f[0] = DotProduct(svector3f, lightdir);
1130 out3f[1] = DotProduct(tvector3f, lightdir);
1131 out3f[2] = DotProduct(normal3f, lightdir);
1135 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)
1138 float lightdir[3], eyedir[3], halfdir[3];
1139 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1141 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1142 VectorNormalizeFast(lightdir);
1143 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1144 VectorNormalizeFast(eyedir);
1145 VectorAdd(lightdir, eyedir, halfdir);
1146 // the cubemap normalizes this for us
1147 out3f[0] = DotProduct(svector3f, halfdir);
1148 out3f[1] = DotProduct(tvector3f, halfdir);
1149 out3f[2] = DotProduct(normal3f, halfdir);
1153 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)
1156 float color[3], color2[3];
1158 GL_VertexPointer(vertex3f);
1159 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1162 bumptexture = r_shadow_blankbumptexture;
1164 // colorscale accounts for how much we multiply the brightness during combine
1165 // mult is how many times the final pass of the lighting will be
1166 // performed to get more brightness than otherwise possible
1167 // limit mult to 64 for sanity sake
1168 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1170 // 3/2 3D combine path (Geforce3, Radeon 8500)
1171 memset(&m, 0, sizeof(m));
1172 m.tex[0] = R_GetTexture(bumptexture);
1173 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1174 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1175 m.texcombinergb[0] = GL_REPLACE;
1176 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1177 m.pointer_texcoord[0] = texcoord2f;
1178 m.pointer_texcoord[1] = varray_texcoord3f[1];
1179 m.pointer_texcoord[2] = varray_texcoord3f[2];
1180 R_Mesh_State_Texture(&m);
1181 GL_ColorMask(0,0,0,1);
1182 GL_BlendFunc(GL_ONE, GL_ZERO);
1183 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1184 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1185 R_Mesh_Draw(numverts, numtriangles, elements);
1187 c_rt_lighttris += numtriangles;
1189 memset(&m, 0, sizeof(m));
1190 m.tex[0] = R_GetTexture(basetexture);
1191 m.pointer_texcoord[0] = texcoord2f;
1194 m.texcubemap[1] = R_GetTexture(lightcubemap);
1195 m.pointer_texcoord[1] = varray_texcoord3f[1];
1196 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1198 R_Mesh_State_Texture(&m);
1199 GL_ColorMask(1,1,1,0);
1200 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1201 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1202 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1204 color[0] = bound(0, color2[0], 1);
1205 color[1] = bound(0, color2[1], 1);
1206 color[2] = bound(0, color2[2], 1);
1207 GL_Color(color[0], color[1], color[2], 1);
1208 R_Mesh_Draw(numverts, numtriangles, elements);
1210 c_rt_lighttris += numtriangles;
1213 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1215 // 1/2/2 3D combine path (original Radeon)
1216 memset(&m, 0, sizeof(m));
1217 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1218 m.pointer_texcoord[0] = varray_texcoord3f[0];
1219 R_Mesh_State_Texture(&m);
1220 GL_ColorMask(0,0,0,1);
1221 GL_BlendFunc(GL_ONE, GL_ZERO);
1222 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1223 R_Mesh_Draw(numverts, numtriangles, elements);
1225 c_rt_lighttris += numtriangles;
1227 memset(&m, 0, sizeof(m));
1228 m.tex[0] = R_GetTexture(bumptexture);
1229 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1230 m.texcombinergb[0] = GL_REPLACE;
1231 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1232 m.pointer_texcoord[0] = texcoord2f;
1233 m.pointer_texcoord[1] = varray_texcoord3f[1];
1234 R_Mesh_State_Texture(&m);
1235 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1236 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1237 R_Mesh_Draw(numverts, numtriangles, elements);
1239 c_rt_lighttris += numtriangles;
1241 memset(&m, 0, sizeof(m));
1242 m.tex[0] = R_GetTexture(basetexture);
1243 m.pointer_texcoord[0] = texcoord2f;
1246 m.texcubemap[1] = R_GetTexture(lightcubemap);
1247 m.pointer_texcoord[1] = varray_texcoord3f[1];
1248 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1250 R_Mesh_State_Texture(&m);
1251 GL_ColorMask(1,1,1,0);
1252 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1253 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1254 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1256 color[0] = bound(0, color2[0], 1);
1257 color[1] = bound(0, color2[1], 1);
1258 color[2] = bound(0, color2[2], 1);
1259 GL_Color(color[0], color[1], color[2], 1);
1260 R_Mesh_Draw(numverts, numtriangles, elements);
1262 c_rt_lighttris += numtriangles;
1265 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1267 // 2/2 3D combine path (original Radeon)
1268 memset(&m, 0, sizeof(m));
1269 m.tex[0] = R_GetTexture(bumptexture);
1270 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1271 m.texcombinergb[0] = GL_REPLACE;
1272 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1273 m.pointer_texcoord[0] = texcoord2f;
1274 m.pointer_texcoord[1] = varray_texcoord3f[1];
1275 R_Mesh_State_Texture(&m);
1276 GL_ColorMask(0,0,0,1);
1277 GL_BlendFunc(GL_ONE, GL_ZERO);
1278 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1279 R_Mesh_Draw(numverts, numtriangles, elements);
1281 c_rt_lighttris += numtriangles;
1283 memset(&m, 0, sizeof(m));
1284 m.tex[0] = R_GetTexture(basetexture);
1285 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1286 m.pointer_texcoord[0] = texcoord2f;
1287 m.pointer_texcoord[1] = varray_texcoord3f[1];
1288 R_Mesh_State_Texture(&m);
1289 GL_ColorMask(1,1,1,0);
1290 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1291 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1292 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1293 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1295 color[0] = bound(0, color2[0], 1);
1296 color[1] = bound(0, color2[1], 1);
1297 color[2] = bound(0, color2[2], 1);
1298 GL_Color(color[0], color[1], color[2], 1);
1299 R_Mesh_Draw(numverts, numtriangles, elements);
1301 c_rt_lighttris += numtriangles;
1304 else if (r_textureunits.integer >= 4)
1306 // 4/2 2D combine path (Geforce3, Radeon 8500)
1307 memset(&m, 0, sizeof(m));
1308 m.tex[0] = R_GetTexture(bumptexture);
1309 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1310 m.texcombinergb[0] = GL_REPLACE;
1311 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1312 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1313 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1314 m.pointer_texcoord[0] = texcoord2f;
1315 m.pointer_texcoord[1] = varray_texcoord3f[1];
1316 m.pointer_texcoord[2] = varray_texcoord2f[2];
1317 m.pointer_texcoord[3] = varray_texcoord2f[3];
1318 R_Mesh_State_Texture(&m);
1319 GL_ColorMask(0,0,0,1);
1320 GL_BlendFunc(GL_ONE, GL_ZERO);
1321 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1322 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1323 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1324 R_Mesh_Draw(numverts, numtriangles, elements);
1326 c_rt_lighttris += numtriangles;
1328 memset(&m, 0, sizeof(m));
1329 m.tex[0] = R_GetTexture(basetexture);
1330 m.pointer_texcoord[0] = texcoord2f;
1333 m.texcubemap[1] = R_GetTexture(lightcubemap);
1334 m.pointer_texcoord[1] = varray_texcoord3f[1];
1335 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1337 R_Mesh_State_Texture(&m);
1338 GL_ColorMask(1,1,1,0);
1339 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1340 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1341 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1343 color[0] = bound(0, color2[0], 1);
1344 color[1] = bound(0, color2[1], 1);
1345 color[2] = bound(0, color2[2], 1);
1346 GL_Color(color[0], color[1], color[2], 1);
1347 R_Mesh_Draw(numverts, numtriangles, elements);
1349 c_rt_lighttris += numtriangles;
1354 // 2/2/2 2D combine path (any dot3 card)
1355 memset(&m, 0, sizeof(m));
1356 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1357 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1358 m.pointer_texcoord[0] = varray_texcoord2f[0];
1359 m.pointer_texcoord[1] = varray_texcoord2f[1];
1360 R_Mesh_State_Texture(&m);
1361 GL_ColorMask(0,0,0,1);
1362 GL_BlendFunc(GL_ONE, GL_ZERO);
1363 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1364 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1365 R_Mesh_Draw(numverts, numtriangles, elements);
1367 c_rt_lighttris += numtriangles;
1369 memset(&m, 0, sizeof(m));
1370 m.tex[0] = R_GetTexture(bumptexture);
1371 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1372 m.texcombinergb[0] = GL_REPLACE;
1373 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1374 m.pointer_texcoord[0] = texcoord2f;
1375 m.pointer_texcoord[1] = varray_texcoord3f[1];
1376 R_Mesh_State_Texture(&m);
1377 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1378 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1379 R_Mesh_Draw(numverts, numtriangles, elements);
1381 c_rt_lighttris += numtriangles;
1383 memset(&m, 0, sizeof(m));
1384 m.tex[0] = R_GetTexture(basetexture);
1385 m.pointer_texcoord[0] = texcoord2f;
1388 m.texcubemap[1] = R_GetTexture(lightcubemap);
1389 m.pointer_texcoord[1] = varray_texcoord3f[1];
1390 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1392 R_Mesh_State_Texture(&m);
1393 GL_ColorMask(1,1,1,0);
1394 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1395 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1396 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1398 color[0] = bound(0, color2[0], 1);
1399 color[1] = bound(0, color2[1], 1);
1400 color[2] = bound(0, color2[2], 1);
1401 GL_Color(color[0], color[1], color[2], 1);
1402 R_Mesh_Draw(numverts, numtriangles, elements);
1404 c_rt_lighttris += numtriangles;
1410 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1411 GL_DepthMask(false);
1413 GL_ColorPointer(varray_color4f);
1414 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1415 memset(&m, 0, sizeof(m));
1416 m.tex[0] = R_GetTexture(basetexture);
1417 m.pointer_texcoord[0] = texcoord2f;
1418 if (r_textureunits.integer >= 2)
1421 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1422 m.pointer_texcoord[1] = varray_texcoord2f[1];
1423 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1425 R_Mesh_State_Texture(&m);
1426 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1428 color[0] = bound(0, color2[0], 1);
1429 color[1] = bound(0, color2[1], 1);
1430 color[2] = bound(0, color2[2], 1);
1431 if (r_textureunits.integer >= 2)
1432 R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1434 R_Shadow_VertexLighting(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1435 R_Mesh_Draw(numverts, numtriangles, elements);
1437 c_rt_lighttris += numtriangles;
1442 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)
1445 float color[3], color2[3], colorscale;
1447 if (!gl_dot3arb || !gl_texturecubemap || !gl_combine.integer || !gl_stencil)
1450 glosstexture = r_shadow_blankglosstexture;
1451 if (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))
1453 colorscale = r_shadow_glossintensity.value;
1455 bumptexture = r_shadow_blankbumptexture;
1456 if (glosstexture == r_shadow_blankglosstexture)
1457 colorscale *= r_shadow_gloss2intensity.value;
1458 GL_VertexPointer(vertex3f);
1460 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1462 // 2/0/0/1/2 3D combine blendsquare path
1463 memset(&m, 0, sizeof(m));
1464 m.tex[0] = R_GetTexture(bumptexture);
1465 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1466 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1467 m.pointer_texcoord[0] = texcoord2f;
1468 m.pointer_texcoord[1] = varray_texcoord3f[1];
1469 R_Mesh_State_Texture(&m);
1470 GL_ColorMask(0,0,0,1);
1471 // this squares the result
1472 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1473 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1474 R_Mesh_Draw(numverts, numtriangles, elements);
1476 c_rt_lighttris += numtriangles;
1478 memset(&m, 0, sizeof(m));
1479 R_Mesh_State_Texture(&m);
1480 // square alpha in framebuffer a few times to make it shiny
1481 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1482 // these comments are a test run through this math for intensity 0.5
1483 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1484 // 0.25 * 0.25 = 0.0625 (this is another pass)
1485 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1486 R_Mesh_Draw(numverts, numtriangles, elements);
1488 c_rt_lighttris += numtriangles;
1489 R_Mesh_Draw(numverts, numtriangles, elements);
1491 c_rt_lighttris += numtriangles;
1493 memset(&m, 0, sizeof(m));
1494 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1495 m.pointer_texcoord[0] = varray_texcoord3f[0];
1496 R_Mesh_State_Texture(&m);
1497 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1498 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1499 R_Mesh_Draw(numverts, numtriangles, elements);
1501 c_rt_lighttris += numtriangles;
1503 memset(&m, 0, sizeof(m));
1504 m.tex[0] = R_GetTexture(glosstexture);
1507 m.texcubemap[1] = R_GetTexture(lightcubemap);
1508 m.pointer_texcoord[1] = varray_texcoord3f[1];
1509 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1511 m.pointer_texcoord[0] = texcoord2f;
1512 R_Mesh_State_Texture(&m);
1513 GL_ColorMask(1,1,1,0);
1514 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1515 VectorScale(lightcolor, colorscale, color2);
1516 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1518 color[0] = bound(0, color2[0], 1);
1519 color[1] = bound(0, color2[1], 1);
1520 color[2] = bound(0, color2[2], 1);
1521 GL_Color(color[0], color[1], color[2], 1);
1522 R_Mesh_Draw(numverts, numtriangles, elements);
1524 c_rt_lighttris += numtriangles;
1527 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1529 // 2/0/0/2 3D combine blendsquare path
1530 memset(&m, 0, sizeof(m));
1531 m.tex[0] = R_GetTexture(bumptexture);
1532 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1533 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1534 m.pointer_texcoord[0] = texcoord2f;
1535 m.pointer_texcoord[1] = varray_texcoord3f[1];
1536 R_Mesh_State_Texture(&m);
1537 GL_ColorMask(0,0,0,1);
1538 // this squares the result
1539 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1540 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1541 R_Mesh_Draw(numverts, numtriangles, elements);
1543 c_rt_lighttris += numtriangles;
1545 memset(&m, 0, sizeof(m));
1546 R_Mesh_State_Texture(&m);
1547 // square alpha in framebuffer a few times to make it shiny
1548 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1549 // these comments are a test run through this math for intensity 0.5
1550 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1551 // 0.25 * 0.25 = 0.0625 (this is another pass)
1552 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1553 R_Mesh_Draw(numverts, numtriangles, elements);
1555 c_rt_lighttris += numtriangles;
1556 R_Mesh_Draw(numverts, numtriangles, elements);
1558 c_rt_lighttris += numtriangles;
1560 memset(&m, 0, sizeof(m));
1561 m.tex[0] = R_GetTexture(glosstexture);
1562 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1563 m.pointer_texcoord[0] = texcoord2f;
1564 m.pointer_texcoord[1] = varray_texcoord3f[1];
1565 R_Mesh_State_Texture(&m);
1566 GL_ColorMask(1,1,1,0);
1567 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1568 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1569 VectorScale(lightcolor, colorscale, color2);
1570 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1572 color[0] = bound(0, color2[0], 1);
1573 color[1] = bound(0, color2[1], 1);
1574 color[2] = bound(0, color2[2], 1);
1575 GL_Color(color[0], color[1], color[2], 1);
1576 R_Mesh_Draw(numverts, numtriangles, elements);
1578 c_rt_lighttris += numtriangles;
1581 else if (r_textureunits.integer >= 2 /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1583 // 2/0/0/2/2 2D combine blendsquare path
1584 memset(&m, 0, sizeof(m));
1585 m.tex[0] = R_GetTexture(bumptexture);
1586 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1587 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1588 m.pointer_texcoord[0] = texcoord2f;
1589 m.pointer_texcoord[1] = varray_texcoord3f[1];
1590 R_Mesh_State_Texture(&m);
1591 GL_ColorMask(0,0,0,1);
1592 // this squares the result
1593 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1594 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1595 R_Mesh_Draw(numverts, numtriangles, elements);
1597 c_rt_lighttris += numtriangles;
1599 memset(&m, 0, sizeof(m));
1600 R_Mesh_State_Texture(&m);
1601 // square alpha in framebuffer a few times to make it shiny
1602 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1603 // these comments are a test run through this math for intensity 0.5
1604 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1605 // 0.25 * 0.25 = 0.0625 (this is another pass)
1606 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1607 R_Mesh_Draw(numverts, numtriangles, elements);
1609 c_rt_lighttris += numtriangles;
1610 R_Mesh_Draw(numverts, numtriangles, elements);
1612 c_rt_lighttris += numtriangles;
1614 memset(&m, 0, sizeof(m));
1615 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1616 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1617 m.pointer_texcoord[0] = varray_texcoord2f[0];
1618 m.pointer_texcoord[1] = varray_texcoord2f[1];
1619 R_Mesh_State_Texture(&m);
1620 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1621 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1622 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1623 R_Mesh_Draw(numverts, numtriangles, elements);
1625 c_rt_lighttris += numtriangles;
1627 memset(&m, 0, sizeof(m));
1628 m.tex[0] = R_GetTexture(glosstexture);
1631 m.texcubemap[1] = R_GetTexture(lightcubemap);
1632 m.pointer_texcoord[1] = varray_texcoord3f[1];
1633 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1635 m.pointer_texcoord[0] = texcoord2f;
1636 R_Mesh_State_Texture(&m);
1637 GL_ColorMask(1,1,1,0);
1638 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1639 VectorScale(lightcolor, colorscale, color2);
1640 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1642 color[0] = bound(0, color2[0], 1);
1643 color[1] = bound(0, color2[1], 1);
1644 color[2] = bound(0, color2[2], 1);
1645 GL_Color(color[0], color[1], color[2], 1);
1646 R_Mesh_Draw(numverts, numtriangles, elements);
1648 c_rt_lighttris += numtriangles;
1654 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1658 R_RTLight_Uncompile(rtlight);
1659 memset(rtlight, 0, sizeof(*rtlight));
1661 VectorCopy(light->origin, rtlight->shadoworigin);
1662 VectorCopy(light->color, rtlight->color);
1663 rtlight->radius = light->radius;
1664 rtlight->cullradius = rtlight->radius;
1665 rtlight->cullradius2 = rtlight->cullradius * rtlight->cullradius;
1666 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->cullradius;
1667 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->cullradius;
1668 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->cullradius;
1669 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->cullradius;
1670 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->cullradius;
1671 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->cullradius;
1672 rtlight->cubemapname[0] = 0;
1673 if (light->cubemapname[0])
1674 strcpy(rtlight->cubemapname, light->cubemapname);
1675 else if (light->cubemapnum > 0)
1676 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1677 rtlight->shadow = light->shadow;
1678 rtlight->corona = light->corona;
1679 rtlight->style = light->style;
1680 rtlight->isstatic = isstatic;
1681 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1682 // ConcatScale won't work here because this needs to scale rotate and
1683 // translate, not just rotate
1684 scale = 1.0f / rtlight->radius;
1685 for (k = 0;k < 3;k++)
1686 for (j = 0;j < 4;j++)
1687 rtlight->matrix_worldtolight.m[k][j] *= scale;
1688 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1689 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1691 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1692 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1693 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.25f, rtlight->lightmap_light);
1694 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1697 // compiles rtlight geometry
1698 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1699 void R_RTLight_Compile(rtlight_t *rtlight)
1701 int i, j, k, l, maxverts = 256, tris;
1702 float *vertex3f = NULL, mins[3], maxs[3];
1703 shadowmesh_t *mesh, *castmesh = NULL;
1705 qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8];
1706 qbyte lightfullpvs[(MAX_MAP_LEAFS + 7)/ 8];
1708 // compile the light
1709 rtlight->compiled = true;
1710 VectorCopy(rtlight->cullmins, mins);
1711 VectorCopy(rtlight->cullmaxs, maxs);
1712 if (rtlight->shadow)
1713 castmesh = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1714 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1717 lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, rtlight->shadoworigin, 0, lightfullpvs, sizeof(lightfullpvs));
1718 memset(lightpvs, 0, lightpvsbytes);
1719 if (cl.worldmodel->brushq3.num_leafs)
1724 // make a pvs that only includes things within the box
1725 for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
1726 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1727 SETPVSBIT(lightpvs, leaf->clusterindex);
1729 // make a cluster list for fast visibility checking during rendering
1730 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1731 if (CHECKPVSBIT(lightpvs, i))
1732 rtlight->static_numclusters++;
1733 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1734 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1735 if (CHECKPVSBIT(lightpvs, i))
1736 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1738 VectorCopy(rtlight->shadoworigin, rtlight->cullmins);
1739 VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs);
1740 for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
1741 face->lighttemp_castshadow = false;
1742 for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
1744 if (CHECKPVSBIT(lightpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1746 for (k = 0;k < 3;k++)
1748 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1749 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1751 for (j = 0;j < leaf->numleaffaces;j++)
1753 face = leaf->firstleafface[j];
1754 if (BoxesOverlap(face->mins, face->maxs, mins, maxs))
1755 face->lighttemp_castshadow = true;
1760 // add surfaces to shadow casting mesh and light mesh
1761 for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
1763 if (face->lighttemp_castshadow)
1765 face->lighttemp_castshadow = false;
1766 if (!(face->texture->surfaceflags & (Q3SURFACEFLAG_NODRAW | Q3SURFACEFLAG_SKY)))
1768 if (rtlight->shadow)
1769 if (!(face->texture->nativecontents & CONTENTSQ3_TRANSLUCENT))
1770 Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, face->data_vertex3f, NULL, NULL, NULL, NULL, face->num_triangles, face->data_element3i);
1771 if (!(face->texture->surfaceflags & Q3SURFACEFLAG_SKY))
1772 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);
1777 else if (cl.worldmodel->brushq1.num_leafs)
1781 VectorCopy(rtlight->shadoworigin, rtlight->cullmins);
1782 VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs);
1783 i = CL_PointQ1Contents(rtlight->shadoworigin);
1785 for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
1786 surf->lighttemp_castshadow = false;
1788 if (r_shadow_portallight.integer && i != CONTENTS_SOLID && i != CONTENTS_SKY)
1791 qbyte *bytesurfacepvs;
1793 byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.num_leafs);
1794 bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numsurfaces);
1796 Portal_Visibility(cl.worldmodel, rtlight->shadoworigin, byteleafpvs, bytesurfacepvs, NULL, 0, true, mins, maxs, rtlight->cullmins, rtlight->cullmaxs);
1798 // make a pvs that only includes things within the box
1799 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1801 if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1803 SETPVSBIT(lightpvs, leaf->clusterindex);
1804 for (k = 0;k < 3;k++)
1806 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1807 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1812 for (i = 0, surf = cl.worldmodel->brushq1.surfaces;i < cl.worldmodel->brushq1.numsurfaces;i++, surf++)
1813 if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
1814 surf->lighttemp_castshadow = true;
1816 Mem_Free(byteleafpvs);
1817 Mem_Free(bytesurfacepvs);
1819 // make a cluster list for fast visibility checking during rendering
1820 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1821 if (CHECKPVSBIT(lightpvs, i))
1822 rtlight->static_numclusters++;
1823 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1824 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1825 if (CHECKPVSBIT(lightpvs, i))
1826 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1830 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1832 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1834 // make a pvs that only includes things within the box
1835 SETPVSBIT(lightpvs, leaf->clusterindex);
1836 for (k = 0;k < 3;k++)
1838 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1839 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1841 for (j = 0;j < leaf->nummarksurfaces;j++)
1843 surf = cl.worldmodel->brushq1.surfaces + leaf->firstmarksurface[j];
1844 if (!surf->lighttemp_castshadow && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
1845 surf->lighttemp_castshadow = true;
1850 // make a pvs that only includes things within the box
1851 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1852 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1853 SETPVSBIT(lightpvs, leaf->clusterindex);
1855 // make a cluster list for fast visibility checking during rendering
1856 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1857 if (CHECKPVSBIT(lightpvs, i))
1858 rtlight->static_numclusters++;
1859 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1860 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1861 if (CHECKPVSBIT(lightpvs, i))
1862 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1865 // add surfaces to shadow casting mesh and light mesh
1866 for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
1868 if (surf->lighttemp_castshadow)
1870 surf->lighttemp_castshadow = false;
1871 if (rtlight->shadow && (surf->flags & SURF_SHADOWCAST))
1872 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);
1873 if (!(surf->flags & SURF_DRAWSKY))
1874 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);
1880 // limit box to light bounds (in case it grew larger)
1881 for (k = 0;k < 3;k++)
1883 if (rtlight->cullmins[k] < rtlight->shadoworigin[k] - rtlight->radius) rtlight->cullmins[k] = rtlight->shadoworigin[k] - rtlight->radius;
1884 if (rtlight->cullmaxs[k] > rtlight->shadoworigin[k] + rtlight->radius) rtlight->cullmaxs[k] = rtlight->shadoworigin[k] + rtlight->radius;
1886 rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1887 rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1889 // cast shadow volume from castmesh
1890 castmesh = Mod_ShadowMesh_Finish(r_shadow_mempool, castmesh, false, true);
1894 for (mesh = castmesh;mesh;mesh = mesh->next)
1896 R_Shadow_ResizeShadowElements(mesh->numtriangles);
1897 maxverts = max(maxverts, mesh->numverts * 2);
1902 vertex3f = Mem_Alloc(r_shadow_mempool, maxverts * sizeof(float[3]));
1903 // now that we have the buffers big enough, construct and add
1904 // the shadow volume mesh
1905 if (rtlight->shadow)
1906 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1907 for (mesh = castmesh;mesh;mesh = mesh->next)
1909 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1910 R_Shadow_PrepareShadowMark(mesh->numtriangles);
1911 for (i = 0;i < mesh->numtriangles;i++)
1914 v[0] = mesh->vertex3f + mesh->element3i[i*3+0] * 3;
1915 v[1] = mesh->vertex3f + mesh->element3i[i*3+1] * 3;
1916 v[2] = mesh->vertex3f + mesh->element3i[i*3+2] * 3;
1917 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])))
1918 shadowmarklist[numshadowmark++] = i;
1920 if (maxshadowelements < numshadowmark * 24)
1921 R_Shadow_ResizeShadowElements((numshadowmark + 256) * 24);
1922 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)))
1923 Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1928 // we're done with castmesh now
1929 Mod_ShadowMesh_Free(castmesh);
1932 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1933 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1936 if (rtlight->static_meshchain_shadow)
1937 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1938 k += mesh->numtriangles;
1940 if (rtlight->static_meshchain_light)
1941 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1942 l += mesh->numtriangles;
1943 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);
1946 void R_RTLight_Uncompile(rtlight_t *rtlight)
1948 if (rtlight->compiled)
1950 if (rtlight->static_meshchain_shadow)
1951 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1952 rtlight->static_meshchain_shadow = NULL;
1953 if (rtlight->static_meshchain_light)
1954 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1955 rtlight->static_meshchain_light = NULL;
1956 if (rtlight->static_clusterindices)
1957 Mem_Free(rtlight->static_clusterindices);
1958 rtlight->static_clusterindices = NULL;
1959 rtlight->static_numclusters = 0;
1960 rtlight->compiled = false;
1964 int shadowframecount = 0;
1966 void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t shadoworigin, vec_t shadowradius, vec3_t cullmins, vec3_t cullmaxs)
1969 if ((BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) || !r_shadow_cull.integer) && (ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume)
1971 vec3_t relativeshadoworigin;
1972 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativeshadoworigin);
1973 ent->model->DrawShadowVolume (ent, relativeshadoworigin, shadowradius);
1977 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
1979 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
1982 entity_render_t *ent;
1984 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
1985 rtexture_t *cubemaptexture;
1986 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
1988 if (d_lightstylevalue[rtlight->style] <= 0)
1990 if (rtlight->compiled)
1992 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
1994 for (i = 0;i < rtlight->static_numclusters;i++)
1995 if (CHECKPVSBIT(r_pvsbits, rtlight->static_clusterindices[i]))
1997 if (i == rtlight->static_numclusters)
2000 else if (VIS_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2002 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2005 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2006 R_RTLight_Compile(rtlight);
2008 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2009 VectorScale(rtlight->color, f, lightcolor);
2011 if (rtlight->selected)
2013 f = 2 + sin(realtime * M_PI * 4.0);
2014 VectorScale(lightcolor, f, lightcolor);
2018 if (rtlight->cubemapname[0])
2019 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2021 cubemaptexture = NULL;
2023 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_worldshadows.integer : r_shadow_dlightshadows.integer);
2024 if (shadow && (gl_stencil || visiblevolumes))
2026 if (!visiblevolumes)
2027 R_Shadow_Stage_ShadowVolumes();
2028 ent = &cl_entities[0].render;
2029 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2031 R_Mesh_Matrix(&ent->matrix);
2032 if (r_shadow_showtris.integer)
2036 int depthenabled = qglIsEnabled(GL_DEPTH_TEST);
2037 int stencilenabled = qglIsEnabled(GL_STENCIL_TEST);
2038 qglDisable(GL_DEPTH_TEST);
2039 qglDisable(GL_STENCIL_TEST);
2040 //qglDisable(GL_CULL_FACE);
2041 GL_ColorMask(1,1,1,1);
2042 memset(&m, 0, sizeof(m));
2043 R_Mesh_State_Texture(&m);
2044 GL_Color(0,0.1,0,1);
2045 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2046 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2048 GL_VertexPointer(mesh->vertex3f);
2049 R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i);
2051 //qglEnable(GL_CULL_FACE);
2053 qglEnable(GL_DEPTH_TEST);
2056 qglEnable(GL_STENCIL_TEST);
2057 GL_ColorMask(0,0,0,0);
2060 R_Shadow_RenderShadowMeshVolume(rtlight->static_meshchain_shadow);
2063 R_TestAndDrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs);
2064 if (r_drawentities.integer)
2065 for (i = 0;i < r_refdef.numentities;i++)
2066 if (r_refdef.entities[i]->flags & RENDER_SHADOW)
2067 R_TestAndDrawShadowVolume(r_refdef.entities[i], rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs);
2070 if (!visiblevolumes)
2072 if (shadow && gl_stencil)
2073 R_Shadow_Stage_LightWithShadows();
2075 R_Shadow_Stage_LightWithoutShadows();
2077 ent = &cl_entities[0].render;
2078 if (ent->model && ent->model->DrawLight)
2080 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2081 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2082 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2083 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2084 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2085 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2087 //R_Shadow_DrawStaticWorldLight_Light(rtlight, &ent->matrix, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2089 R_Mesh_Matrix(&ent->matrix);
2090 if (r_shadow_showtris.integer)
2093 int depthenabled = qglIsEnabled(GL_DEPTH_TEST);
2094 int stencilenabled = qglIsEnabled(GL_STENCIL_TEST);
2095 qglDisable(GL_DEPTH_TEST);
2096 qglDisable(GL_STENCIL_TEST);
2097 //qglDisable(GL_CULL_FACE);
2098 memset(&m, 0, sizeof(m));
2099 R_Mesh_State_Texture(&m);
2100 GL_Color(0.2,0,0,1);
2101 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2102 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2104 GL_VertexPointer(mesh->vertex3f);
2105 R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i);
2107 //qglEnable(GL_CULL_FACE);
2109 qglEnable(GL_DEPTH_TEST);
2111 qglEnable(GL_STENCIL_TEST);
2113 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2115 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);
2116 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);
2120 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2122 if (r_drawentities.integer)
2124 for (i = 0;i < r_refdef.numentities;i++)
2126 ent = r_refdef.entities[i];
2127 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
2128 && BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2129 && (ent->flags & RENDER_LIGHT))
2131 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2132 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2133 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2134 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2135 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2136 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2143 void R_ShadowVolumeLighting(int visiblevolumes)
2151 memset(&m, 0, sizeof(m));
2152 R_Mesh_State_Texture(&m);
2154 GL_BlendFunc(GL_ONE, GL_ONE);
2155 GL_DepthMask(false);
2156 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2157 qglDisable(GL_CULL_FACE);
2158 GL_Color(0.0, 0.0125, 0.1, 1);
2161 R_Shadow_Stage_Begin();
2163 if (r_shadow_realtime_world.integer)
2165 R_Shadow_LoadWorldLightsIfNeeded();
2166 if (r_shadow_debuglight.integer >= 0)
2168 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2169 if (lnum == r_shadow_debuglight.integer)
2170 R_DrawRTLight(&light->rtlight, visiblevolumes);
2173 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2174 R_DrawRTLight(&light->rtlight, visiblevolumes);
2176 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2177 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2178 R_DrawRTLight(&light->rtlight, visiblevolumes);
2182 qglEnable(GL_CULL_FACE);
2183 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2186 R_Shadow_Stage_End();
2189 cvar_t r_editlights = {0, "r_editlights", "0"};
2190 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
2191 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
2192 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
2193 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
2194 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
2195 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
2196 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
2197 dlight_t *r_shadow_worldlightchain;
2198 dlight_t *r_shadow_selectedlight;
2199 vec3_t r_editlights_cursorlocation;
2201 typedef struct cubemapinfo_s
2204 rtexture_t *texture;
2208 #define MAX_CUBEMAPS 128
2209 static int numcubemaps;
2210 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
2212 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2213 typedef struct suffixinfo_s
2216 int flipx, flipy, flipdiagonal;
2219 static suffixinfo_t suffix[3][6] =
2222 {"posx", false, false, false},
2223 {"negx", false, false, false},
2224 {"posy", false, false, false},
2225 {"negy", false, false, false},
2226 {"posz", false, false, false},
2227 {"negz", false, false, false}
2230 {"px", false, false, false},
2231 {"nx", false, false, false},
2232 {"py", false, false, false},
2233 {"ny", false, false, false},
2234 {"pz", false, false, false},
2235 {"nz", false, false, false}
2238 {"ft", true, false, true},
2239 {"bk", false, true, true},
2240 {"lf", true, true, false},
2241 {"rt", false, false, false},
2242 {"up", false, false, false},
2243 {"dn", false, false, false}
2247 static int componentorder[4] = {0, 1, 2, 3};
2249 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2251 int i, j, cubemapsize;
2252 qbyte *cubemappixels, *image_rgba;
2253 rtexture_t *cubemaptexture;
2255 // must start 0 so the first loadimagepixels has no requested width/height
2257 cubemappixels = NULL;
2258 cubemaptexture = NULL;
2259 for (j = 0;j < 3 && !cubemappixels;j++)
2261 for (i = 0;i < 6;i++)
2263 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2264 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2266 if (image_width == image_height)
2268 if (!cubemappixels && image_width >= 1)
2270 cubemapsize = image_width;
2271 // note this clears to black, so unavailable sizes are black
2272 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2275 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);
2278 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2279 Mem_Free(image_rgba);
2285 if (!r_shadow_filters_texturepool)
2286 r_shadow_filters_texturepool = R_AllocTexturePool();
2287 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2288 Mem_Free(cubemappixels);
2292 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2293 for (j = 0;j < 3;j++)
2294 for (i = 0;i < 6;i++)
2295 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2296 Con_Printf(" and was unable to find any of them.\n");
2298 return cubemaptexture;
2301 rtexture_t *R_Shadow_Cubemap(const char *basename)
2304 for (i = 0;i < numcubemaps;i++)
2305 if (!strcasecmp(cubemaps[i].basename, basename))
2306 return cubemaps[i].texture;
2307 if (i >= MAX_CUBEMAPS)
2310 strcpy(cubemaps[i].basename, basename);
2311 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2312 return cubemaps[i].texture;
2315 void R_Shadow_FreeCubemaps(void)
2318 R_FreeTexturePool(&r_shadow_filters_texturepool);
2321 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)
2325 if (radius < 15 || DotProduct(color, color) < 0.03)
2327 Con_Printf("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2331 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2332 VectorCopy(origin, light->origin);
2333 VectorCopy(angles, light->angles);
2334 VectorCopy(color, light->color);
2335 light->radius = radius;
2336 light->style = style;
2337 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2339 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2342 light->shadow = shadowenable;
2343 light->corona = corona;
2344 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2345 strcpy(light->cubemapname, cubemapname);
2346 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2347 light->next = r_shadow_worldlightchain;
2348 r_shadow_worldlightchain = light;
2350 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2351 if (r_shadow_staticworldlights.integer)
2352 R_RTLight_Compile(&light->rtlight);
2355 void R_Shadow_FreeWorldLight(dlight_t *light)
2357 dlight_t **lightpointer;
2358 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2359 if (*lightpointer != light)
2360 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2361 *lightpointer = light->next;
2362 R_RTLight_Uncompile(&light->rtlight);
2366 void R_Shadow_ClearWorldLights(void)
2368 while (r_shadow_worldlightchain)
2369 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2370 r_shadow_selectedlight = NULL;
2371 R_Shadow_FreeCubemaps();
2374 void R_Shadow_SelectLight(dlight_t *light)
2376 if (r_shadow_selectedlight)
2377 r_shadow_selectedlight->selected = false;
2378 r_shadow_selectedlight = light;
2379 if (r_shadow_selectedlight)
2380 r_shadow_selectedlight->selected = true;
2383 rtexture_t *lighttextures[5];
2385 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2387 float scale = r_editlights_cursorgrid.value * 0.5f;
2388 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);
2391 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2394 const dlight_t *light;
2397 if (light->selected)
2398 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2401 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);
2404 void R_Shadow_DrawLightSprites(void)
2410 for (i = 0;i < 5;i++)
2412 lighttextures[i] = NULL;
2413 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2414 lighttextures[i] = pic->tex;
2417 for (light = r_shadow_worldlightchain;light;light = light->next)
2418 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2419 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2422 void R_Shadow_SelectLightInView(void)
2424 float bestrating, rating, temp[3];
2425 dlight_t *best, *light;
2428 for (light = r_shadow_worldlightchain;light;light = light->next)
2430 VectorSubtract(light->origin, r_vieworigin, temp);
2431 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2434 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2435 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2437 bestrating = rating;
2442 R_Shadow_SelectLight(best);
2445 void R_Shadow_LoadWorldLights(void)
2447 int n, a, style, shadow;
2448 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2449 float origin[3], radius, color[3], angles[3], corona;
2450 if (cl.worldmodel == NULL)
2452 Con_Printf("No map loaded.\n");
2455 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2456 strlcat (name, ".rtlights", sizeof (name));
2457 lightsstring = FS_LoadFile(name, false);
2467 for (;COM_Parse(t, true) && strcmp(
2468 if (COM_Parse(t, true))
2470 if (com_token[0] == '!')
2473 origin[0] = atof(com_token+1);
2476 origin[0] = atof(com_token);
2481 while (*s && *s != '\n')
2487 // check for modifier flags
2493 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]);
2495 VectorClear(angles);
2498 if (a < 9 || !strcmp(cubemapname, "\"\""))
2503 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);
2506 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2507 radius *= r_editlights_rtlightssizescale.value;
2508 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2513 Con_Printf("invalid rtlights file \"%s\"\n", name);
2514 Mem_Free(lightsstring);
2518 void R_Shadow_SaveWorldLights(void)
2521 int bufchars, bufmaxchars;
2523 char name[MAX_QPATH];
2525 if (!r_shadow_worldlightchain)
2527 if (cl.worldmodel == NULL)
2529 Con_Printf("No map loaded.\n");
2532 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2533 strlcat (name, ".rtlights", sizeof (name));
2534 bufchars = bufmaxchars = 0;
2536 for (light = r_shadow_worldlightchain;light;light = light->next)
2538 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]);
2539 if (bufchars + (int) strlen(line) > bufmaxchars)
2541 bufmaxchars = bufchars + strlen(line) + 2048;
2543 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2547 memcpy(buf, oldbuf, bufchars);
2553 memcpy(buf + bufchars, line, strlen(line));
2554 bufchars += strlen(line);
2558 FS_WriteFile(name, buf, bufchars);
2563 void R_Shadow_LoadLightsFile(void)
2566 char name[MAX_QPATH], *lightsstring, *s, *t;
2567 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2568 if (cl.worldmodel == NULL)
2570 Con_Printf("No map loaded.\n");
2573 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2574 strlcat (name, ".lights", sizeof (name));
2575 lightsstring = FS_LoadFile(name, false);
2583 while (*s && *s != '\n')
2588 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);
2592 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);
2595 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2596 radius = bound(15, radius, 4096);
2597 VectorScale(color, (2.0f / (8388608.0f)), color);
2598 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2603 Con_Printf("invalid lights file \"%s\"\n", name);
2604 Mem_Free(lightsstring);
2608 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2610 int entnum, style, islight, skin, pflags, effects;
2611 char key[256], value[1024];
2612 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2615 if (cl.worldmodel == NULL)
2617 Con_Printf("No map loaded.\n");
2620 data = cl.worldmodel->brush.entities;
2623 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2626 origin[0] = origin[1] = origin[2] = 0;
2627 originhack[0] = originhack[1] = originhack[2] = 0;
2628 angles[0] = angles[1] = angles[2] = 0;
2629 color[0] = color[1] = color[2] = 1;
2630 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2640 if (!COM_ParseToken(&data, false))
2642 if (com_token[0] == '}')
2643 break; // end of entity
2644 if (com_token[0] == '_')
2645 strcpy(key, com_token + 1);
2647 strcpy(key, com_token);
2648 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2649 key[strlen(key)-1] = 0;
2650 if (!COM_ParseToken(&data, false))
2652 strcpy(value, com_token);
2654 // now that we have the key pair worked out...
2655 if (!strcmp("light", key))
2656 light = atof(value);
2657 else if (!strcmp("origin", key))
2658 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2659 else if (!strcmp("angle", key))
2660 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2661 else if (!strcmp("angles", key))
2662 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2663 else if (!strcmp("color", key))
2664 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2665 else if (!strcmp("wait", key))
2666 fadescale = atof(value);
2667 else if (!strcmp("classname", key))
2669 if (!strncmp(value, "light", 5))
2672 if (!strcmp(value, "light_fluoro"))
2677 overridecolor[0] = 1;
2678 overridecolor[1] = 1;
2679 overridecolor[2] = 1;
2681 if (!strcmp(value, "light_fluorospark"))
2686 overridecolor[0] = 1;
2687 overridecolor[1] = 1;
2688 overridecolor[2] = 1;
2690 if (!strcmp(value, "light_globe"))
2695 overridecolor[0] = 1;
2696 overridecolor[1] = 0.8;
2697 overridecolor[2] = 0.4;
2699 if (!strcmp(value, "light_flame_large_yellow"))
2704 overridecolor[0] = 1;
2705 overridecolor[1] = 0.5;
2706 overridecolor[2] = 0.1;
2708 if (!strcmp(value, "light_flame_small_yellow"))
2713 overridecolor[0] = 1;
2714 overridecolor[1] = 0.5;
2715 overridecolor[2] = 0.1;
2717 if (!strcmp(value, "light_torch_small_white"))
2722 overridecolor[0] = 1;
2723 overridecolor[1] = 0.5;
2724 overridecolor[2] = 0.1;
2726 if (!strcmp(value, "light_torch_small_walltorch"))
2731 overridecolor[0] = 1;
2732 overridecolor[1] = 0.5;
2733 overridecolor[2] = 0.1;
2737 else if (!strcmp("style", key))
2738 style = atoi(value);
2739 else if (cl.worldmodel->type == mod_brushq3)
2741 if (!strcmp("scale", key))
2742 lightscale = atof(value);
2743 if (!strcmp("fade", key))
2744 fadescale = atof(value);
2746 else if (!strcmp("skin", key))
2747 skin = (int)atof(value);
2748 else if (!strcmp("pflags", key))
2749 pflags = (int)atof(value);
2750 else if (!strcmp("effects", key))
2751 effects = (int)atof(value);
2753 if (light <= 0 && islight)
2755 if (lightscale <= 0)
2759 if (gamemode == GAME_TENEBRAE)
2761 if (effects & EF_NODRAW)
2763 pflags |= PFLAGS_FULLDYNAMIC;
2764 effects &= ~EF_NODRAW;
2767 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2768 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2769 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2770 VectorCopy(overridecolor, color);
2771 VectorScale(color, light, color);
2772 VectorAdd(origin, originhack, origin);
2773 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2774 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2779 void R_Shadow_SetCursorLocationForView(void)
2781 vec_t dist, push, frac;
2782 vec3_t dest, endpos, normal;
2783 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2784 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2787 dist = frac * r_editlights_cursordistance.value;
2788 push = r_editlights_cursorpushback.value;
2792 VectorMA(endpos, push, r_viewforward, endpos);
2793 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2795 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2796 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2797 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2800 void R_Shadow_UpdateWorldLightSelection(void)
2802 if (r_editlights.integer)
2804 R_Shadow_SetCursorLocationForView();
2805 R_Shadow_SelectLightInView();
2806 R_Shadow_DrawLightSprites();
2809 R_Shadow_SelectLight(NULL);
2812 void R_Shadow_EditLights_Clear_f(void)
2814 R_Shadow_ClearWorldLights();
2817 void R_Shadow_EditLights_Reload_f(void)
2819 r_shadow_reloadlights = true;
2822 void R_Shadow_EditLights_Save_f(void)
2825 R_Shadow_SaveWorldLights();
2828 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2830 R_Shadow_ClearWorldLights();
2831 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2834 void R_Shadow_EditLights_ImportLightsFile_f(void)
2836 R_Shadow_ClearWorldLights();
2837 R_Shadow_LoadLightsFile();
2840 void R_Shadow_EditLights_Spawn_f(void)
2843 if (!r_editlights.integer)
2845 Con_Printf("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2848 if (Cmd_Argc() != 1)
2850 Con_Printf("r_editlights_spawn does not take parameters\n");
2853 color[0] = color[1] = color[2] = 1;
2854 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2857 void R_Shadow_EditLights_Edit_f(void)
2859 vec3_t origin, angles, color;
2860 vec_t radius, corona;
2862 char cubemapname[1024];
2863 if (!r_editlights.integer)
2865 Con_Printf("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2868 if (!r_shadow_selectedlight)
2870 Con_Printf("No selected light.\n");
2873 VectorCopy(r_shadow_selectedlight->origin, origin);
2874 VectorCopy(r_shadow_selectedlight->angles, angles);
2875 VectorCopy(r_shadow_selectedlight->color, color);
2876 radius = r_shadow_selectedlight->radius;
2877 style = r_shadow_selectedlight->style;
2878 if (r_shadow_selectedlight->cubemapname)
2879 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2882 shadows = r_shadow_selectedlight->shadow;
2883 corona = r_shadow_selectedlight->corona;
2884 if (!strcmp(Cmd_Argv(1), "origin"))
2886 if (Cmd_Argc() != 5)
2888 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2891 origin[0] = atof(Cmd_Argv(2));
2892 origin[1] = atof(Cmd_Argv(3));
2893 origin[2] = atof(Cmd_Argv(4));
2895 else if (!strcmp(Cmd_Argv(1), "originx"))
2897 if (Cmd_Argc() != 3)
2899 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2902 origin[0] = atof(Cmd_Argv(2));
2904 else if (!strcmp(Cmd_Argv(1), "originy"))
2906 if (Cmd_Argc() != 3)
2908 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2911 origin[1] = atof(Cmd_Argv(2));
2913 else if (!strcmp(Cmd_Argv(1), "originz"))
2915 if (Cmd_Argc() != 3)
2917 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2920 origin[2] = atof(Cmd_Argv(2));
2922 else if (!strcmp(Cmd_Argv(1), "move"))
2924 if (Cmd_Argc() != 5)
2926 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2929 origin[0] += atof(Cmd_Argv(2));
2930 origin[1] += atof(Cmd_Argv(3));
2931 origin[2] += atof(Cmd_Argv(4));
2933 else if (!strcmp(Cmd_Argv(1), "movex"))
2935 if (Cmd_Argc() != 3)
2937 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2940 origin[0] += atof(Cmd_Argv(2));
2942 else if (!strcmp(Cmd_Argv(1), "movey"))
2944 if (Cmd_Argc() != 3)
2946 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2949 origin[1] += atof(Cmd_Argv(2));
2951 else if (!strcmp(Cmd_Argv(1), "movez"))
2953 if (Cmd_Argc() != 3)
2955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2958 origin[2] += atof(Cmd_Argv(2));
2960 else if (!strcmp(Cmd_Argv(1), "angles"))
2962 if (Cmd_Argc() != 5)
2964 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2967 angles[0] = atof(Cmd_Argv(2));
2968 angles[1] = atof(Cmd_Argv(3));
2969 angles[2] = atof(Cmd_Argv(4));
2971 else if (!strcmp(Cmd_Argv(1), "anglesx"))
2973 if (Cmd_Argc() != 3)
2975 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2978 angles[0] = atof(Cmd_Argv(2));
2980 else if (!strcmp(Cmd_Argv(1), "anglesy"))
2982 if (Cmd_Argc() != 3)
2984 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2987 angles[1] = atof(Cmd_Argv(2));
2989 else if (!strcmp(Cmd_Argv(1), "anglesz"))
2991 if (Cmd_Argc() != 3)
2993 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2996 angles[2] = atof(Cmd_Argv(2));
2998 else if (!strcmp(Cmd_Argv(1), "color"))
3000 if (Cmd_Argc() != 5)
3002 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3005 color[0] = atof(Cmd_Argv(2));
3006 color[1] = atof(Cmd_Argv(3));
3007 color[2] = atof(Cmd_Argv(4));
3009 else if (!strcmp(Cmd_Argv(1), "radius"))
3011 if (Cmd_Argc() != 3)
3013 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3016 radius = atof(Cmd_Argv(2));
3018 else if (!strcmp(Cmd_Argv(1), "style"))
3020 if (Cmd_Argc() != 3)
3022 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3025 style = atoi(Cmd_Argv(2));
3027 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3031 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3034 if (Cmd_Argc() == 3)
3035 strcpy(cubemapname, Cmd_Argv(2));
3039 else if (!strcmp(Cmd_Argv(1), "shadows"))
3041 if (Cmd_Argc() != 3)
3043 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3046 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3048 else if (!strcmp(Cmd_Argv(1), "corona"))
3050 if (Cmd_Argc() != 3)
3052 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3055 corona = atof(Cmd_Argv(2));
3059 Con_Printf("usage: r_editlights_edit [property] [value]\n");
3060 Con_Printf("Selected light's properties:\n");
3061 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3062 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3063 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3064 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3065 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3066 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3067 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3068 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3071 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3072 r_shadow_selectedlight = NULL;
3073 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3076 extern int con_vislines;
3077 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3081 if (r_shadow_selectedlight == NULL)
3085 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3086 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;
3087 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;
3088 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;
3089 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3090 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3091 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3092 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;
3093 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3096 void R_Shadow_EditLights_ToggleShadow_f(void)
3098 if (!r_editlights.integer)
3100 Con_Printf("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3103 if (!r_shadow_selectedlight)
3105 Con_Printf("No selected light.\n");
3108 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);
3109 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3110 r_shadow_selectedlight = NULL;
3113 void R_Shadow_EditLights_ToggleCorona_f(void)
3115 if (!r_editlights.integer)
3117 Con_Printf("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3120 if (!r_shadow_selectedlight)
3122 Con_Printf("No selected light.\n");
3125 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);
3126 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3127 r_shadow_selectedlight = NULL;
3130 void R_Shadow_EditLights_Remove_f(void)
3132 if (!r_editlights.integer)
3134 Con_Printf("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3137 if (!r_shadow_selectedlight)
3139 Con_Printf("No selected light.\n");
3142 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3143 r_shadow_selectedlight = NULL;
3146 void R_Shadow_EditLights_Help_f(void)
3149 "Documentation on r_editlights system:\n"
3151 "r_editlights : enable/disable editing mode\n"
3152 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3153 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3154 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3155 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3156 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3157 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3158 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3160 "r_editlights_help : this help\n"
3161 "r_editlights_clear : remove all lights\n"
3162 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3163 "r_editlights_save : save to .rtlights file\n"
3164 "r_editlights_spawn : create a light with default settings\n"
3165 "r_editlights_edit command : edit selected light - more documentation below\n"
3166 "r_editlights_remove : remove selected light\n"
3167 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3168 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3169 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3171 "origin x y z : set light location\n"
3172 "originx x: set x component of light location\n"
3173 "originy y: set y component of light location\n"
3174 "originz z: set z component of light location\n"
3175 "move x y z : adjust light location\n"
3176 "movex x: adjust x component of light location\n"
3177 "movey y: adjust y component of light location\n"
3178 "movez z: adjust z component of light location\n"
3179 "angles x y z : set light angles\n"
3180 "anglesx x: set x component of light angles\n"
3181 "anglesy y: set y component of light angles\n"
3182 "anglesz z: set z component of light angles\n"
3183 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3184 "radius radius : set radius (size) of light\n"
3185 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3186 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3187 "shadows 1/0 : turn on/off shadows\n"
3188 "corona n : set corona intensity\n"
3189 "<nothing> : print light properties to console\n"
3193 void R_Shadow_EditLights_Init(void)
3195 Cvar_RegisterVariable(&r_editlights);
3196 Cvar_RegisterVariable(&r_editlights_cursordistance);
3197 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3198 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3199 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3200 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3201 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3202 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3203 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3204 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3205 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3206 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3207 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3208 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3209 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3210 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3211 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3212 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3213 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);