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 normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_STENCIL,
149 R_SHADOW_RENDERMODE_STENCILTWOSIDE,
150 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
151 R_SHADOW_RENDERMODE_LIGHT_DOT3,
152 R_SHADOW_RENDERMODE_LIGHT_GLSL,
153 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
154 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
156 r_shadow_rendermode_t;
158 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
159 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
160 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
162 mempool_t *r_shadow_mempool;
164 int maxshadowelements;
178 int r_shadow_buffer_numleafpvsbytes;
179 unsigned char *r_shadow_buffer_leafpvs;
180 int *r_shadow_buffer_leaflist;
182 int r_shadow_buffer_numsurfacepvsbytes;
183 unsigned char *r_shadow_buffer_surfacepvs;
184 int *r_shadow_buffer_surfacelist;
186 rtexturepool_t *r_shadow_texturepool;
187 rtexture_t *r_shadow_attenuation2dtexture;
188 rtexture_t *r_shadow_attenuation3dtexture;
190 // lights are reloaded when this changes
191 char r_shadow_mapname[MAX_QPATH];
193 // used only for light filters (cubemaps)
194 rtexturepool_t *r_shadow_filters_texturepool;
196 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
197 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
198 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
199 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
200 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
201 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
202 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
203 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
204 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
205 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
206 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
207 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
208 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
209 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal culling optimizations on dynamic lights (slow! you probably don't want this!)"};
210 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
211 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1", "enables shadows from dynamic lights when using full world lighting"};
212 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
213 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
214 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
215 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
216 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
217 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
218 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
219 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
220 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
221 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
222 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
223 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
224 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
225 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
226 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
228 float r_shadow_attenpower, r_shadow_attenscale;
230 rtlight_t *r_shadow_compilingrtlight;
231 dlight_t *r_shadow_worldlightchain;
232 dlight_t *r_shadow_selectedlight;
233 dlight_t r_shadow_bufferlight;
234 vec3_t r_editlights_cursorlocation;
236 extern int con_vislines;
238 typedef struct cubemapinfo_s
245 #define MAX_CUBEMAPS 256
246 static int numcubemaps;
247 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
249 void R_Shadow_UncompileWorldLights(void);
250 void R_Shadow_ClearWorldLights(void);
251 void R_Shadow_SaveWorldLights(void);
252 void R_Shadow_LoadWorldLights(void);
253 void R_Shadow_LoadLightsFile(void);
254 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
255 void R_Shadow_EditLights_Reload_f(void);
256 void R_Shadow_ValidateCvars(void);
257 static void R_Shadow_MakeTextures(void);
258 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
260 void r_shadow_start(void)
262 // allocate vertex processing arrays
264 r_shadow_attenuation2dtexture = NULL;
265 r_shadow_attenuation3dtexture = NULL;
266 r_shadow_texturepool = NULL;
267 r_shadow_filters_texturepool = NULL;
268 R_Shadow_ValidateCvars();
269 R_Shadow_MakeTextures();
270 maxshadowelements = 0;
271 shadowelements = NULL;
279 shadowmarklist = NULL;
281 r_shadow_buffer_numleafpvsbytes = 0;
282 r_shadow_buffer_leafpvs = NULL;
283 r_shadow_buffer_leaflist = NULL;
284 r_shadow_buffer_numsurfacepvsbytes = 0;
285 r_shadow_buffer_surfacepvs = NULL;
286 r_shadow_buffer_surfacelist = NULL;
289 void r_shadow_shutdown(void)
291 R_Shadow_UncompileWorldLights();
293 r_shadow_attenuation2dtexture = NULL;
294 r_shadow_attenuation3dtexture = NULL;
295 R_FreeTexturePool(&r_shadow_texturepool);
296 R_FreeTexturePool(&r_shadow_filters_texturepool);
297 maxshadowelements = 0;
299 Mem_Free(shadowelements);
300 shadowelements = NULL;
303 Mem_Free(vertexupdate);
306 Mem_Free(vertexremap);
312 Mem_Free(shadowmark);
315 Mem_Free(shadowmarklist);
316 shadowmarklist = NULL;
318 r_shadow_buffer_numleafpvsbytes = 0;
319 if (r_shadow_buffer_leafpvs)
320 Mem_Free(r_shadow_buffer_leafpvs);
321 r_shadow_buffer_leafpvs = NULL;
322 if (r_shadow_buffer_leaflist)
323 Mem_Free(r_shadow_buffer_leaflist);
324 r_shadow_buffer_leaflist = NULL;
325 r_shadow_buffer_numsurfacepvsbytes = 0;
326 if (r_shadow_buffer_surfacepvs)
327 Mem_Free(r_shadow_buffer_surfacepvs);
328 r_shadow_buffer_surfacepvs = NULL;
329 if (r_shadow_buffer_surfacelist)
330 Mem_Free(r_shadow_buffer_surfacelist);
331 r_shadow_buffer_surfacelist = NULL;
334 void r_shadow_newmap(void)
338 void R_Shadow_Help_f(void)
341 "Documentation on r_shadow system:\n"
343 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
344 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
345 "r_shadow_debuglight : render only this light number (-1 = all)\n"
346 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
347 "r_shadow_gloss2intensity : brightness of forced gloss\n"
348 "r_shadow_glossintensity : brightness of textured gloss\n"
349 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
350 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
351 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
352 "r_shadow_portallight : use portal visibility for static light precomputation\n"
353 "r_shadow_projectdistance : shadow volume projection distance\n"
354 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
355 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
356 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
357 "r_shadow_realtime_world : use high quality world lighting mode\n"
358 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
359 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
360 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
361 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
362 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
363 "r_shadow_scissor : use scissor optimization\n"
364 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
365 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
366 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
367 "r_showlighting : useful for performance testing; bright = slow!\n"
368 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
370 "r_shadow_help : this help\n"
374 void R_Shadow_Init(void)
376 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
377 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
378 Cvar_RegisterVariable(&r_shadow_debuglight);
379 Cvar_RegisterVariable(&r_shadow_gloss);
380 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
381 Cvar_RegisterVariable(&r_shadow_glossintensity);
382 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
383 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
384 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
385 Cvar_RegisterVariable(&r_shadow_portallight);
386 Cvar_RegisterVariable(&r_shadow_projectdistance);
387 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
388 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
389 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
390 Cvar_RegisterVariable(&r_shadow_realtime_world);
391 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
392 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
393 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
394 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
395 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
396 Cvar_RegisterVariable(&r_shadow_scissor);
397 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
398 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
399 Cvar_RegisterVariable(&r_shadow_texture3d);
400 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
401 if (gamemode == GAME_TENEBRAE)
403 Cvar_SetValue("r_shadow_gloss", 2);
404 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
406 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
407 R_Shadow_EditLights_Init();
408 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
409 r_shadow_worldlightchain = NULL;
410 maxshadowelements = 0;
411 shadowelements = NULL;
419 shadowmarklist = NULL;
421 r_shadow_buffer_numleafpvsbytes = 0;
422 r_shadow_buffer_leafpvs = NULL;
423 r_shadow_buffer_leaflist = NULL;
424 r_shadow_buffer_numsurfacepvsbytes = 0;
425 r_shadow_buffer_surfacepvs = NULL;
426 r_shadow_buffer_surfacelist = NULL;
427 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
430 matrix4x4_t matrix_attenuationxyz =
433 {0.5, 0.0, 0.0, 0.5},
434 {0.0, 0.5, 0.0, 0.5},
435 {0.0, 0.0, 0.5, 0.5},
440 matrix4x4_t matrix_attenuationz =
443 {0.0, 0.0, 0.5, 0.5},
444 {0.0, 0.0, 0.0, 0.5},
445 {0.0, 0.0, 0.0, 0.5},
450 int *R_Shadow_ResizeShadowElements(int numtris)
452 // make sure shadowelements is big enough for this volume
453 if (maxshadowelements < numtris * 24)
455 maxshadowelements = numtris * 24;
457 Mem_Free(shadowelements);
458 shadowelements = (int *)Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
460 return shadowelements;
463 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
465 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
466 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
467 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
469 if (r_shadow_buffer_leafpvs)
470 Mem_Free(r_shadow_buffer_leafpvs);
471 if (r_shadow_buffer_leaflist)
472 Mem_Free(r_shadow_buffer_leaflist);
473 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
474 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
475 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
477 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
479 if (r_shadow_buffer_surfacepvs)
480 Mem_Free(r_shadow_buffer_surfacepvs);
481 if (r_shadow_buffer_surfacelist)
482 Mem_Free(r_shadow_buffer_surfacelist);
483 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
484 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
485 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
489 void R_Shadow_PrepareShadowMark(int numtris)
491 // make sure shadowmark is big enough for this volume
492 if (maxshadowmark < numtris)
494 maxshadowmark = numtris;
496 Mem_Free(shadowmark);
498 Mem_Free(shadowmarklist);
499 shadowmark = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
500 shadowmarklist = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
504 // if shadowmarkcount wrapped we clear the array and adjust accordingly
505 if (shadowmarkcount == 0)
508 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
513 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)
516 int outtriangles = 0, outvertices = 0;
520 if (maxvertexupdate < innumvertices)
522 maxvertexupdate = innumvertices;
524 Mem_Free(vertexupdate);
526 Mem_Free(vertexremap);
527 vertexupdate = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
528 vertexremap = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
532 if (vertexupdatenum == 0)
535 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
536 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
539 for (i = 0;i < numshadowmarktris;i++)
540 shadowmark[shadowmarktris[i]] = shadowmarkcount;
542 for (i = 0;i < numshadowmarktris;i++)
544 element = inelement3i + shadowmarktris[i] * 3;
545 // make sure the vertices are created
546 for (j = 0;j < 3;j++)
548 if (vertexupdate[element[j]] != vertexupdatenum)
550 float ratio, direction[3];
551 vertexupdate[element[j]] = vertexupdatenum;
552 vertexremap[element[j]] = outvertices;
553 vertex = invertex3f + element[j] * 3;
554 // project one copy of the vertex to the sphere radius of the light
555 // (FIXME: would projecting it to the light box be better?)
556 VectorSubtract(vertex, projectorigin, direction);
557 ratio = projectdistance / VectorLength(direction);
558 VectorCopy(vertex, outvertex3f);
559 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
566 for (i = 0;i < numshadowmarktris;i++)
568 int remappedelement[3];
570 const int *neighbortriangle;
572 markindex = shadowmarktris[i] * 3;
573 element = inelement3i + markindex;
574 neighbortriangle = inneighbor3i + markindex;
575 // output the front and back triangles
576 outelement3i[0] = vertexremap[element[0]];
577 outelement3i[1] = vertexremap[element[1]];
578 outelement3i[2] = vertexremap[element[2]];
579 outelement3i[3] = vertexremap[element[2]] + 1;
580 outelement3i[4] = vertexremap[element[1]] + 1;
581 outelement3i[5] = vertexremap[element[0]] + 1;
585 // output the sides (facing outward from this triangle)
586 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
588 remappedelement[0] = vertexremap[element[0]];
589 remappedelement[1] = vertexremap[element[1]];
590 outelement3i[0] = remappedelement[1];
591 outelement3i[1] = remappedelement[0];
592 outelement3i[2] = remappedelement[0] + 1;
593 outelement3i[3] = remappedelement[1];
594 outelement3i[4] = remappedelement[0] + 1;
595 outelement3i[5] = remappedelement[1] + 1;
600 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
602 remappedelement[1] = vertexremap[element[1]];
603 remappedelement[2] = vertexremap[element[2]];
604 outelement3i[0] = remappedelement[2];
605 outelement3i[1] = remappedelement[1];
606 outelement3i[2] = remappedelement[1] + 1;
607 outelement3i[3] = remappedelement[2];
608 outelement3i[4] = remappedelement[1] + 1;
609 outelement3i[5] = remappedelement[2] + 1;
614 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
616 remappedelement[0] = vertexremap[element[0]];
617 remappedelement[2] = vertexremap[element[2]];
618 outelement3i[0] = remappedelement[0];
619 outelement3i[1] = remappedelement[2];
620 outelement3i[2] = remappedelement[2] + 1;
621 outelement3i[3] = remappedelement[0];
622 outelement3i[4] = remappedelement[2] + 1;
623 outelement3i[5] = remappedelement[0] + 1;
630 *outnumvertices = outvertices;
634 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)
637 if (projectdistance < 0.1)
639 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
642 if (!numverts || !nummarktris)
644 // make sure shadowelements is big enough for this volume
645 if (maxshadowelements < nummarktris * 24)
646 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
647 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
648 renderstats.lights_dynamicshadowtriangles += tris;
649 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
652 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
657 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
659 tend = firsttriangle + numtris;
660 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
661 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
662 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
664 // surface box entirely inside light box, no box cull
665 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
666 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
667 shadowmarklist[numshadowmark++] = t;
671 // surface box not entirely inside light box, cull each triangle
672 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
674 v[0] = invertex3f + e[0] * 3;
675 v[1] = invertex3f + e[1] * 3;
676 v[2] = invertex3f + e[2] * 3;
677 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
678 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
679 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
680 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
681 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
682 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
683 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
684 shadowmarklist[numshadowmark++] = t;
689 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
692 if (r_shadow_compilingrtlight)
694 // if we're compiling an rtlight, capture the mesh
695 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
698 renderstats.lights_shadowtriangles += numtriangles;
699 memset(&m, 0, sizeof(m));
700 m.pointer_vertex = vertex3f;
702 GL_LockArrays(0, numvertices);
703 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
705 // decrement stencil if backface is behind depthbuffer
706 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
707 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
708 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
709 // increment stencil if frontface is behind depthbuffer
710 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
711 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
713 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
717 static void R_Shadow_MakeTextures(void)
720 float v[3], intensity;
722 R_FreeTexturePool(&r_shadow_texturepool);
723 r_shadow_texturepool = R_AllocTexturePool();
724 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
725 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
726 #define ATTEN2DSIZE 64
727 #define ATTEN3DSIZE 32
728 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
729 for (y = 0;y < ATTEN2DSIZE;y++)
731 for (x = 0;x < ATTEN2DSIZE;x++)
733 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
734 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
736 intensity = 1.0f - sqrt(DotProduct(v, v));
738 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
739 d = bound(0, intensity, 255);
740 data[(y*ATTEN2DSIZE+x)*4+0] = d;
741 data[(y*ATTEN2DSIZE+x)*4+1] = d;
742 data[(y*ATTEN2DSIZE+x)*4+2] = d;
743 data[(y*ATTEN2DSIZE+x)*4+3] = d;
746 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
747 if (r_shadow_texture3d.integer)
749 for (z = 0;z < ATTEN3DSIZE;z++)
751 for (y = 0;y < ATTEN3DSIZE;y++)
753 for (x = 0;x < ATTEN3DSIZE;x++)
755 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
756 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
757 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
758 intensity = 1.0f - sqrt(DotProduct(v, v));
760 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
761 d = bound(0, intensity, 255);
762 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
763 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
764 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
765 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
769 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
774 void R_Shadow_ValidateCvars(void)
776 if (r_shadow_texture3d.integer && !gl_texture3d)
777 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
778 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
779 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
782 // light currently being rendered
783 rtlight_t *r_shadow_rtlight;
785 // this is the location of the eye in entity space
786 vec3_t r_shadow_entityeyeorigin;
787 // this is the location of the light in entity space
788 vec3_t r_shadow_entitylightorigin;
789 // this transforms entity coordinates to light filter cubemap coordinates
790 // (also often used for other purposes)
791 matrix4x4_t r_shadow_entitytolight;
792 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
793 // of attenuation texturing in full 3D (Z result often ignored)
794 matrix4x4_t r_shadow_entitytoattenuationxyz;
795 // this transforms only the Z to S, and T is always 0.5
796 matrix4x4_t r_shadow_entitytoattenuationz;
798 void R_Shadow_RenderMode_Begin(void)
802 R_Shadow_ValidateCvars();
804 if (!r_shadow_attenuation2dtexture
805 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
806 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
807 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
808 R_Shadow_MakeTextures();
810 memset(&m, 0, sizeof(m));
812 GL_BlendFunc(GL_ONE, GL_ZERO);
815 GL_Color(0, 0, 0, 1);
816 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
817 qglEnable(GL_CULL_FACE);
818 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
820 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
822 if (gl_ext_stenciltwoside.integer)
823 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
825 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
827 if (r_glsl.integer && gl_support_fragment_shader)
828 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
829 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
830 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
832 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
835 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
837 r_shadow_rtlight = rtlight;
840 void R_Shadow_RenderMode_Reset(void)
843 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
845 qglUseProgramObjectARB(0);
846 // HACK HACK HACK: work around for bug in NVIDIAI 6xxx drivers that causes GL_OUT_OF_MEMORY and/or software rendering
847 qglBegin(GL_TRIANGLES);
851 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
852 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
853 memset(&m, 0, sizeof(m));
857 void R_Shadow_RenderMode_StencilShadowVolumes(void)
859 R_Shadow_RenderMode_Reset();
860 GL_Color(1, 1, 1, 1);
861 GL_ColorMask(0, 0, 0, 0);
862 GL_BlendFunc(GL_ONE, GL_ZERO);
866 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
867 //if (r_shadow_shadow_polygonoffset.value != 0)
869 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
870 // qglEnable(GL_POLYGON_OFFSET_FILL);
873 // qglDisable(GL_POLYGON_OFFSET_FILL);
874 qglDepthFunc(GL_LESS);
875 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
876 qglEnable(GL_STENCIL_TEST);
877 qglStencilFunc(GL_ALWAYS, 128, ~0);
878 r_shadow_rendermode = r_shadow_shadowingrendermode;
879 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
881 qglDisable(GL_CULL_FACE);
882 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
883 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
885 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
886 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
888 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
892 qglEnable(GL_CULL_FACE);
894 // this is changed by every shadow render so its value here is unimportant
895 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
897 GL_Clear(GL_STENCIL_BUFFER_BIT);
898 renderstats.lights_clears++;
901 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
903 R_Shadow_RenderMode_Reset();
904 GL_BlendFunc(GL_ONE, GL_ONE);
908 qglPolygonOffset(0, 0);
909 //qglDisable(GL_POLYGON_OFFSET_FILL);
910 GL_Color(1, 1, 1, 1);
911 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
913 qglDepthFunc(GL_LEQUAL);
915 qglDepthFunc(GL_EQUAL);
916 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
917 qglEnable(GL_CULL_FACE);
919 qglEnable(GL_STENCIL_TEST);
921 qglDisable(GL_STENCIL_TEST);
923 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
924 // only draw light where this geometry was already rendered AND the
925 // stencil is 128 (values other than this mean shadow)
926 qglStencilFunc(GL_EQUAL, 128, ~0);
927 r_shadow_rendermode = r_shadow_lightingrendermode;
928 // do global setup needed for the chosen lighting mode
929 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
931 R_Mesh_VertexPointer(varray_vertex3f);
932 R_Mesh_TexCoordPointer(0, 2, varray_texcoord2f[0]);
933 R_Mesh_TexCoordPointer(1, 3, varray_svector3f);
934 R_Mesh_TexCoordPointer(2, 3, varray_tvector3f);
935 R_Mesh_TexCoordPointer(3, 3, varray_normal3f);
936 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
937 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
938 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
939 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
940 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
941 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
942 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
943 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
944 GL_BlendFunc(GL_ONE, GL_ONE);
945 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
950 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
952 R_Shadow_RenderMode_Reset();
953 GL_BlendFunc(GL_ONE, GL_ONE);
955 GL_DepthTest(!r_showdisabledepthtest.integer);
957 qglPolygonOffset(0, 0);
958 GL_Color(0.0, 0.0125, 0.1, 1);
959 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
960 qglDepthFunc(GL_GEQUAL);
961 qglCullFace(GL_FRONT); // this culls back
962 qglDisable(GL_CULL_FACE);
963 qglDisable(GL_STENCIL_TEST);
964 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
967 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
969 R_Shadow_RenderMode_Reset();
970 GL_BlendFunc(GL_ONE, GL_ONE);
972 GL_DepthTest(!r_showdisabledepthtest.integer);
974 qglPolygonOffset(0, 0);
975 GL_Color(0.1, 0.0125, 0, 1);
976 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
978 qglDepthFunc(GL_LEQUAL);
980 qglDepthFunc(GL_EQUAL);
981 qglCullFace(GL_FRONT); // this culls back
982 qglEnable(GL_CULL_FACE);
984 qglEnable(GL_STENCIL_TEST);
986 qglDisable(GL_STENCIL_TEST);
987 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
990 void R_Shadow_RenderMode_End(void)
992 R_Shadow_RenderMode_Reset();
993 R_Shadow_RenderMode_ActiveLight(NULL);
994 GL_BlendFunc(GL_ONE, GL_ZERO);
998 qglPolygonOffset(0, 0);
999 //qglDisable(GL_POLYGON_OFFSET_FILL);
1000 GL_Color(1, 1, 1, 1);
1001 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1002 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1003 qglDepthFunc(GL_LEQUAL);
1004 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1005 qglEnable(GL_CULL_FACE);
1006 qglDisable(GL_STENCIL_TEST);
1007 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1008 if (gl_support_stenciltwoside)
1009 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1011 qglStencilFunc(GL_ALWAYS, 128, ~0);
1012 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1015 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1017 int i, ix1, iy1, ix2, iy2;
1018 float x1, y1, x2, y2;
1021 mplane_t planes[11];
1022 float vertex3f[256*3];
1024 // if view is inside the light box, just say yes it's visible
1025 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1027 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1031 // create a temporary brush describing the area the light can affect in worldspace
1032 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1033 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1034 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1035 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1036 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1037 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1038 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1039 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1040 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1041 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1042 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1044 // turn the brush into a mesh
1045 memset(&mesh, 0, sizeof(rmesh_t));
1046 mesh.maxvertices = 256;
1047 mesh.vertex3f = vertex3f;
1048 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1049 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1051 // if that mesh is empty, the light is not visible at all
1052 if (!mesh.numvertices)
1055 if (!r_shadow_scissor.integer)
1058 // if that mesh is not empty, check what area of the screen it covers
1059 x1 = y1 = x2 = y2 = 0;
1061 for (i = 0;i < mesh.numvertices;i++)
1063 VectorCopy(mesh.vertex3f + i * 3, v);
1064 GL_TransformToScreen(v, v2);
1065 //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]);
1068 if (x1 > v2[0]) x1 = v2[0];
1069 if (x2 < v2[0]) x2 = v2[0];
1070 if (y1 > v2[1]) y1 = v2[1];
1071 if (y2 < v2[1]) y2 = v2[1];
1080 // now convert the scissor rectangle to integer screen coordinates
1085 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1087 // clamp it to the screen
1088 if (ix1 < r_view_x) ix1 = r_view_x;
1089 if (iy1 < r_view_y) iy1 = r_view_y;
1090 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1091 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1093 // if it is inside out, it's not visible
1094 if (ix2 <= ix1 || iy2 <= iy1)
1097 // the light area is visible, set up the scissor rectangle
1098 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1099 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1100 //qglEnable(GL_SCISSOR_TEST);
1101 renderstats.lights_scissored++;
1105 extern float *rsurface_vertex3f;
1106 extern float *rsurface_svector3f;
1107 extern float *rsurface_tvector3f;
1108 extern float *rsurface_normal3f;
1109 extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg, qboolean generatenormals, qboolean generatetangents);
1111 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1113 int numverts = surface->num_vertices;
1114 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1115 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1116 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1117 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1118 if (r_textureunits.integer >= 3)
1120 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1122 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1123 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1124 if ((dot = DotProduct(n, v)) < 0)
1126 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1127 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1128 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1129 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1132 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1133 VectorScale(color4f, f, color4f);
1137 VectorClear(color4f);
1141 else if (r_textureunits.integer >= 2)
1143 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1145 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1146 if ((dist = fabs(v[2])) < 1)
1148 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1149 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1150 if ((dot = DotProduct(n, v)) < 0)
1152 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1153 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1154 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1155 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1159 color4f[0] = ambientcolor[0] * distintensity;
1160 color4f[1] = ambientcolor[1] * distintensity;
1161 color4f[2] = ambientcolor[2] * distintensity;
1165 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1166 VectorScale(color4f, f, color4f);
1170 VectorClear(color4f);
1176 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1178 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1179 if ((dist = DotProduct(v, v)) < 1)
1182 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1183 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1184 if ((dot = DotProduct(n, v)) < 0)
1186 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1187 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1188 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1189 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1193 color4f[0] = ambientcolor[0] * distintensity;
1194 color4f[1] = ambientcolor[1] * distintensity;
1195 color4f[2] = ambientcolor[2] * distintensity;
1199 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1200 VectorScale(color4f, f, color4f);
1204 VectorClear(color4f);
1210 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1211 #define USETEXMATRIX
1213 #ifndef USETEXMATRIX
1214 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1215 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1216 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1220 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1221 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1222 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1229 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1233 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1234 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1242 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
1246 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1248 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1249 // the cubemap normalizes this for us
1250 out3f[0] = DotProduct(svector3f, lightdir);
1251 out3f[1] = DotProduct(tvector3f, lightdir);
1252 out3f[2] = DotProduct(normal3f, lightdir);
1256 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
1259 float lightdir[3], eyedir[3], halfdir[3];
1260 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1262 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1263 VectorNormalize(lightdir);
1264 VectorSubtract(relativeeyeorigin, vertex3f, eyedir);
1265 VectorNormalize(eyedir);
1266 VectorAdd(lightdir, eyedir, halfdir);
1267 // the cubemap normalizes this for us
1268 out3f[0] = DotProduct(svector3f, halfdir);
1269 out3f[1] = DotProduct(tvector3f, halfdir);
1270 out3f[2] = DotProduct(normal3f, halfdir);
1274 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1276 // used to display how many times a surface is lit for level design purposes
1277 int surfacelistindex;
1279 GL_Color(0.1, 0.025, 0, 1);
1280 memset(&m, 0, sizeof(m));
1282 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1284 const msurface_t *surface = surfacelist[surfacelistindex];
1285 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, false);
1286 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1287 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);
1288 GL_LockArrays(0, 0);
1292 static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1294 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1295 int surfacelistindex;
1296 R_SetupSurfaceShader(ent, texture, r_shadow_entityeyeorigin, lightcolorbase, false);
1297 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1299 const msurface_t *surface = surfacelist[surfacelistindex];
1300 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1301 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, true);
1302 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1303 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1304 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1305 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1306 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1307 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1308 GL_LockArrays(0, 0);
1312 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1317 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1319 // colorscale accounts for how much we multiply the brightness
1322 // mult is how many times the final pass of the lighting will be
1323 // performed to get more brightness than otherwise possible.
1325 // Limit mult to 64 for sanity sake.
1326 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1328 // 3 3D combine path (Geforce3, Radeon 8500)
1329 memset(&m, 0, sizeof(m));
1330 m.pointer_vertex = rsurface_vertex3f;
1331 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1333 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1334 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1336 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1337 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1339 m.tex[1] = R_GetTexture(basetexture);
1340 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1341 m.texmatrix[1] = texture->currenttexmatrix;
1342 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1344 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1345 m.texmatrix[2] = r_shadow_entitytolight;
1347 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1348 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1350 GL_BlendFunc(GL_ONE, GL_ONE);
1352 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1354 // 2 3D combine path (Geforce3, original Radeon)
1355 memset(&m, 0, sizeof(m));
1356 m.pointer_vertex = rsurface_vertex3f;
1357 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1359 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1360 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1362 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1363 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1365 m.tex[1] = R_GetTexture(basetexture);
1366 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1367 m.texmatrix[1] = texture->currenttexmatrix;
1368 GL_BlendFunc(GL_ONE, GL_ONE);
1370 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1372 // 4 2D combine path (Geforce3, Radeon 8500)
1373 memset(&m, 0, sizeof(m));
1374 m.pointer_vertex = rsurface_vertex3f;
1375 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1377 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1378 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1380 m.pointer_texcoord[0] = varray_texcoord2f[0];
1381 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1383 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1385 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1386 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1388 m.pointer_texcoord[1] = varray_texcoord2f[1];
1389 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1391 m.tex[2] = R_GetTexture(basetexture);
1392 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1393 m.texmatrix[2] = texture->currenttexmatrix;
1394 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1396 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1398 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1399 m.texmatrix[3] = r_shadow_entitytolight;
1401 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1402 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1405 GL_BlendFunc(GL_ONE, GL_ONE);
1407 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1409 // 3 2D combine path (Geforce3, original Radeon)
1410 memset(&m, 0, sizeof(m));
1411 m.pointer_vertex = rsurface_vertex3f;
1412 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1414 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1415 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1417 m.pointer_texcoord[0] = varray_texcoord2f[0];
1418 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1420 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1422 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1423 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1425 m.pointer_texcoord[1] = varray_texcoord2f[1];
1426 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1428 m.tex[2] = R_GetTexture(basetexture);
1429 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1430 m.texmatrix[2] = texture->currenttexmatrix;
1431 GL_BlendFunc(GL_ONE, GL_ONE);
1435 // 2/2/2 2D combine path (any dot3 card)
1436 memset(&m, 0, sizeof(m));
1437 m.pointer_vertex = rsurface_vertex3f;
1438 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1440 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1441 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1443 m.pointer_texcoord[0] = varray_texcoord2f[0];
1444 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1446 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1448 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1449 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1451 m.pointer_texcoord[1] = varray_texcoord2f[1];
1452 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1455 GL_ColorMask(0,0,0,1);
1456 GL_BlendFunc(GL_ONE, GL_ZERO);
1457 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1458 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1459 GL_LockArrays(0, 0);
1461 memset(&m, 0, sizeof(m));
1462 m.pointer_vertex = rsurface_vertex3f;
1463 m.tex[0] = R_GetTexture(basetexture);
1464 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1465 m.texmatrix[0] = texture->currenttexmatrix;
1466 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1468 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1470 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1471 m.texmatrix[1] = r_shadow_entitytolight;
1473 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1474 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1477 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1479 // this final code is shared
1481 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1482 VectorScale(lightcolorbase, colorscale, color2);
1483 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1484 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1486 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1487 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1489 GL_LockArrays(0, 0);
1492 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1497 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1499 // colorscale accounts for how much we multiply the brightness
1502 // mult is how many times the final pass of the lighting will be
1503 // performed to get more brightness than otherwise possible.
1505 // Limit mult to 64 for sanity sake.
1506 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1508 // 3/2 3D combine path (Geforce3, Radeon 8500)
1509 memset(&m, 0, sizeof(m));
1510 m.pointer_vertex = rsurface_vertex3f;
1511 m.tex[0] = R_GetTexture(normalmaptexture);
1512 m.texcombinergb[0] = GL_REPLACE;
1513 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1514 m.texmatrix[0] = texture->currenttexmatrix;
1515 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1516 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1517 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1518 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1519 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1521 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1522 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1524 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1525 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1528 GL_ColorMask(0,0,0,1);
1529 GL_BlendFunc(GL_ONE, GL_ZERO);
1530 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1531 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1532 GL_LockArrays(0, 0);
1534 memset(&m, 0, sizeof(m));
1535 m.pointer_vertex = rsurface_vertex3f;
1536 m.tex[0] = R_GetTexture(basetexture);
1537 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1538 m.texmatrix[0] = texture->currenttexmatrix;
1539 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1541 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1543 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1544 m.texmatrix[1] = r_shadow_entitytolight;
1546 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1547 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1550 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1552 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1554 // 1/2/2 3D combine path (original Radeon)
1555 memset(&m, 0, sizeof(m));
1556 m.pointer_vertex = rsurface_vertex3f;
1557 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1559 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1560 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1562 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1563 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1566 GL_ColorMask(0,0,0,1);
1567 GL_BlendFunc(GL_ONE, GL_ZERO);
1568 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1569 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1570 GL_LockArrays(0, 0);
1572 memset(&m, 0, sizeof(m));
1573 m.pointer_vertex = rsurface_vertex3f;
1574 m.tex[0] = R_GetTexture(normalmaptexture);
1575 m.texcombinergb[0] = GL_REPLACE;
1576 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1577 m.texmatrix[0] = texture->currenttexmatrix;
1578 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1579 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1580 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1581 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1583 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1584 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1585 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1586 GL_LockArrays(0, 0);
1588 memset(&m, 0, sizeof(m));
1589 m.pointer_vertex = rsurface_vertex3f;
1590 m.tex[0] = R_GetTexture(basetexture);
1591 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1592 m.texmatrix[0] = texture->currenttexmatrix;
1593 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1595 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1597 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1598 m.texmatrix[1] = r_shadow_entitytolight;
1600 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1601 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1604 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1606 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1608 // 2/2 3D combine path (original Radeon)
1609 memset(&m, 0, sizeof(m));
1610 m.pointer_vertex = rsurface_vertex3f;
1611 m.tex[0] = R_GetTexture(normalmaptexture);
1612 m.texcombinergb[0] = GL_REPLACE;
1613 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1614 m.texmatrix[0] = texture->currenttexmatrix;
1615 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1616 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1617 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1618 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1620 GL_ColorMask(0,0,0,1);
1621 GL_BlendFunc(GL_ONE, GL_ZERO);
1622 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1623 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1624 GL_LockArrays(0, 0);
1626 memset(&m, 0, sizeof(m));
1627 m.pointer_vertex = rsurface_vertex3f;
1628 m.tex[0] = R_GetTexture(basetexture);
1629 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1630 m.texmatrix[0] = texture->currenttexmatrix;
1631 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1633 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1634 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1636 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1637 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1639 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1641 else if (r_textureunits.integer >= 4)
1643 // 4/2 2D combine path (Geforce3, Radeon 8500)
1644 memset(&m, 0, sizeof(m));
1645 m.pointer_vertex = rsurface_vertex3f;
1646 m.tex[0] = R_GetTexture(normalmaptexture);
1647 m.texcombinergb[0] = GL_REPLACE;
1648 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1649 m.texmatrix[0] = texture->currenttexmatrix;
1650 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1651 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1652 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1653 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1654 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1656 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1657 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1659 m.pointer_texcoord[2] = varray_texcoord2f[2];
1660 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1662 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1664 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1665 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1667 m.pointer_texcoord[3] = varray_texcoord2f[3];
1668 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[3] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1671 GL_ColorMask(0,0,0,1);
1672 GL_BlendFunc(GL_ONE, GL_ZERO);
1673 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1674 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1675 GL_LockArrays(0, 0);
1677 memset(&m, 0, sizeof(m));
1678 m.pointer_vertex = rsurface_vertex3f;
1679 m.tex[0] = R_GetTexture(basetexture);
1680 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1681 m.texmatrix[0] = texture->currenttexmatrix;
1682 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1684 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1686 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1687 m.texmatrix[1] = r_shadow_entitytolight;
1689 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1690 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1693 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1697 // 2/2/2 2D combine path (any dot3 card)
1698 memset(&m, 0, sizeof(m));
1699 m.pointer_vertex = rsurface_vertex3f;
1700 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1702 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1703 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1705 m.pointer_texcoord[0] = varray_texcoord2f[0];
1706 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1708 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1710 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1711 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1713 m.pointer_texcoord[1] = varray_texcoord2f[1];
1714 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1717 GL_ColorMask(0,0,0,1);
1718 GL_BlendFunc(GL_ONE, GL_ZERO);
1719 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1720 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1721 GL_LockArrays(0, 0);
1723 memset(&m, 0, sizeof(m));
1724 m.pointer_vertex = rsurface_vertex3f;
1725 m.tex[0] = R_GetTexture(normalmaptexture);
1726 m.texcombinergb[0] = GL_REPLACE;
1727 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1728 m.texmatrix[0] = texture->currenttexmatrix;
1729 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1730 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1731 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1732 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1734 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1735 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1736 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1737 GL_LockArrays(0, 0);
1739 memset(&m, 0, sizeof(m));
1740 m.pointer_vertex = rsurface_vertex3f;
1741 m.tex[0] = R_GetTexture(basetexture);
1742 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1743 m.texmatrix[0] = texture->currenttexmatrix;
1744 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1746 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1748 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1749 m.texmatrix[1] = r_shadow_entitytolight;
1751 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1752 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1755 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1757 // this final code is shared
1759 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1760 VectorScale(lightcolorbase, colorscale, color2);
1761 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1762 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1764 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1765 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1767 GL_LockArrays(0, 0);
1770 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1775 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1776 // FIXME: detect blendsquare!
1777 //if (!gl_support_blendsquare)
1780 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1782 // 2/0/0/1/2 3D combine blendsquare path
1783 memset(&m, 0, sizeof(m));
1784 m.pointer_vertex = rsurface_vertex3f;
1785 m.tex[0] = R_GetTexture(normalmaptexture);
1786 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1787 m.texmatrix[0] = texture->currenttexmatrix;
1788 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1789 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1790 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1791 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
1793 GL_ColorMask(0,0,0,1);
1794 // this squares the result
1795 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1796 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1797 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1798 GL_LockArrays(0, 0);
1800 memset(&m, 0, sizeof(m));
1801 m.pointer_vertex = rsurface_vertex3f;
1803 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1804 // square alpha in framebuffer a few times to make it shiny
1805 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1806 // these comments are a test run through this math for intensity 0.5
1807 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1808 // 0.25 * 0.25 = 0.0625 (this is another pass)
1809 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1810 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1811 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1812 GL_LockArrays(0, 0);
1814 memset(&m, 0, sizeof(m));
1815 m.pointer_vertex = rsurface_vertex3f;
1816 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1818 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1819 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1821 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1822 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1825 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1826 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1827 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1828 GL_LockArrays(0, 0);
1830 memset(&m, 0, sizeof(m));
1831 m.pointer_vertex = rsurface_vertex3f;
1832 m.tex[0] = R_GetTexture(glosstexture);
1833 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1834 m.texmatrix[0] = texture->currenttexmatrix;
1835 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1837 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1839 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1840 m.texmatrix[1] = r_shadow_entitytolight;
1842 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1843 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1846 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1848 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1850 // 2/0/0/2 3D combine blendsquare path
1851 memset(&m, 0, sizeof(m));
1852 m.pointer_vertex = rsurface_vertex3f;
1853 m.tex[0] = R_GetTexture(normalmaptexture);
1854 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1855 m.texmatrix[0] = texture->currenttexmatrix;
1856 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1857 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1858 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1859 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
1861 GL_ColorMask(0,0,0,1);
1862 // this squares the result
1863 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1864 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1865 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1866 GL_LockArrays(0, 0);
1868 memset(&m, 0, sizeof(m));
1869 m.pointer_vertex = rsurface_vertex3f;
1871 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1872 // square alpha in framebuffer a few times to make it shiny
1873 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1874 // these comments are a test run through this math for intensity 0.5
1875 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1876 // 0.25 * 0.25 = 0.0625 (this is another pass)
1877 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1878 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1879 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1880 GL_LockArrays(0, 0);
1882 memset(&m, 0, sizeof(m));
1883 m.pointer_vertex = rsurface_vertex3f;
1884 m.tex[0] = R_GetTexture(glosstexture);
1885 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1886 m.texmatrix[0] = texture->currenttexmatrix;
1887 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1889 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1890 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1892 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1893 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1895 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1899 // 2/0/0/2/2 2D combine blendsquare path
1900 memset(&m, 0, sizeof(m));
1901 m.pointer_vertex = rsurface_vertex3f;
1902 m.tex[0] = R_GetTexture(normalmaptexture);
1903 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1904 m.texmatrix[0] = texture->currenttexmatrix;
1905 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1906 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1907 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1908 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
1910 GL_ColorMask(0,0,0,1);
1911 // this squares the result
1912 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1913 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1914 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1915 GL_LockArrays(0, 0);
1917 memset(&m, 0, sizeof(m));
1918 m.pointer_vertex = rsurface_vertex3f;
1920 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1921 // square alpha in framebuffer a few times to make it shiny
1922 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1923 // these comments are a test run through this math for intensity 0.5
1924 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1925 // 0.25 * 0.25 = 0.0625 (this is another pass)
1926 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1927 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1928 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1929 GL_LockArrays(0, 0);
1931 memset(&m, 0, sizeof(m));
1932 m.pointer_vertex = rsurface_vertex3f;
1933 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1935 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1936 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1938 m.pointer_texcoord[0] = varray_texcoord2f[0];
1939 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[0] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
1941 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1943 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1944 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1946 m.pointer_texcoord[1] = varray_texcoord2f[1];
1947 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
1950 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1951 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1952 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1953 GL_LockArrays(0, 0);
1955 memset(&m, 0, sizeof(m));
1956 m.pointer_vertex = rsurface_vertex3f;
1957 m.tex[0] = R_GetTexture(glosstexture);
1958 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1959 m.texmatrix[0] = texture->currenttexmatrix;
1960 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1962 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1964 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1965 m.texmatrix[1] = r_shadow_entitytolight;
1967 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1968 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytolight);
1971 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1974 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1975 VectorScale(lightcolorbase, colorscale, color2);
1976 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1977 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1979 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1980 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1982 GL_LockArrays(0, 0);
1985 static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1987 // ARB path (any Geforce, any Radeon)
1988 int surfacelistindex;
1989 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1990 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1991 qboolean dospecular = specularscale > 0;
1992 if (!doambient && !dodiffuse && !dospecular)
1994 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1996 const msurface_t *surface = surfacelist[surfacelistindex];
1997 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, true);
1999 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
2001 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
2005 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
2007 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
2012 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
2014 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
2017 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(ent, texture, surface, lightcolorbase, glosstexture, normalmaptexture, specularscale);
2021 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
2024 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
2025 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
2026 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
2031 // due to low fillrate on the cards this vertex lighting path is
2032 // designed for, we manually cull all triangles that do not
2033 // contain a lit vertex
2036 int newnumtriangles;
2038 int newelements[3072];
2040 newnumtriangles = 0;
2042 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
2044 if (newnumtriangles >= 1024)
2046 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2047 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
2048 GL_LockArrays(0, 0);
2049 newnumtriangles = 0;
2052 if (VectorLength2(varray_color4f + e[0] * 4) + VectorLength2(varray_color4f + e[1] * 4) + VectorLength2(varray_color4f + e[2] * 4) >= 0.01)
2062 if (newnumtriangles >= 1)
2064 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2065 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
2066 GL_LockArrays(0, 0);
2072 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
2073 if (VectorLength2(c))
2077 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2078 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
2079 GL_LockArrays(0, 0);
2081 // now reduce the intensity for the next overbright pass
2082 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
2084 c[0] = max(0, c[0] - 1);
2085 c[1] = max(0, c[1] - 1);
2086 c[2] = max(0, c[2] - 1);
2091 static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
2093 int surfacelistindex;
2094 float ambientcolorbase[3], diffusecolorbase[3];
2095 float ambientcolorpants[3], diffusecolorpants[3];
2096 float ambientcolorshirt[3], diffusecolorshirt[3];
2098 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
2099 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
2100 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
2101 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
2102 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
2103 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
2104 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2105 memset(&m, 0, sizeof(m));
2106 m.tex[0] = R_GetTexture(basetexture);
2107 if (r_textureunits.integer >= 2)
2110 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2112 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2114 m.pointer_texcoord[1] = varray_texcoord2f[1];
2115 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2117 if (r_textureunits.integer >= 3)
2119 // Geforce3/Radeon class but not using dot3
2120 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2122 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2124 m.pointer_texcoord[2] = varray_texcoord2f[2];
2125 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2129 m.pointer_color = varray_color4f;
2131 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2133 const msurface_t *surface = surfacelist[surfacelistindex];
2134 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, true, false);
2135 // OpenGL 1.1 path (anything)
2136 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2137 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
2138 if (r_textureunits.integer >= 2)
2142 R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
2144 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[1] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationxyz);
2146 if (r_textureunits.integer >= 3)
2148 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2150 R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
2152 R_Shadow_Transform_Vertex3f_Texcoord2f(varray_texcoord2f[2] + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, &r_shadow_entitytoattenuationz);
2156 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2157 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorbase, ambientcolorbase);
2160 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2161 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorpants, ambientcolorpants);
2165 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2166 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorshirt, ambientcolorshirt);
2171 void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
2173 // FIXME: support MATERIALFLAG_NODEPTHTEST
2174 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2175 // calculate colors to render this texture with
2176 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
2177 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
2178 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
2179 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2181 if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
2182 qglDisable(GL_CULL_FACE);
2184 qglEnable(GL_CULL_FACE);
2185 if (texture->colormapping)
2187 qboolean dopants = texture->skin.pants != NULL && VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f);
2188 qboolean doshirt = texture->skin.shirt != NULL && VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2191 lightcolorpants[0] = lightcolorbase[0] * ent->colormap_pantscolor[0];
2192 lightcolorpants[1] = lightcolorbase[1] * ent->colormap_pantscolor[1];
2193 lightcolorpants[2] = lightcolorbase[2] * ent->colormap_pantscolor[2];
2196 VectorClear(lightcolorpants);
2199 lightcolorshirt[0] = lightcolorbase[0] * ent->colormap_shirtcolor[0];
2200 lightcolorshirt[1] = lightcolorbase[1] * ent->colormap_shirtcolor[1];
2201 lightcolorshirt[2] = lightcolorbase[2] * ent->colormap_shirtcolor[2];
2204 VectorClear(lightcolorshirt);
2205 switch (r_shadow_rendermode)
2207 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2208 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
2210 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2211 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
2213 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2214 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
2216 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2217 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
2220 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2226 switch (r_shadow_rendermode)
2228 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2229 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2231 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2232 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2234 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2235 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2237 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2238 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2241 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2247 void R_RTLight_Update(dlight_t *light, int isstatic)
2251 rtlight_t *rtlight = &light->rtlight;
2252 R_RTLight_Uncompile(rtlight);
2253 memset(rtlight, 0, sizeof(*rtlight));
2255 VectorCopy(light->origin, rtlight->shadoworigin);
2256 VectorCopy(light->color, rtlight->color);
2257 rtlight->radius = light->radius;
2258 //rtlight->cullradius = rtlight->radius;
2259 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2260 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2261 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2262 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2263 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2264 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2265 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2266 rtlight->cubemapname[0] = 0;
2267 if (light->cubemapname[0])
2268 strcpy(rtlight->cubemapname, light->cubemapname);
2269 else if (light->cubemapnum > 0)
2270 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2271 rtlight->shadow = light->shadow;
2272 rtlight->corona = light->corona;
2273 rtlight->style = light->style;
2274 rtlight->isstatic = isstatic;
2275 rtlight->coronasizescale = light->coronasizescale;
2276 rtlight->ambientscale = light->ambientscale;
2277 rtlight->diffusescale = light->diffusescale;
2278 rtlight->specularscale = light->specularscale;
2279 rtlight->flags = light->flags;
2280 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2281 // ConcatScale won't work here because this needs to scale rotate and
2282 // translate, not just rotate
2283 scale = 1.0f / rtlight->radius;
2284 for (k = 0;k < 3;k++)
2285 for (j = 0;j < 4;j++)
2286 rtlight->matrix_worldtolight.m[k][j] *= scale;
2289 // compiles rtlight geometry
2290 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2291 void R_RTLight_Compile(rtlight_t *rtlight)
2293 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2294 entity_render_t *ent = r_refdef.worldentity;
2295 model_t *model = r_refdef.worldmodel;
2296 unsigned char *data;
2298 // compile the light
2299 rtlight->compiled = true;
2300 rtlight->static_numleafs = 0;
2301 rtlight->static_numleafpvsbytes = 0;
2302 rtlight->static_leaflist = NULL;
2303 rtlight->static_leafpvs = NULL;
2304 rtlight->static_numsurfaces = 0;
2305 rtlight->static_surfacelist = NULL;
2306 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2307 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2308 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2309 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2310 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2311 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2313 if (model && model->GetLightInfo)
2315 // this variable must be set for the CompileShadowVolume code
2316 r_shadow_compilingrtlight = rtlight;
2317 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2318 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2319 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2320 data = (unsigned char *)Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2321 rtlight->static_numleafs = numleafs;
2322 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2323 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2324 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2325 rtlight->static_numsurfaces = numsurfaces;
2326 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2328 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2329 if (numleafpvsbytes)
2330 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2332 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2333 if (model->CompileShadowVolume && rtlight->shadow)
2334 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2335 // now we're done compiling the rtlight
2336 r_shadow_compilingrtlight = NULL;
2340 // use smallest available cullradius - box radius or light radius
2341 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2342 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2346 if (rtlight->static_meshchain_shadow)
2349 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2352 shadowtris += mesh->numtriangles;
2356 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes);
2359 void R_RTLight_Uncompile(rtlight_t *rtlight)
2361 if (rtlight->compiled)
2363 if (rtlight->static_meshchain_shadow)
2364 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2365 rtlight->static_meshchain_shadow = NULL;
2366 // these allocations are grouped
2367 if (rtlight->static_leaflist)
2368 Mem_Free(rtlight->static_leaflist);
2369 rtlight->static_numleafs = 0;
2370 rtlight->static_numleafpvsbytes = 0;
2371 rtlight->static_leaflist = NULL;
2372 rtlight->static_leafpvs = NULL;
2373 rtlight->static_numsurfaces = 0;
2374 rtlight->static_surfacelist = NULL;
2375 rtlight->compiled = false;
2379 void R_Shadow_UncompileWorldLights(void)
2382 for (light = r_shadow_worldlightchain;light;light = light->next)
2383 R_RTLight_Uncompile(&light->rtlight);
2386 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2388 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2389 vec_t relativeshadowradius;
2390 if (ent == r_refdef.worldentity)
2392 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2395 R_Mesh_Matrix(&ent->matrix);
2396 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2398 renderstats.lights_shadowtriangles += mesh->numtriangles;
2399 R_Mesh_VertexPointer(mesh->vertex3f);
2400 GL_LockArrays(0, mesh->numverts);
2401 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2403 // decrement stencil if backface is behind depthbuffer
2404 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2405 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2406 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2407 // increment stencil if frontface is behind depthbuffer
2408 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2409 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2411 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2412 GL_LockArrays(0, 0);
2415 else if (numsurfaces)
2417 R_Mesh_Matrix(&ent->matrix);
2418 ent->model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2423 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2424 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2425 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2426 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2427 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2428 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2429 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2430 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2431 R_Mesh_Matrix(&ent->matrix);
2432 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2436 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2438 // set up properties for rendering light onto this entity
2439 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2440 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2441 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2442 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2443 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2444 R_Mesh_Matrix(&ent->matrix);
2447 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2449 R_Shadow_SetupEntityLight(ent);
2450 if (ent == r_refdef.worldentity)
2451 ent->model->DrawLight(ent, numsurfaces, surfacelist);
2453 ent->model->DrawLight(ent, ent->model->nummodelsurfaces, ent->model->surfacelist);
2456 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2460 int numleafs, numsurfaces;
2461 int *leaflist, *surfacelist;
2462 unsigned char *leafpvs;
2463 int numlightentities;
2464 int numshadowentities;
2465 entity_render_t *lightentities[MAX_EDICTS];
2466 entity_render_t *shadowentities[MAX_EDICTS];
2468 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2469 // skip lights that are basically invisible (color 0 0 0)
2470 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2473 // loading is done before visibility checks because loading should happen
2474 // all at once at the start of a level, not when it stalls gameplay.
2475 // (especially important to benchmarks)
2477 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2478 R_RTLight_Compile(rtlight);
2480 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2482 // look up the light style value at this time
2483 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2484 VectorScale(rtlight->color, f, rtlight->currentcolor);
2486 if (rtlight->selected)
2488 f = 2 + sin(realtime * M_PI * 4.0);
2489 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2493 // if lightstyle is currently off, don't draw the light
2494 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2497 // if the light box is offscreen, skip it
2498 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2501 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2503 // compiled light, world available and can receive realtime lighting
2504 // retrieve leaf information
2505 numleafs = rtlight->static_numleafs;
2506 leaflist = rtlight->static_leaflist;
2507 leafpvs = rtlight->static_leafpvs;
2508 numsurfaces = rtlight->static_numsurfaces;
2509 surfacelist = rtlight->static_surfacelist;
2511 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2513 // dynamic light, world available and can receive realtime lighting
2514 // calculate lit surfaces and leafs
2515 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2516 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2517 leaflist = r_shadow_buffer_leaflist;
2518 leafpvs = r_shadow_buffer_leafpvs;
2519 surfacelist = r_shadow_buffer_surfacelist;
2520 // if the reduced leaf bounds are offscreen, skip it
2521 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2533 // check if light is illuminating any visible leafs
2536 for (i = 0;i < numleafs;i++)
2537 if (r_worldleafvisible[leaflist[i]])
2542 // set up a scissor rectangle for this light
2543 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2546 // make a list of lit entities and shadow casting entities
2547 numlightentities = 0;
2548 numshadowentities = 0;
2549 // don't count the world unless some surfaces are actually lit
2552 lightentities[numlightentities++] = r_refdef.worldentity;
2553 shadowentities[numshadowentities++] = r_refdef.worldentity;
2555 // add dynamic entities that are lit by the light
2556 if (r_drawentities.integer)
2558 for (i = 0;i < r_refdef.numentities;i++)
2560 entity_render_t *ent = r_refdef.entities[i];
2561 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2563 && !(ent->flags & RENDER_TRANSPARENT)
2564 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2566 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2567 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2568 shadowentities[numshadowentities++] = ent;
2569 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2570 lightentities[numlightentities++] = ent;
2575 // return if there's nothing at all to light
2576 if (!numlightentities)
2579 // don't let sound skip if going slow
2580 if (r_refdef.extraupdate)
2583 // make this the active rtlight for rendering purposes
2584 R_Shadow_RenderMode_ActiveLight(rtlight);
2585 // count this light in the r_speeds
2586 renderstats.lights++;
2589 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2591 // draw stencil shadow volumes to mask off pixels that are in shadow
2592 // so that they won't receive lighting
2596 R_Shadow_RenderMode_StencilShadowVolumes();
2597 for (i = 0;i < numshadowentities;i++)
2598 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2601 // optionally draw visible shape of the shadow volumes
2602 // for performance analysis by level designers
2603 if (r_showshadowvolumes.integer)
2605 R_Shadow_RenderMode_VisibleShadowVolumes();
2606 for (i = 0;i < numshadowentities;i++)
2607 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2611 if (numlightentities)
2613 // draw lighting in the unmasked areas
2614 R_Shadow_RenderMode_Lighting(usestencil, false);
2615 for (i = 0;i < numlightentities;i++)
2616 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2618 // optionally draw the illuminated areas
2619 // for performance analysis by level designers
2620 if (r_showlighting.integer)
2622 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2623 for (i = 0;i < numlightentities;i++)
2624 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2629 void R_ShadowVolumeLighting(qboolean visible)
2634 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2635 R_Shadow_EditLights_Reload_f();
2637 R_Shadow_RenderMode_Begin();
2639 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2640 if (r_shadow_debuglight.integer >= 0)
2642 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2643 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2644 R_DrawRTLight(&light->rtlight, visible);
2647 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2648 if (light->flags & flag)
2649 R_DrawRTLight(&light->rtlight, visible);
2651 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2652 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2654 R_Shadow_RenderMode_End();
2657 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2658 typedef struct suffixinfo_s
2661 qboolean flipx, flipy, flipdiagonal;
2664 static suffixinfo_t suffix[3][6] =
2667 {"px", false, false, false},
2668 {"nx", false, false, false},
2669 {"py", false, false, false},
2670 {"ny", false, false, false},
2671 {"pz", false, false, false},
2672 {"nz", false, false, false}
2675 {"posx", false, false, false},
2676 {"negx", false, false, false},
2677 {"posy", false, false, false},
2678 {"negy", false, false, false},
2679 {"posz", false, false, false},
2680 {"negz", false, false, false}
2683 {"rt", true, false, true},
2684 {"lf", false, true, true},
2685 {"ft", true, true, false},
2686 {"bk", false, false, false},
2687 {"up", true, false, true},
2688 {"dn", true, false, true}
2692 static int componentorder[4] = {0, 1, 2, 3};
2694 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2696 int i, j, cubemapsize;
2697 unsigned char *cubemappixels, *image_rgba;
2698 rtexture_t *cubemaptexture;
2700 // must start 0 so the first loadimagepixels has no requested width/height
2702 cubemappixels = NULL;
2703 cubemaptexture = NULL;
2704 // keep trying different suffix groups (posx, px, rt) until one loads
2705 for (j = 0;j < 3 && !cubemappixels;j++)
2707 // load the 6 images in the suffix group
2708 for (i = 0;i < 6;i++)
2710 // generate an image name based on the base and and suffix
2711 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2713 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2715 // an image loaded, make sure width and height are equal
2716 if (image_width == image_height)
2718 // if this is the first image to load successfully, allocate the cubemap memory
2719 if (!cubemappixels && image_width >= 1)
2721 cubemapsize = image_width;
2722 // note this clears to black, so unavailable sides are black
2723 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2725 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2727 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);
2730 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2732 Mem_Free(image_rgba);
2736 // if a cubemap loaded, upload it
2739 if (!r_shadow_filters_texturepool)
2740 r_shadow_filters_texturepool = R_AllocTexturePool();
2741 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2742 Mem_Free(cubemappixels);
2746 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2747 for (j = 0;j < 3;j++)
2748 for (i = 0;i < 6;i++)
2749 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2750 Con_Print(" and was unable to find any of them.\n");
2752 return cubemaptexture;
2755 rtexture_t *R_Shadow_Cubemap(const char *basename)
2758 for (i = 0;i < numcubemaps;i++)
2759 if (!strcasecmp(cubemaps[i].basename, basename))
2760 return cubemaps[i].texture;
2761 if (i >= MAX_CUBEMAPS)
2762 return r_texture_whitecube;
2764 strcpy(cubemaps[i].basename, basename);
2765 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2766 if (!cubemaps[i].texture)
2767 cubemaps[i].texture = r_texture_whitecube;
2768 return cubemaps[i].texture;
2771 void R_Shadow_FreeCubemaps(void)
2774 R_FreeTexturePool(&r_shadow_filters_texturepool);
2777 dlight_t *R_Shadow_NewWorldLight(void)
2780 light = (dlight_t *)Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2781 light->next = r_shadow_worldlightchain;
2782 r_shadow_worldlightchain = light;
2786 void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2788 VectorCopy(origin, light->origin);
2789 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2790 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2791 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2792 light->color[0] = max(color[0], 0);
2793 light->color[1] = max(color[1], 0);
2794 light->color[2] = max(color[2], 0);
2795 light->radius = max(radius, 0);
2796 light->style = style;
2797 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2799 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2802 light->shadow = shadowenable;
2803 light->corona = corona;
2806 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2807 light->coronasizescale = coronasizescale;
2808 light->ambientscale = ambientscale;
2809 light->diffusescale = diffusescale;
2810 light->specularscale = specularscale;
2811 light->flags = flags;
2812 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2814 R_RTLight_Update(light, true);
2817 void R_Shadow_FreeWorldLight(dlight_t *light)
2819 dlight_t **lightpointer;
2820 R_RTLight_Uncompile(&light->rtlight);
2821 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2822 if (*lightpointer != light)
2823 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2824 *lightpointer = light->next;
2828 void R_Shadow_ClearWorldLights(void)
2830 while (r_shadow_worldlightchain)
2831 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2832 r_shadow_selectedlight = NULL;
2833 R_Shadow_FreeCubemaps();
2836 void R_Shadow_SelectLight(dlight_t *light)
2838 if (r_shadow_selectedlight)
2839 r_shadow_selectedlight->selected = false;
2840 r_shadow_selectedlight = light;
2841 if (r_shadow_selectedlight)
2842 r_shadow_selectedlight->selected = true;
2845 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2847 float scale = r_editlights_cursorgrid.value * 0.5f;
2848 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[0]->tex, NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
2851 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2854 const dlight_t *light = (dlight_t *)ent;
2856 if (light->selected)
2857 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2860 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacenumber]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
2863 void R_Shadow_DrawLightSprites(void)
2868 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2869 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2870 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2873 void R_Shadow_SelectLightInView(void)
2875 float bestrating, rating, temp[3];
2876 dlight_t *best, *light;
2879 for (light = r_shadow_worldlightchain;light;light = light->next)
2881 VectorSubtract(light->origin, r_vieworigin, temp);
2882 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2885 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2886 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2888 bestrating = rating;
2893 R_Shadow_SelectLight(best);
2896 void R_Shadow_LoadWorldLights(void)
2898 int n, a, style, shadow, flags;
2899 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2900 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2901 if (r_refdef.worldmodel == NULL)
2903 Con_Print("No map loaded.\n");
2906 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2907 strlcat (name, ".rtlights", sizeof (name));
2908 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2918 for (;COM_Parse(t, true) && strcmp(
2919 if (COM_Parse(t, true))
2921 if (com_token[0] == '!')
2924 origin[0] = atof(com_token+1);
2927 origin[0] = atof(com_token);
2932 while (*s && *s != '\n' && *s != '\r')
2938 // check for modifier flags
2945 a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
2948 flags = LIGHTFLAG_REALTIMEMODE;
2956 coronasizescale = 0.25f;
2958 VectorClear(angles);
2961 if (a < 9 || !strcmp(cubemapname, "\"\""))
2963 // remove quotes on cubemapname
2964 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2966 cubemapname[strlen(cubemapname)-1] = 0;
2967 strcpy(cubemapname, cubemapname + 1);
2971 Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1);
2974 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2982 Con_Printf("invalid rtlights file \"%s\"\n", name);
2983 Mem_Free(lightsstring);
2987 void R_Shadow_SaveWorldLights(void)
2990 size_t bufchars, bufmaxchars;
2992 char name[MAX_QPATH];
2993 char line[MAX_INPUTLINE];
2994 if (!r_shadow_worldlightchain)
2996 if (r_refdef.worldmodel == NULL)
2998 Con_Print("No map loaded.\n");
3001 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3002 strlcat (name, ".rtlights", sizeof (name));
3003 bufchars = bufmaxchars = 0;
3005 for (light = r_shadow_worldlightchain;light;light = light->next)
3007 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3008 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
3009 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3010 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, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
3012 sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style);
3013 if (bufchars + strlen(line) > bufmaxchars)
3015 bufmaxchars = bufchars + strlen(line) + 2048;
3017 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3021 memcpy(buf, oldbuf, bufchars);
3027 memcpy(buf + bufchars, line, strlen(line));
3028 bufchars += strlen(line);
3032 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3037 void R_Shadow_LoadLightsFile(void)
3040 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3041 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3042 if (r_refdef.worldmodel == NULL)
3044 Con_Print("No map loaded.\n");
3047 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3048 strlcat (name, ".lights", sizeof (name));
3049 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3057 while (*s && *s != '\n' && *s != '\r')
3063 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);
3067 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);
3070 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3071 radius = bound(15, radius, 4096);
3072 VectorScale(color, (2.0f / (8388608.0f)), color);
3073 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3081 Con_Printf("invalid lights file \"%s\"\n", name);
3082 Mem_Free(lightsstring);
3086 // tyrlite/hmap2 light types in the delay field
3087 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3089 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3091 int entnum, style, islight, skin, pflags, effects, type, n;
3094 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3095 char key[256], value[MAX_INPUTLINE];
3097 if (r_refdef.worldmodel == NULL)
3099 Con_Print("No map loaded.\n");
3102 // try to load a .ent file first
3103 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3104 strlcat (key, ".ent", sizeof (key));
3105 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3106 // and if that is not found, fall back to the bsp file entity string
3108 data = r_refdef.worldmodel->brush.entities;
3111 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3113 type = LIGHTTYPE_MINUSX;
3114 origin[0] = origin[1] = origin[2] = 0;
3115 originhack[0] = originhack[1] = originhack[2] = 0;
3116 angles[0] = angles[1] = angles[2] = 0;
3117 color[0] = color[1] = color[2] = 1;
3118 light[0] = light[1] = light[2] = 1;light[3] = 300;
3119 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3129 if (!COM_ParseToken(&data, false))
3131 if (com_token[0] == '}')
3132 break; // end of entity
3133 if (com_token[0] == '_')
3134 strcpy(key, com_token + 1);
3136 strcpy(key, com_token);
3137 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3138 key[strlen(key)-1] = 0;
3139 if (!COM_ParseToken(&data, false))
3141 strcpy(value, com_token);
3143 // now that we have the key pair worked out...
3144 if (!strcmp("light", key))
3146 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3150 light[0] = vec[0] * (1.0f / 256.0f);
3151 light[1] = vec[0] * (1.0f / 256.0f);
3152 light[2] = vec[0] * (1.0f / 256.0f);
3158 light[0] = vec[0] * (1.0f / 255.0f);
3159 light[1] = vec[1] * (1.0f / 255.0f);
3160 light[2] = vec[2] * (1.0f / 255.0f);
3164 else if (!strcmp("delay", key))
3166 else if (!strcmp("origin", key))
3167 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3168 else if (!strcmp("angle", key))
3169 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3170 else if (!strcmp("angles", key))
3171 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3172 else if (!strcmp("color", key))
3173 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3174 else if (!strcmp("wait", key))
3175 fadescale = atof(value);
3176 else if (!strcmp("classname", key))
3178 if (!strncmp(value, "light", 5))
3181 if (!strcmp(value, "light_fluoro"))
3186 overridecolor[0] = 1;
3187 overridecolor[1] = 1;
3188 overridecolor[2] = 1;
3190 if (!strcmp(value, "light_fluorospark"))
3195 overridecolor[0] = 1;
3196 overridecolor[1] = 1;
3197 overridecolor[2] = 1;
3199 if (!strcmp(value, "light_globe"))
3204 overridecolor[0] = 1;
3205 overridecolor[1] = 0.8;
3206 overridecolor[2] = 0.4;
3208 if (!strcmp(value, "light_flame_large_yellow"))
3213 overridecolor[0] = 1;
3214 overridecolor[1] = 0.5;
3215 overridecolor[2] = 0.1;
3217 if (!strcmp(value, "light_flame_small_yellow"))
3222 overridecolor[0] = 1;
3223 overridecolor[1] = 0.5;
3224 overridecolor[2] = 0.1;
3226 if (!strcmp(value, "light_torch_small_white"))
3231 overridecolor[0] = 1;
3232 overridecolor[1] = 0.5;
3233 overridecolor[2] = 0.1;
3235 if (!strcmp(value, "light_torch_small_walltorch"))
3240 overridecolor[0] = 1;
3241 overridecolor[1] = 0.5;
3242 overridecolor[2] = 0.1;
3246 else if (!strcmp("style", key))
3247 style = atoi(value);
3248 else if (!strcmp("skin", key))
3249 skin = (int)atof(value);
3250 else if (!strcmp("pflags", key))
3251 pflags = (int)atof(value);
3252 else if (!strcmp("effects", key))
3253 effects = (int)atof(value);
3254 else if (r_refdef.worldmodel->type == mod_brushq3)
3256 if (!strcmp("scale", key))
3257 lightscale = atof(value);
3258 if (!strcmp("fade", key))
3259 fadescale = atof(value);
3264 if (lightscale <= 0)
3268 if (color[0] == color[1] && color[0] == color[2])
3270 color[0] *= overridecolor[0];
3271 color[1] *= overridecolor[1];
3272 color[2] *= overridecolor[2];
3274 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3275 color[0] = color[0] * light[0];
3276 color[1] = color[1] * light[1];
3277 color[2] = color[2] * light[2];
3280 case LIGHTTYPE_MINUSX:
3282 case LIGHTTYPE_RECIPX:
3284 VectorScale(color, (1.0f / 16.0f), color);
3286 case LIGHTTYPE_RECIPXX:
3288 VectorScale(color, (1.0f / 16.0f), color);
3291 case LIGHTTYPE_NONE:
3295 case LIGHTTYPE_MINUSXX:
3298 VectorAdd(origin, originhack, origin);
3300 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3303 Mem_Free(entfiledata);
3307 void R_Shadow_SetCursorLocationForView(void)
3310 vec3_t dest, endpos;
3312 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3313 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3314 if (trace.fraction < 1)
3316 dist = trace.fraction * r_editlights_cursordistance.value;
3317 push = r_editlights_cursorpushback.value;
3321 VectorMA(trace.endpos, push, r_viewforward, endpos);
3322 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3326 VectorClear( endpos );
3328 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3329 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3330 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3333 void R_Shadow_UpdateWorldLightSelection(void)
3335 if (r_editlights.integer)
3337 R_Shadow_SetCursorLocationForView();
3338 R_Shadow_SelectLightInView();
3339 R_Shadow_DrawLightSprites();
3342 R_Shadow_SelectLight(NULL);
3345 void R_Shadow_EditLights_Clear_f(void)
3347 R_Shadow_ClearWorldLights();
3350 void R_Shadow_EditLights_Reload_f(void)
3352 if (!r_refdef.worldmodel)
3354 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3355 R_Shadow_ClearWorldLights();
3356 R_Shadow_LoadWorldLights();
3357 if (r_shadow_worldlightchain == NULL)
3359 R_Shadow_LoadLightsFile();
3360 if (r_shadow_worldlightchain == NULL)
3361 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3365 void R_Shadow_EditLights_Save_f(void)
3367 if (!r_refdef.worldmodel)
3369 R_Shadow_SaveWorldLights();
3372 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3374 R_Shadow_ClearWorldLights();
3375 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3378 void R_Shadow_EditLights_ImportLightsFile_f(void)
3380 R_Shadow_ClearWorldLights();
3381 R_Shadow_LoadLightsFile();
3384 void R_Shadow_EditLights_Spawn_f(void)
3387 if (!r_editlights.integer)
3389 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3392 if (Cmd_Argc() != 1)
3394 Con_Print("r_editlights_spawn does not take parameters\n");
3397 color[0] = color[1] = color[2] = 1;
3398 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3401 void R_Shadow_EditLights_Edit_f(void)
3403 vec3_t origin, angles, color;
3404 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3405 int style, shadows, flags, normalmode, realtimemode;
3406 char cubemapname[MAX_INPUTLINE];
3407 if (!r_editlights.integer)
3409 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3412 if (!r_shadow_selectedlight)
3414 Con_Print("No selected light.\n");
3417 VectorCopy(r_shadow_selectedlight->origin, origin);
3418 VectorCopy(r_shadow_selectedlight->angles, angles);
3419 VectorCopy(r_shadow_selectedlight->color, color);
3420 radius = r_shadow_selectedlight->radius;
3421 style = r_shadow_selectedlight->style;
3422 if (r_shadow_selectedlight->cubemapname)
3423 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3426 shadows = r_shadow_selectedlight->shadow;
3427 corona = r_shadow_selectedlight->corona;
3428 coronasizescale = r_shadow_selectedlight->coronasizescale;
3429 ambientscale = r_shadow_selectedlight->ambientscale;
3430 diffusescale = r_shadow_selectedlight->diffusescale;
3431 specularscale = r_shadow_selectedlight->specularscale;
3432 flags = r_shadow_selectedlight->flags;
3433 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3434 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3435 if (!strcmp(Cmd_Argv(1), "origin"))
3437 if (Cmd_Argc() != 5)
3439 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3442 origin[0] = atof(Cmd_Argv(2));
3443 origin[1] = atof(Cmd_Argv(3));
3444 origin[2] = atof(Cmd_Argv(4));
3446 else if (!strcmp(Cmd_Argv(1), "originx"))
3448 if (Cmd_Argc() != 3)
3450 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3453 origin[0] = atof(Cmd_Argv(2));
3455 else if (!strcmp(Cmd_Argv(1), "originy"))
3457 if (Cmd_Argc() != 3)
3459 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3462 origin[1] = atof(Cmd_Argv(2));
3464 else if (!strcmp(Cmd_Argv(1), "originz"))
3466 if (Cmd_Argc() != 3)
3468 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3471 origin[2] = atof(Cmd_Argv(2));
3473 else if (!strcmp(Cmd_Argv(1), "move"))
3475 if (Cmd_Argc() != 5)
3477 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3480 origin[0] += atof(Cmd_Argv(2));
3481 origin[1] += atof(Cmd_Argv(3));
3482 origin[2] += atof(Cmd_Argv(4));
3484 else if (!strcmp(Cmd_Argv(1), "movex"))
3486 if (Cmd_Argc() != 3)
3488 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3491 origin[0] += atof(Cmd_Argv(2));
3493 else if (!strcmp(Cmd_Argv(1), "movey"))
3495 if (Cmd_Argc() != 3)
3497 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3500 origin[1] += atof(Cmd_Argv(2));
3502 else if (!strcmp(Cmd_Argv(1), "movez"))
3504 if (Cmd_Argc() != 3)
3506 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3509 origin[2] += atof(Cmd_Argv(2));
3511 else if (!strcmp(Cmd_Argv(1), "angles"))
3513 if (Cmd_Argc() != 5)
3515 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3518 angles[0] = atof(Cmd_Argv(2));
3519 angles[1] = atof(Cmd_Argv(3));
3520 angles[2] = atof(Cmd_Argv(4));
3522 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3524 if (Cmd_Argc() != 3)
3526 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3529 angles[0] = atof(Cmd_Argv(2));
3531 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3533 if (Cmd_Argc() != 3)
3535 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3538 angles[1] = atof(Cmd_Argv(2));
3540 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3542 if (Cmd_Argc() != 3)
3544 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3547 angles[2] = atof(Cmd_Argv(2));
3549 else if (!strcmp(Cmd_Argv(1), "color"))
3551 if (Cmd_Argc() != 5)
3553 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3556 color[0] = atof(Cmd_Argv(2));
3557 color[1] = atof(Cmd_Argv(3));
3558 color[2] = atof(Cmd_Argv(4));
3560 else if (!strcmp(Cmd_Argv(1), "radius"))
3562 if (Cmd_Argc() != 3)
3564 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3567 radius = atof(Cmd_Argv(2));
3569 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3571 if (Cmd_Argc() == 3)
3573 double scale = atof(Cmd_Argv(2));
3580 if (Cmd_Argc() != 5)
3582 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3585 color[0] *= atof(Cmd_Argv(2));
3586 color[1] *= atof(Cmd_Argv(3));
3587 color[2] *= atof(Cmd_Argv(4));
3590 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3592 if (Cmd_Argc() != 3)
3594 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3597 radius *= atof(Cmd_Argv(2));
3599 else if (!strcmp(Cmd_Argv(1), "style"))
3601 if (Cmd_Argc() != 3)
3603 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3606 style = atoi(Cmd_Argv(2));
3608 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3612 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3615 if (Cmd_Argc() == 3)
3616 strcpy(cubemapname, Cmd_Argv(2));
3620 else if (!strcmp(Cmd_Argv(1), "shadows"))
3622 if (Cmd_Argc() != 3)
3624 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3627 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3629 else if (!strcmp(Cmd_Argv(1), "corona"))
3631 if (Cmd_Argc() != 3)
3633 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3636 corona = atof(Cmd_Argv(2));
3638 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3640 if (Cmd_Argc() != 3)
3642 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3645 coronasizescale = atof(Cmd_Argv(2));
3647 else if (!strcmp(Cmd_Argv(1), "ambient"))
3649 if (Cmd_Argc() != 3)
3651 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3654 ambientscale = atof(Cmd_Argv(2));
3656 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3658 if (Cmd_Argc() != 3)
3660 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3663 diffusescale = atof(Cmd_Argv(2));
3665 else if (!strcmp(Cmd_Argv(1), "specular"))
3667 if (Cmd_Argc() != 3)
3669 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3672 specularscale = atof(Cmd_Argv(2));
3674 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3676 if (Cmd_Argc() != 3)
3678 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3681 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3683 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3685 if (Cmd_Argc() != 3)
3687 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3690 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3694 Con_Print("usage: r_editlights_edit [property] [value]\n");
3695 Con_Print("Selected light's properties:\n");
3696 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3697 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3698 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3699 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3700 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3701 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3702 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3703 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3704 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3705 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3706 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3707 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3708 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3709 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3712 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3713 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3716 void R_Shadow_EditLights_EditAll_f(void)
3720 if (!r_editlights.integer)
3722 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3726 for (light = r_shadow_worldlightchain;light;light = light->next)
3728 R_Shadow_SelectLight(light);
3729 R_Shadow_EditLights_Edit_f();
3733 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3735 int lightnumber, lightcount;
3739 if (!r_editlights.integer)
3745 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3746 if (light == r_shadow_selectedlight)
3747 lightnumber = lightcount;
3748 sprintf(temp, "Cursor %f %f %f Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3749 if (r_shadow_selectedlight == NULL)
3751 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3752 sprintf(temp, "Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3753 sprintf(temp, "Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3754 sprintf(temp, "Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3755 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3756 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3757 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3758 sprintf(temp, "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3759 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3760 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3761 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3762 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3763 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3764 sprintf(temp, "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3765 sprintf(temp, "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3768 void R_Shadow_EditLights_ToggleShadow_f(void)
3770 if (!r_editlights.integer)
3772 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3775 if (!r_shadow_selectedlight)
3777 Con_Print("No selected light.\n");
3780 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
3783 void R_Shadow_EditLights_ToggleCorona_f(void)
3785 if (!r_editlights.integer)
3787 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3790 if (!r_shadow_selectedlight)
3792 Con_Print("No selected light.\n");
3795 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
3798 void R_Shadow_EditLights_Remove_f(void)
3800 if (!r_editlights.integer)
3802 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3805 if (!r_shadow_selectedlight)
3807 Con_Print("No selected light.\n");
3810 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3811 r_shadow_selectedlight = NULL;
3814 void R_Shadow_EditLights_Help_f(void)
3817 "Documentation on r_editlights system:\n"
3819 "r_editlights : enable/disable editing mode\n"
3820 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3821 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3822 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3823 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3824 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3826 "r_editlights_help : this help\n"
3827 "r_editlights_clear : remove all lights\n"
3828 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3829 "r_editlights_save : save to .rtlights file\n"
3830 "r_editlights_spawn : create a light with default settings\n"
3831 "r_editlights_edit command : edit selected light - more documentation below\n"
3832 "r_editlights_remove : remove selected light\n"
3833 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3834 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3835 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3837 "origin x y z : set light location\n"
3838 "originx x: set x component of light location\n"
3839 "originy y: set y component of light location\n"
3840 "originz z: set z component of light location\n"
3841 "move x y z : adjust light location\n"
3842 "movex x: adjust x component of light location\n"
3843 "movey y: adjust y component of light location\n"
3844 "movez z: adjust z component of light location\n"
3845 "angles x y z : set light angles\n"
3846 "anglesx x: set x component of light angles\n"
3847 "anglesy y: set y component of light angles\n"
3848 "anglesz z: set z component of light angles\n"
3849 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3850 "radius radius : set radius (size) of light\n"
3851 "colorscale grey : multiply color of light (1 does nothing)\n"
3852 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3853 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3854 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3855 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3856 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3857 "shadows 1/0 : turn on/off shadows\n"
3858 "corona n : set corona intensity\n"
3859 "coronasize n : set corona size (0-1)\n"
3860 "ambient n : set ambient intensity (0-1)\n"
3861 "diffuse n : set diffuse intensity (0-1)\n"
3862 "specular n : set specular intensity (0-1)\n"
3863 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3864 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3865 "<nothing> : print light properties to console\n"
3869 void R_Shadow_EditLights_CopyInfo_f(void)
3871 if (!r_editlights.integer)
3873 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3876 if (!r_shadow_selectedlight)
3878 Con_Print("No selected light.\n");
3881 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3882 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3883 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3884 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3885 if (r_shadow_selectedlight->cubemapname)
3886 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3888 r_shadow_bufferlight.cubemapname[0] = 0;
3889 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3890 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3891 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3892 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3893 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3894 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3895 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3898 void R_Shadow_EditLights_PasteInfo_f(void)
3900 if (!r_editlights.integer)
3902 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3905 if (!r_shadow_selectedlight)
3907 Con_Print("No selected light.\n");
3910 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
3913 void R_Shadow_EditLights_Init(void)
3915 Cvar_RegisterVariable(&r_editlights);
3916 Cvar_RegisterVariable(&r_editlights_cursordistance);
3917 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3918 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3919 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3920 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3921 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3922 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3923 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
3924 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3925 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3926 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3927 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f, "changes a property on ALL lights at once (tip: use radiusscale and colorscale to alter these properties)");
3928 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3929 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3930 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3931 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3932 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3933 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3934 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");