3 #include "cl_collision.h"
7 static void R_Shadow_EditLights_Init(void);
9 typedef enum r_shadow_rendermode_e
11 R_SHADOW_RENDERMODE_NONE,
12 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
13 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
14 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
15 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
16 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
17 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
18 R_SHADOW_RENDERMODE_LIGHT_GLSL,
19 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
20 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
21 R_SHADOW_RENDERMODE_SHADOWMAP2D
23 r_shadow_rendermode_t;
25 typedef enum r_shadow_shadowmode_e
27 R_SHADOW_SHADOWMODE_DISABLED,
28 R_SHADOW_SHADOWMODE_SHADOWMAP2D
30 r_shadow_shadowmode_t;
32 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
33 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
34 int r_shadow_scenemaxlights;
35 int r_shadow_scenenumlights;
36 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
37 qboolean r_shadow_usingshadowmap2d;
38 qboolean r_shadow_usingshadowmaportho;
39 int r_shadow_shadowmapside;
40 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
41 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
42 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
43 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
45 int r_shadow_drawbuffer;
46 int r_shadow_readbuffer;
48 int r_shadow_cullface_front, r_shadow_cullface_back;
49 GLuint r_shadow_fbo2d;
50 int r_shadow_shadowmode_shadowmapping; // cached value of r_shadow_shadowmapping cvar
51 int r_shadow_shadowmode_deferred; // cached value of r_shadow_deferred cvar
52 r_shadow_shadowmode_t r_shadow_shadowmode;
53 int r_shadow_shadowmapfilterquality;
54 int r_shadow_shadowmapdepthbits;
55 int r_shadow_shadowmapmaxsize;
56 int r_shadow_shadowmaptexturesize;
57 qboolean r_shadow_shadowmapvsdct;
58 qboolean r_shadow_shadowmapsampler;
59 qboolean r_shadow_shadowmapshadowsampler;
60 int r_shadow_shadowmappcf;
61 int r_shadow_shadowmapborder;
62 matrix4x4_t r_shadow_shadowmapmatrix;
63 int r_shadow_lightscissor[4];
64 qboolean r_shadow_usingdeferredprepass;
65 qboolean r_shadow_shadowmapdepthtexture;
66 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
67 int r_shadow_shadowmapatlas_modelshadows_x;
68 int r_shadow_shadowmapatlas_modelshadows_y;
69 int r_shadow_shadowmapatlas_modelshadows_size;
70 int maxshadowtriangles;
73 int maxshadowvertices;
74 float *shadowvertex3f;
84 unsigned char *shadowsides;
92 int r_shadow_buffer_numleafpvsbytes;
93 unsigned char *r_shadow_buffer_visitingleafpvs;
94 unsigned char *r_shadow_buffer_leafpvs;
95 int *r_shadow_buffer_leaflist;
97 int r_shadow_buffer_numsurfacepvsbytes;
98 unsigned char *r_shadow_buffer_surfacepvs;
99 int *r_shadow_buffer_surfacelist;
100 unsigned char *r_shadow_buffer_surfacesides;
102 int r_shadow_buffer_numshadowtrispvsbytes;
103 unsigned char *r_shadow_buffer_shadowtrispvs;
104 int r_shadow_buffer_numlighttrispvsbytes;
105 unsigned char *r_shadow_buffer_lighttrispvs;
107 rtexturepool_t *r_shadow_texturepool;
108 rtexture_t *r_shadow_attenuationgradienttexture;
109 skinframe_t *r_shadow_lightcorona;
110 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
111 rtexture_t *r_shadow_shadowmap2ddepthtexture;
112 rtexture_t *r_shadow_shadowmapvsdcttexture;
114 GLuint r_shadow_prepassgeometryfbo;
115 GLuint r_shadow_prepasslightingdiffusespecularfbo;
116 GLuint r_shadow_prepasslightingdiffusefbo;
117 int r_shadow_prepass_width;
118 int r_shadow_prepass_height;
119 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
120 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
121 rtexture_t *r_shadow_prepasslightingdiffusetexture;
122 rtexture_t *r_shadow_prepasslightingspeculartexture;
124 int r_shadow_viewfbo;
125 rtexture_t *r_shadow_viewdepthtexture;
126 rtexture_t *r_shadow_viewcolortexture;
129 int r_shadow_viewwidth;
130 int r_shadow_viewheight;
132 // lights are reloaded when this changes
133 char r_shadow_mapname[MAX_QPATH];
135 // buffer for doing corona fading
136 unsigned int r_shadow_occlusion_buf = 0;
138 // used only for light filters (cubemaps)
139 rtexturepool_t *r_shadow_filters_texturepool;
141 cvar_t r_shadow_bumpscale_basetexture = {CVAR_CLIENT, "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"};
142 cvar_t r_shadow_bumpscale_bumpmap = {CVAR_CLIENT, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
143 cvar_t r_shadow_debuglight = {CVAR_CLIENT, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
144 cvar_t r_shadow_deferred = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
145 cvar_t r_shadow_usebihculling = {CVAR_CLIENT, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
146 cvar_t r_shadow_usenormalmap = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
147 cvar_t r_shadow_gloss = {CVAR_CLIENT | 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)"};
148 cvar_t r_shadow_gloss2intensity = {CVAR_CLIENT, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
149 cvar_t r_shadow_glossintensity = {CVAR_CLIENT, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
150 cvar_t r_shadow_glossexponent = {CVAR_CLIENT, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
151 cvar_t r_shadow_gloss2exponent = {CVAR_CLIENT, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
152 cvar_t r_shadow_glossexact = {CVAR_CLIENT, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
153 cvar_t r_shadow_lightattenuationdividebias = {CVAR_CLIENT, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
154 cvar_t r_shadow_lightattenuationlinearscale = {CVAR_CLIENT, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
155 cvar_t r_shadow_lightintensityscale = {CVAR_CLIENT, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
156 cvar_t r_shadow_lightradiusscale = {CVAR_CLIENT, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
157 cvar_t r_shadow_projectdistance = {CVAR_CLIENT, "r_shadow_projectdistance", "0", "how far to cast shadows"};
158 cvar_t r_shadow_frontsidecasting = {CVAR_CLIENT, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
159 cvar_t r_shadow_realtime_dlight = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
160 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
161 cvar_t r_shadow_realtime_dlight_svbspculling = {CVAR_CLIENT, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
162 cvar_t r_shadow_realtime_dlight_portalculling = {CVAR_CLIENT, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
163 cvar_t r_shadow_realtime_world = {CVAR_CLIENT | 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)"};
164 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {CVAR_CLIENT, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
165 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_CLIENT | 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"};
166 cvar_t r_shadow_realtime_world_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
167 cvar_t r_shadow_realtime_world_compile = {CVAR_CLIENT, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
168 cvar_t r_shadow_realtime_world_compileshadow = {CVAR_CLIENT, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
169 cvar_t r_shadow_realtime_world_compilesvbsp = {CVAR_CLIENT, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
170 cvar_t r_shadow_realtime_world_compileportalculling = {CVAR_CLIENT, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
171 cvar_t r_shadow_scissor = {CVAR_CLIENT, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
172 cvar_t r_shadow_shadowmapping = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
173 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
174 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
175 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
176 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
177 cvar_t r_shadow_shadowmapping_minsize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
178 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
179 cvar_t r_shadow_shadowmapping_texturesize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
180 cvar_t r_shadow_shadowmapping_precision = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
181 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
182 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
183 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
184 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
185 cvar_t r_shadow_shadowmapping_bias = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
186 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
187 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
188 cvar_t r_shadow_sortsurfaces = {CVAR_CLIENT, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
189 cvar_t r_shadow_culllights_pvs = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
190 cvar_t r_shadow_culllights_trace = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
191 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
192 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
193 cvar_t r_shadow_culllights_trace_expand = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
194 cvar_t r_shadow_culllights_trace_pad = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_pad", "8", "accept traces that hit within this many units of the light bounds"};
195 cvar_t r_shadow_culllights_trace_samples = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
196 cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"};
197 cvar_t r_shadow_culllights_trace_delay = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
198 cvar_t r_shadow_bouncegrid = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
199 cvar_t r_shadow_bouncegrid_blur = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
200 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color"};
201 cvar_t r_shadow_bouncegrid_dynamic_culllightpaths = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_culllightpaths", "0", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
202 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "1", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
203 cvar_t r_shadow_bouncegrid_dynamic_dlightparticlemultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_dlightparticlemultiplier", "1", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
204 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
205 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1)"};
206 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0)"};
207 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxphotons", "25000", "upper bound on photons to shoot per update, divided proportionately between lights - normally the number of photons is calculated by energyperphoton"};
208 cvar_t r_shadow_bouncegrid_dynamic_quality = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_quality", "1", "amount of photons that should be fired (this is multiplied by spacing ^ 2 to make it adaptive with spacing changes)"};
209 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
210 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
211 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
212 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
213 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
214 cvar_t r_shadow_bouncegrid_floatcolors = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_floatcolors", "1", "upload texture as RGBA16F (or RGBA32F when set to 2) rather than RGBA8 format - this gives more dynamic range and accuracy"};
215 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
216 cvar_t r_shadow_bouncegrid_intensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
217 cvar_t r_shadow_bouncegrid_lightpathsize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize", "64", "radius (in game units) of the light path for accumulation of light in the bouncegrid texture"};
218 cvar_t r_shadow_bouncegrid_normalizevectors = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)"};
219 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "4", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
220 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
221 cvar_t r_shadow_bouncegrid_rng_seed = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_rng_seed", "0", "0+ = use this number as RNG seed, -1 = use time instead for disco-like craziness in dynamic mode"};
222 cvar_t r_shadow_bouncegrid_rng_type = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)"};
223 cvar_t r_shadow_bouncegrid_static = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
224 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color"};
225 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
226 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
227 cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
228 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
229 cvar_t r_shadow_bouncegrid_static_quality = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_quality", "16", "amount of photons that should be fired (this is multiplied by spacing ^ 2 to make it adaptive with spacing changes)"};
230 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
231 cvar_t r_shadow_bouncegrid_subsamples = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_subsamples", "1", "when generating the texture, sample this many points along each dimension (multisampling uses more compute but not more memory bandwidth)"};
232 cvar_t r_shadow_bouncegrid_threaded = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_threaded", "1", "enables use of taskqueue_maxthreads to perform the traces and slice rendering of bouncegrid"};
233 cvar_t r_coronas = {CVAR_CLIENT | CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
234 cvar_t r_coronas_occlusionsizescale = {CVAR_CLIENT | CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
235 cvar_t r_coronas_occlusionquery = {CVAR_CLIENT | CVAR_SAVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"};
236 cvar_t gl_flashblend = {CVAR_CLIENT | CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
237 cvar_t r_editlights = {CVAR_CLIENT, "r_editlights", "0", "enables .rtlights file editing mode"};
238 cvar_t r_editlights_cursordistance = {CVAR_CLIENT, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
239 cvar_t r_editlights_cursorpushback = {CVAR_CLIENT, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
240 cvar_t r_editlights_cursorpushoff = {CVAR_CLIENT, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
241 cvar_t r_editlights_cursorgrid = {CVAR_CLIENT, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
242 cvar_t r_editlights_quakelightsizescale = {CVAR_CLIENT | CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
243 cvar_t r_editlights_drawproperties = {CVAR_CLIENT, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
244 cvar_t r_editlights_current_origin = {CVAR_CLIENT, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
245 cvar_t r_editlights_current_angles = {CVAR_CLIENT, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
246 cvar_t r_editlights_current_color = {CVAR_CLIENT, "r_editlights_current_color", "1 1 1", "color of selected light"};
247 cvar_t r_editlights_current_radius = {CVAR_CLIENT, "r_editlights_current_radius", "0", "radius of selected light"};
248 cvar_t r_editlights_current_corona = {CVAR_CLIENT, "r_editlights_current_corona", "0", "corona intensity of selected light"};
249 cvar_t r_editlights_current_coronasize = {CVAR_CLIENT, "r_editlights_current_coronasize", "0", "corona size of selected light"};
250 cvar_t r_editlights_current_style = {CVAR_CLIENT, "r_editlights_current_style", "0", "style of selected light"};
251 cvar_t r_editlights_current_shadows = {CVAR_CLIENT, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
252 cvar_t r_editlights_current_cubemap = {CVAR_CLIENT, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
253 cvar_t r_editlights_current_ambient = {CVAR_CLIENT, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
254 cvar_t r_editlights_current_diffuse = {CVAR_CLIENT, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
255 cvar_t r_editlights_current_specular = {CVAR_CLIENT, "r_editlights_current_specular", "1", "specular intensity of selected light"};
256 cvar_t r_editlights_current_normalmode = {CVAR_CLIENT, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
257 cvar_t r_editlights_current_realtimemode = {CVAR_CLIENT, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
259 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
261 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
262 #define ATTENTABLESIZE 256
263 // 1D gradient, 2D circle and 3D sphere attenuation textures
264 #define ATTEN1DSIZE 32
265 #define ATTEN2DSIZE 64
266 #define ATTEN3DSIZE 32
268 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
269 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
270 static float r_shadow_attentable[ATTENTABLESIZE+1];
272 rtlight_t *r_shadow_compilingrtlight;
273 static memexpandablearray_t r_shadow_worldlightsarray;
274 dlight_t *r_shadow_selectedlight;
275 dlight_t r_shadow_bufferlight;
276 vec3_t r_editlights_cursorlocation;
277 qboolean r_editlights_lockcursor;
279 extern int con_vislines;
281 void R_Shadow_UncompileWorldLights(void);
282 void R_Shadow_ClearWorldLights(void);
283 void R_Shadow_SaveWorldLights(void);
284 void R_Shadow_LoadWorldLights(void);
285 void R_Shadow_LoadLightsFile(void);
286 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
287 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd);
288 static void R_Shadow_MakeTextures(void);
290 #define EDLIGHTSPRSIZE 8
291 skinframe_t *r_editlights_sprcursor;
292 skinframe_t *r_editlights_sprlight;
293 skinframe_t *r_editlights_sprnoshadowlight;
294 skinframe_t *r_editlights_sprcubemaplight;
295 skinframe_t *r_editlights_sprcubemapnoshadowlight;
296 skinframe_t *r_editlights_sprselection;
298 static void R_Shadow_DrawModelShadowMaps(void);
299 static void R_Shadow_MakeShadowMap(int texturesize);
300 static void R_Shadow_MakeVSDCT(void);
301 static void R_Shadow_SetShadowMode(void)
303 r_shadow_shadowmode_shadowmapping = r_shadow_shadowmapping.integer;
304 r_shadow_shadowmode_deferred = r_shadow_deferred.integer;
305 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
306 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
307 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
308 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
309 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
310 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
311 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
312 r_shadow_shadowmapsampler = false;
313 r_shadow_shadowmappcf = 0;
314 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
315 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_DISABLED;
316 if (r_shadow_shadowmode_shadowmapping || r_shadow_shadowmode_deferred)
318 switch (vid.renderpath)
320 case RENDERPATH_GL32:
321 if (r_shadow_shadowmapfilterquality < 0)
323 if (!r_fb.usedepthtextures)
324 r_shadow_shadowmappcf = 1;
325 else if ((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
327 r_shadow_shadowmapsampler = true;
328 r_shadow_shadowmappcf = 1;
330 else if (vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
331 r_shadow_shadowmappcf = 1;
332 else if ((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
333 r_shadow_shadowmappcf = 1;
335 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
339 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
340 switch (r_shadow_shadowmapfilterquality)
345 r_shadow_shadowmappcf = 1;
348 r_shadow_shadowmappcf = 1;
351 r_shadow_shadowmappcf = 2;
355 if (!r_fb.usedepthtextures)
356 r_shadow_shadowmapsampler = false;
357 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
359 case RENDERPATH_GLES2:
360 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
365 switch (r_shadow_shadowmode)
367 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
368 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
370 case R_SHADOW_SHADOWMODE_DISABLED:
374 if(R_CompileShader_CheckStaticParms())
375 R_GLSL_Restart_f(&cmd_client);
378 qboolean R_Shadow_ShadowMappingEnabled(void)
380 switch (r_shadow_shadowmode)
382 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
384 case R_SHADOW_SHADOWMODE_DISABLED:
390 static void R_Shadow_FreeShadowMaps(void)
392 R_Shadow_UncompileWorldLights();
394 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
396 R_Shadow_SetShadowMode();
398 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
402 if (r_shadow_shadowmap2ddepthtexture)
403 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
404 r_shadow_shadowmap2ddepthtexture = NULL;
406 if (r_shadow_shadowmap2ddepthbuffer)
407 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
408 r_shadow_shadowmap2ddepthbuffer = NULL;
410 if (r_shadow_shadowmapvsdcttexture)
411 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
412 r_shadow_shadowmapvsdcttexture = NULL;
416 static void r_shadow_start(void)
418 // allocate vertex processing arrays
419 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
420 r_shadow_attenuationgradienttexture = NULL;
421 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_DISABLED;
422 r_shadow_shadowmap2ddepthtexture = NULL;
423 r_shadow_shadowmap2ddepthbuffer = NULL;
424 r_shadow_shadowmapvsdcttexture = NULL;
425 r_shadow_shadowmapmaxsize = 0;
426 r_shadow_shadowmaptexturesize = 0;
427 r_shadow_shadowmapfilterquality = -1;
428 r_shadow_shadowmapdepthbits = 0;
429 r_shadow_shadowmapvsdct = false;
430 r_shadow_shadowmapsampler = false;
431 r_shadow_shadowmappcf = 0;
434 R_Shadow_FreeShadowMaps();
436 r_shadow_texturepool = NULL;
437 r_shadow_filters_texturepool = NULL;
438 R_Shadow_MakeTextures();
439 r_shadow_scenemaxlights = 0;
440 r_shadow_scenenumlights = 0;
441 r_shadow_scenelightlist = NULL;
442 maxshadowtriangles = 0;
443 shadowelements = NULL;
444 maxshadowvertices = 0;
445 shadowvertex3f = NULL;
453 shadowmarklist = NULL;
458 shadowsideslist = NULL;
459 r_shadow_buffer_numleafpvsbytes = 0;
460 r_shadow_buffer_visitingleafpvs = NULL;
461 r_shadow_buffer_leafpvs = NULL;
462 r_shadow_buffer_leaflist = NULL;
463 r_shadow_buffer_numsurfacepvsbytes = 0;
464 r_shadow_buffer_surfacepvs = NULL;
465 r_shadow_buffer_surfacelist = NULL;
466 r_shadow_buffer_surfacesides = NULL;
467 r_shadow_buffer_numshadowtrispvsbytes = 0;
468 r_shadow_buffer_shadowtrispvs = NULL;
469 r_shadow_buffer_numlighttrispvsbytes = 0;
470 r_shadow_buffer_lighttrispvs = NULL;
472 r_shadow_usingdeferredprepass = false;
473 r_shadow_prepass_width = r_shadow_prepass_height = 0;
475 // determine renderpath specific capabilities, we don't need to figure
476 // these out per frame...
477 switch(vid.renderpath)
479 case RENDERPATH_GL32:
480 r_shadow_bouncegrid_state.allowdirectionalshading = true;
481 r_shadow_bouncegrid_state.capable = true;
483 case RENDERPATH_GLES2:
484 // for performance reasons, do not use directional shading on GLES devices
485 r_shadow_bouncegrid_state.capable = true;
490 static void R_Shadow_FreeDeferred(void);
491 static void r_shadow_shutdown(void)
495 R_Shadow_FreeShadowMaps();
497 r_shadow_usingdeferredprepass = false;
498 if (r_shadow_prepass_width)
499 R_Shadow_FreeDeferred();
500 r_shadow_prepass_width = r_shadow_prepass_height = 0;
503 r_shadow_scenemaxlights = 0;
504 r_shadow_scenenumlights = 0;
505 if (r_shadow_scenelightlist)
506 Mem_Free(r_shadow_scenelightlist);
507 r_shadow_scenelightlist = NULL;
508 r_shadow_bouncegrid_state.highpixels = NULL;
509 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
510 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
511 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
512 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
513 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
514 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
515 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
516 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
517 r_shadow_attenuationgradienttexture = NULL;
518 R_FreeTexturePool(&r_shadow_texturepool);
519 R_FreeTexturePool(&r_shadow_filters_texturepool);
520 maxshadowtriangles = 0;
522 Mem_Free(shadowelements);
523 shadowelements = NULL;
525 Mem_Free(shadowvertex3f);
526 shadowvertex3f = NULL;
529 Mem_Free(vertexupdate);
532 Mem_Free(vertexremap);
538 Mem_Free(shadowmark);
541 Mem_Free(shadowmarklist);
542 shadowmarklist = NULL;
547 Mem_Free(shadowsides);
550 Mem_Free(shadowsideslist);
551 shadowsideslist = NULL;
552 r_shadow_buffer_numleafpvsbytes = 0;
553 if (r_shadow_buffer_visitingleafpvs)
554 Mem_Free(r_shadow_buffer_visitingleafpvs);
555 r_shadow_buffer_visitingleafpvs = NULL;
556 if (r_shadow_buffer_leafpvs)
557 Mem_Free(r_shadow_buffer_leafpvs);
558 r_shadow_buffer_leafpvs = NULL;
559 if (r_shadow_buffer_leaflist)
560 Mem_Free(r_shadow_buffer_leaflist);
561 r_shadow_buffer_leaflist = NULL;
562 r_shadow_buffer_numsurfacepvsbytes = 0;
563 if (r_shadow_buffer_surfacepvs)
564 Mem_Free(r_shadow_buffer_surfacepvs);
565 r_shadow_buffer_surfacepvs = NULL;
566 if (r_shadow_buffer_surfacelist)
567 Mem_Free(r_shadow_buffer_surfacelist);
568 r_shadow_buffer_surfacelist = NULL;
569 if (r_shadow_buffer_surfacesides)
570 Mem_Free(r_shadow_buffer_surfacesides);
571 r_shadow_buffer_surfacesides = NULL;
572 r_shadow_buffer_numshadowtrispvsbytes = 0;
573 if (r_shadow_buffer_shadowtrispvs)
574 Mem_Free(r_shadow_buffer_shadowtrispvs);
575 r_shadow_buffer_numlighttrispvsbytes = 0;
576 if (r_shadow_buffer_lighttrispvs)
577 Mem_Free(r_shadow_buffer_lighttrispvs);
580 static void r_shadow_newmap(void)
582 r_shadow_bouncegrid_state.highpixels = NULL;
583 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
584 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
585 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
586 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
587 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
588 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
589 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
591 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
592 if (r_shadow_lightcorona) { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
593 if (r_editlights_sprcursor) { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
594 if (r_editlights_sprlight) { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
595 if (r_editlights_sprnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
596 if (r_editlights_sprcubemaplight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
597 if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
598 if (r_editlights_sprselection) { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
599 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
600 R_Shadow_EditLights_Reload_f(&cmd_client);
604 * (Cloudwalk) FIXME: If anyone wants to figure this shit out,
605 * go ahead. Clearing r_shadow_occlusion_buf is enough on AMD
606 * and NVIDIA. But Intel, even if I call glDeleteBuffers, insists
607 * on doing some stupid bullshit, causing a crash in the driver,
608 * when ever it calls glGetQueryObjectiv. In the interest of
609 * maintaining some semblance of stability, no occlusionquery
612 static void R_DisableCoronas_Intel_c(char *string)
615 if(strstr(gl_vendor,"Intel"))
617 value = atoi(string);
620 Con_Warnf("Occlusion query is not supported on Intel iGPUs at this time. Sorry!\n");
621 string[0] = '0', string[1] = '\000';
624 Con_Warnf("Force-enabling occlusion query on Intel. Proceed at your own risk. It *will* crash after a vid_restart!\n");
628 void R_Shadow_Init(void)
630 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
631 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
632 Cvar_RegisterVariable(&r_shadow_usebihculling);
633 Cvar_RegisterVariable(&r_shadow_usenormalmap);
634 Cvar_RegisterVariable(&r_shadow_debuglight);
635 Cvar_RegisterVariable(&r_shadow_deferred);
636 Cvar_RegisterVariable(&r_shadow_gloss);
637 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
638 Cvar_RegisterVariable(&r_shadow_glossintensity);
639 Cvar_RegisterVariable(&r_shadow_glossexponent);
640 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
641 Cvar_RegisterVariable(&r_shadow_glossexact);
642 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
643 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
644 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
645 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
646 Cvar_RegisterVariable(&r_shadow_projectdistance);
647 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
648 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
649 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
650 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
651 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
652 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
653 Cvar_RegisterVariable(&r_shadow_realtime_world);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
660 Cvar_RegisterVariable(&r_shadow_scissor);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
670 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
671 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
672 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
674 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
675 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
676 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
677 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
678 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
679 Cvar_RegisterVariable(&r_shadow_culllights_trace);
680 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
681 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
682 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
683 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
684 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
685 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
686 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
687 Cvar_RegisterVariable(&r_shadow_bouncegrid);
688 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
689 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
690 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
691 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
692 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
693 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
694 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
695 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
696 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
697 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
698 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
699 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
700 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
701 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
702 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
703 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
704 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
705 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
706 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
707 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
708 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
709 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
710 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
711 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
712 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
713 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
714 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
715 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
716 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
717 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
718 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
719 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
720 Cvar_RegisterVariable(&r_shadow_bouncegrid_subsamples);
721 Cvar_RegisterVariable(&r_shadow_bouncegrid_threaded);
722 Cvar_RegisterVariable(&r_coronas);
723 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
724 Cvar_RegisterVariable(&r_coronas_occlusionquery);
725 Cvar_RegisterCallback(&r_coronas_occlusionquery,R_DisableCoronas_Intel_c);
726 Cvar_RegisterVariable(&gl_flashblend);
727 R_Shadow_EditLights_Init();
728 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
729 r_shadow_scenemaxlights = 0;
730 r_shadow_scenenumlights = 0;
731 r_shadow_scenelightlist = NULL;
732 maxshadowtriangles = 0;
733 shadowelements = NULL;
734 maxshadowvertices = 0;
735 shadowvertex3f = NULL;
743 shadowmarklist = NULL;
748 shadowsideslist = NULL;
749 r_shadow_buffer_numleafpvsbytes = 0;
750 r_shadow_buffer_visitingleafpvs = NULL;
751 r_shadow_buffer_leafpvs = NULL;
752 r_shadow_buffer_leaflist = NULL;
753 r_shadow_buffer_numsurfacepvsbytes = 0;
754 r_shadow_buffer_surfacepvs = NULL;
755 r_shadow_buffer_surfacelist = NULL;
756 r_shadow_buffer_surfacesides = NULL;
757 r_shadow_buffer_shadowtrispvs = NULL;
758 r_shadow_buffer_lighttrispvs = NULL;
759 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
762 matrix4x4_t matrix_attenuationxyz =
765 {0.5, 0.0, 0.0, 0.5},
766 {0.0, 0.5, 0.0, 0.5},
767 {0.0, 0.0, 0.5, 0.5},
772 matrix4x4_t matrix_attenuationz =
775 {0.0, 0.0, 0.5, 0.5},
776 {0.0, 0.0, 0.0, 0.5},
777 {0.0, 0.0, 0.0, 0.5},
782 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
784 numvertices = ((numvertices + 255) & ~255) * vertscale;
785 numtriangles = ((numtriangles + 255) & ~255) * triscale;
786 // make sure shadowelements is big enough for this volume
787 if (maxshadowtriangles < numtriangles)
789 maxshadowtriangles = numtriangles;
791 Mem_Free(shadowelements);
792 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
794 // make sure shadowvertex3f is big enough for this volume
795 if (maxshadowvertices < numvertices)
797 maxshadowvertices = numvertices;
799 Mem_Free(shadowvertex3f);
800 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
804 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
806 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
807 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
808 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
809 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
810 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
812 if (r_shadow_buffer_visitingleafpvs)
813 Mem_Free(r_shadow_buffer_visitingleafpvs);
814 if (r_shadow_buffer_leafpvs)
815 Mem_Free(r_shadow_buffer_leafpvs);
816 if (r_shadow_buffer_leaflist)
817 Mem_Free(r_shadow_buffer_leaflist);
818 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
819 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
820 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
821 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
823 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
825 if (r_shadow_buffer_surfacepvs)
826 Mem_Free(r_shadow_buffer_surfacepvs);
827 if (r_shadow_buffer_surfacelist)
828 Mem_Free(r_shadow_buffer_surfacelist);
829 if (r_shadow_buffer_surfacesides)
830 Mem_Free(r_shadow_buffer_surfacesides);
831 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
832 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
833 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
834 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
836 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
838 if (r_shadow_buffer_shadowtrispvs)
839 Mem_Free(r_shadow_buffer_shadowtrispvs);
840 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
841 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
843 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
845 if (r_shadow_buffer_lighttrispvs)
846 Mem_Free(r_shadow_buffer_lighttrispvs);
847 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
848 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
852 void R_Shadow_PrepareShadowMark(int numtris)
854 // make sure shadowmark is big enough for this volume
855 if (maxshadowmark < numtris)
857 maxshadowmark = numtris;
859 Mem_Free(shadowmark);
861 Mem_Free(shadowmarklist);
862 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
863 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
867 // if shadowmarkcount wrapped we clear the array and adjust accordingly
868 if (shadowmarkcount == 0)
871 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
876 void R_Shadow_PrepareShadowSides(int numtris)
878 if (maxshadowsides < numtris)
880 maxshadowsides = numtris;
882 Mem_Free(shadowsides);
884 Mem_Free(shadowsideslist);
885 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
886 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
891 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
893 // p1, p2, p3 are in the cubemap's local coordinate system
894 // bias = border/(size - border)
897 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
898 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
899 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
900 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
902 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
903 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
904 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
905 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
907 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
908 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
909 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
911 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
912 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
913 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
914 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
916 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
917 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
918 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
919 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
921 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
922 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
923 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
925 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
926 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
927 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
928 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
930 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
931 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
932 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
933 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
935 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
936 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
937 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
942 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
944 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
945 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
948 VectorSubtract(maxs, mins, radius);
949 VectorScale(radius, 0.5f, radius);
950 VectorAdd(mins, radius, center);
951 Matrix4x4_Transform(worldtolight, center, lightcenter);
952 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
953 VectorSubtract(lightcenter, lightradius, pmin);
954 VectorAdd(lightcenter, lightradius, pmax);
956 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
957 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
958 if(ap1 > bias*an1 && ap2 > bias*an2)
960 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
961 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
962 if(an1 > bias*ap1 && an2 > bias*ap2)
964 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
965 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
967 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
968 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
969 if(ap1 > bias*an1 && ap2 > bias*an2)
971 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
972 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
973 if(an1 > bias*ap1 && an2 > bias*ap2)
975 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
976 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
978 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
979 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
980 if(ap1 > bias*an1 && ap2 > bias*an2)
982 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
983 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
984 if(an1 > bias*ap1 && an2 > bias*ap2)
986 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
987 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
992 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
994 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
996 // p is in the cubemap's local coordinate system
997 // bias = border/(size - border)
998 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
999 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1000 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1002 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1003 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1004 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1005 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1006 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1007 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1011 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1015 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1016 float scale = (size - 2*border)/size, len;
1017 float bias = border / (float)(size - border), dp, dn, ap, an;
1018 // check if cone enclosing side would cross frustum plane
1019 scale = 2 / (scale*scale + 2);
1020 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1021 for (i = 0;i < 5;i++)
1023 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1025 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1026 len = scale*VectorLength2(n);
1027 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1028 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1029 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1031 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1033 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1034 len = scale*VectorLength2(n);
1035 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1036 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1037 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1039 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1040 // check if frustum corners/origin cross plane sides
1042 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1043 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1044 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1045 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1046 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1047 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1048 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1049 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1050 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1051 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1052 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1053 for (i = 0;i < 4;i++)
1055 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1056 VectorSubtract(n, p, n);
1057 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1058 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1059 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1060 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1061 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1062 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1063 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1064 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1065 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1068 // finite version, assumes corners are a finite distance from origin dependent on far plane
1069 for (i = 0;i < 5;i++)
1071 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1072 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1073 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1074 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1075 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1076 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1077 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1078 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1079 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1080 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1083 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1086 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1094 int mask, surfacemask = 0;
1095 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1097 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1098 tend = firsttriangle + numtris;
1099 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1101 // surface box entirely inside light box, no box cull
1102 if (projectdirection)
1104 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1106 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1107 TriangleNormal(v[0], v[1], v[2], normal);
1108 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1110 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1111 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1112 surfacemask |= mask;
1115 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1116 shadowsides[numshadowsides] = mask;
1117 shadowsideslist[numshadowsides++] = t;
1124 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1126 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1127 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1129 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1130 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1131 surfacemask |= mask;
1134 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1135 shadowsides[numshadowsides] = mask;
1136 shadowsideslist[numshadowsides++] = t;
1144 // surface box not entirely inside light box, cull each triangle
1145 if (projectdirection)
1147 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1149 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1150 TriangleNormal(v[0], v[1], v[2], normal);
1151 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1152 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1154 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1155 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1156 surfacemask |= mask;
1159 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1160 shadowsides[numshadowsides] = mask;
1161 shadowsideslist[numshadowsides++] = t;
1168 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1170 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1171 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1172 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1174 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1175 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1176 surfacemask |= mask;
1179 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1180 shadowsides[numshadowsides] = mask;
1181 shadowsideslist[numshadowsides++] = t;
1190 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
1192 int i, j, outtriangles = 0;
1193 int *outelement3i[6];
1194 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1196 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1197 // make sure shadowelements is big enough for this mesh
1198 if (maxshadowtriangles < outtriangles)
1199 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1201 // compute the offset and size of the separate index lists for each cubemap side
1203 for (i = 0;i < 6;i++)
1205 outelement3i[i] = shadowelements + outtriangles * 3;
1206 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1207 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1208 outtriangles += sidetotals[i];
1211 // gather up the (sparse) triangles into separate index lists for each cubemap side
1212 for (i = 0;i < numsidetris;i++)
1214 const int *element = elements + sidetris[i] * 3;
1215 for (j = 0;j < 6;j++)
1217 if (sides[i] & (1 << j))
1219 outelement3i[j][0] = element[0];
1220 outelement3i[j][1] = element[1];
1221 outelement3i[j][2] = element[2];
1222 outelement3i[j] += 3;
1227 Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1230 static void R_Shadow_MakeTextures_MakeCorona(void)
1234 unsigned char pixels[32][32][4];
1235 for (y = 0;y < 32;y++)
1237 dy = (y - 15.5f) * (1.0f / 16.0f);
1238 for (x = 0;x < 32;x++)
1240 dx = (x - 15.5f) * (1.0f / 16.0f);
1241 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1242 a = bound(0, a, 255);
1243 pixels[y][x][0] = a;
1244 pixels[y][x][1] = a;
1245 pixels[y][x][2] = a;
1246 pixels[y][x][3] = 255;
1249 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1252 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1254 float dist = sqrt(x*x+y*y+z*z);
1255 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1256 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1257 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1260 static void R_Shadow_MakeTextures(void)
1263 float intensity, dist;
1265 R_Shadow_FreeShadowMaps();
1266 R_FreeTexturePool(&r_shadow_texturepool);
1267 r_shadow_texturepool = R_AllocTexturePool();
1268 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1269 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1270 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1271 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1272 for (x = 0;x <= ATTENTABLESIZE;x++)
1274 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1275 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1276 r_shadow_attentable[x] = bound(0, intensity, 1);
1278 // 1D gradient texture
1279 for (x = 0;x < ATTEN1DSIZE;x++)
1280 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1281 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1284 R_Shadow_MakeTextures_MakeCorona();
1286 // Editor light sprites
1287 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1304 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1305 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1322 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1323 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1340 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1341 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1358 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1359 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1376 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1377 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1394 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1397 void R_Shadow_RenderMode_Begin(void)
1404 if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1405 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1406 R_Shadow_MakeTextures();
1409 R_Mesh_ResetTextureState();
1410 GL_BlendFunc(GL_ONE, GL_ZERO);
1411 GL_DepthRange(0, 1);
1412 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1414 GL_DepthMask(false);
1415 GL_Color(0, 0, 0, 1);
1416 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1418 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1419 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1423 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1424 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1425 r_shadow_drawbuffer = drawbuffer;
1426 r_shadow_readbuffer = readbuffer;
1428 r_shadow_cullface_front = r_refdef.view.cullface_front;
1429 r_shadow_cullface_back = r_refdef.view.cullface_back;
1432 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1434 rsurface.rtlight = rtlight;
1437 void R_Shadow_RenderMode_Reset(void)
1439 R_Mesh_ResetTextureState();
1440 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1441 R_SetViewport(&r_refdef.view.viewport);
1442 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1443 GL_DepthRange(0, 1);
1445 GL_DepthMask(false);
1446 GL_DepthFunc(GL_LEQUAL);
1447 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1448 r_refdef.view.cullface_front = r_shadow_cullface_front;
1449 r_refdef.view.cullface_back = r_shadow_cullface_back;
1450 GL_CullFace(r_refdef.view.cullface_back);
1451 GL_Color(1, 1, 1, 1);
1452 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1453 GL_BlendFunc(GL_ONE, GL_ZERO);
1454 R_SetupShader_Generic_NoTexture(false, false);
1455 r_shadow_usingshadowmap2d = false;
1458 void R_Shadow_ClearStencil(void)
1460 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1461 r_refdef.stats[r_stat_lights_clears]++;
1464 static void R_Shadow_MakeVSDCT(void)
1466 // maps to a 2x3 texture rectangle with normalized coordinates
1471 // stores abs(dir.xy), offset.xy/2.5
1472 unsigned char data[4*6] =
1474 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1475 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1476 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1477 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1478 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1479 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1481 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1484 static void R_Shadow_MakeShadowMap(int texturesize)
1486 switch (r_shadow_shadowmode)
1488 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1489 if (r_shadow_shadowmap2ddepthtexture) return;
1490 if (r_fb.usedepthtextures)
1492 r_shadow_shadowmap2ddepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP24_COMP : TEXTYPE_SHADOWMAP24_RAW) : (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP16_COMP : TEXTYPE_SHADOWMAP16_RAW), r_shadow_shadowmapsampler);
1493 r_shadow_shadowmap2ddepthbuffer = NULL;
1494 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1498 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1499 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1500 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1503 case R_SHADOW_SHADOWMODE_DISABLED:
1508 void R_Shadow_ClearShadowMapTexture(void)
1510 r_viewport_t viewport;
1511 float clearcolor[4];
1513 // if they don't exist, create our textures now
1514 if (!r_shadow_shadowmap2ddepthtexture)
1515 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1516 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1517 R_Shadow_MakeVSDCT();
1519 // we're setting up to render shadowmaps, so change rendermode
1520 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1522 R_Mesh_ResetTextureState();
1523 R_Shadow_RenderMode_Reset();
1524 if (r_shadow_shadowmap2ddepthbuffer)
1525 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1527 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1528 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1529 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1533 // we have to set a viewport to clear anything in some renderpaths (D3D)
1534 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1535 R_SetViewport(&viewport);
1536 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1537 if (r_shadow_shadowmap2ddepthbuffer)
1538 GL_ColorMask(1, 1, 1, 1);
1540 GL_ColorMask(0, 0, 0, 0);
1541 switch (vid.renderpath)
1543 case RENDERPATH_GL32:
1544 case RENDERPATH_GLES2:
1545 GL_CullFace(r_refdef.view.cullface_back);
1548 Vector4Set(clearcolor, 1, 1, 1, 1);
1549 if (r_shadow_shadowmap2ddepthbuffer)
1550 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1552 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1555 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1557 int size = rsurface.rtlight->shadowmapatlassidesize;
1558 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1559 float farclip = 1.0f;
1560 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1561 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1562 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1563 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1564 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1565 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1566 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1567 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1568 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1569 if (r_shadow_shadowmap2ddepthbuffer)
1571 // completely different meaning than in depthtexture approach
1572 r_shadow_lightshadowmap_parameters[1] = 0;
1573 r_shadow_lightshadowmap_parameters[3] = -bias;
1577 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1579 float nearclip, farclip;
1580 r_viewport_t viewport;
1583 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1585 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1587 R_Mesh_ResetTextureState();
1588 R_Shadow_RenderMode_Reset();
1589 if (r_shadow_shadowmap2ddepthbuffer)
1590 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1592 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1593 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1594 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1599 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1602 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1603 R_SetViewport(&viewport);
1604 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1605 flipped = (side & 1) ^ (side >> 2);
1606 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1607 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1609 if (r_shadow_shadowmap2ddepthbuffer)
1610 GL_ColorMask(1,1,1,1);
1612 GL_ColorMask(0,0,0,0);
1613 switch(vid.renderpath)
1615 case RENDERPATH_GL32:
1616 case RENDERPATH_GLES2:
1617 GL_CullFace(r_refdef.view.cullface_back);
1621 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1622 r_shadow_shadowmapside = side;
1625 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1627 R_Mesh_ResetTextureState();
1630 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1631 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1632 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1633 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1636 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1637 R_Shadow_RenderMode_Reset();
1638 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1640 GL_DepthFunc(GL_EQUAL);
1641 // do global setup needed for the chosen lighting mode
1642 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1643 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1644 r_shadow_usingshadowmap2d = shadowmapping;
1645 r_shadow_rendermode = r_shadow_lightingrendermode;
1648 static const unsigned short bboxelements[36] =
1658 static const float bboxpoints[8][3] =
1670 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1673 float vertex3f[8*3];
1674 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1675 // do global setup needed for the chosen lighting mode
1676 R_Shadow_RenderMode_Reset();
1677 r_shadow_rendermode = r_shadow_lightingrendermode;
1678 R_EntityMatrix(&identitymatrix);
1679 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1680 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1681 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1683 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1685 r_shadow_usingshadowmap2d = shadowmapping;
1687 // render the lighting
1688 R_SetupShader_DeferredLight(rsurface.rtlight);
1689 for (i = 0;i < 8;i++)
1690 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1691 GL_ColorMask(1,1,1,1);
1692 GL_DepthMask(false);
1693 GL_DepthRange(0, 1);
1694 GL_PolygonOffset(0, 0);
1696 GL_DepthFunc(GL_GREATER);
1697 GL_CullFace(r_refdef.view.cullface_back);
1698 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1699 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1702 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1704 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1711 // see if there are really any lights to render...
1712 if (enable && r_shadow_bouncegrid_static.integer)
1715 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1716 for (lightindex = 0;lightindex < range;lightindex++)
1718 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1719 if (!light || !(light->flags & flag))
1721 rtlight = &light->rtlight;
1722 // when static, we skip styled lights because they tend to change...
1723 if (rtlight->style > 0)
1725 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1726 if (!VectorLength2(lightcolor))
1736 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1738 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1739 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1740 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1741 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1743 // prevent any garbage in alignment padded areas as we'll be using memcmp
1744 memset(settings, 0, sizeof(*settings));
1746 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1747 settings->staticmode = s;
1748 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1749 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1750 settings->lightpathsize = bound(0.0f, r_shadow_bouncegrid_lightpathsize.value, 1024.0f);
1751 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1752 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1753 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1754 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1755 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1756 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1757 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1758 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) / 65536.0f;
1759 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1760 settings->energyperphoton = 4096.0f / quality;
1761 settings->spacing[0] = spacing;
1762 settings->spacing[1] = spacing;
1763 settings->spacing[2] = spacing;
1764 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1765 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1766 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1767 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1768 settings->subsamples = bound(1, r_shadow_bouncegrid_subsamples.integer, 4);
1770 // bound the values for sanity
1771 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1772 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1773 settings->maxbounce = bound(0, settings->maxbounce, 16);
1774 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1775 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1776 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1779 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1790 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1792 // get the spacing values
1793 spacing[0] = settings->spacing[0];
1794 spacing[1] = settings->spacing[1];
1795 spacing[2] = settings->spacing[2];
1796 ispacing[0] = 1.0f / spacing[0];
1797 ispacing[1] = 1.0f / spacing[1];
1798 ispacing[2] = 1.0f / spacing[2];
1800 // calculate texture size enclosing entire world bounds at the spacing
1801 if (r_refdef.scene.worldmodel)
1805 qboolean bounds_set = false;
1809 // calculate bounds enclosing world lights as they should be noticably tighter
1810 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1811 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1812 for (lightindex = 0;lightindex < range;lightindex++)
1814 const vec_t *rtlmins, *rtlmaxs;
1816 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1820 rtlight = &light->rtlight;
1821 rtlmins = rtlight->cullmins;
1822 rtlmaxs = rtlight->cullmaxs;
1826 VectorCopy(rtlmins, mins);
1827 VectorCopy(rtlmaxs, maxs);
1832 mins[0] = min(mins[0], rtlmins[0]);
1833 mins[1] = min(mins[1], rtlmins[1]);
1834 mins[2] = min(mins[2], rtlmins[2]);
1835 maxs[0] = max(maxs[0], rtlmaxs[0]);
1836 maxs[1] = max(maxs[1], rtlmaxs[1]);
1837 maxs[2] = max(maxs[2], rtlmaxs[2]);
1841 // limit to no larger than the world bounds
1842 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1843 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1844 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1845 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1846 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1847 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1849 VectorMA(mins, -2.0f, spacing, mins);
1850 VectorMA(maxs, 2.0f, spacing, maxs);
1854 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1855 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1857 VectorSubtract(maxs, mins, size);
1858 // now we can calculate the resolution we want
1859 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1860 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1861 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1862 // figure out the exact texture size (honoring power of 2 if required)
1863 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1864 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1865 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1866 size[0] = spacing[0] * resolution[0];
1867 size[1] = spacing[1] * resolution[1];
1868 size[2] = spacing[2] * resolution[2];
1870 // if dynamic we may or may not want to use the world bounds
1871 // if the dynamic size is smaller than the world bounds, use it instead
1872 if (!settings->staticmode && (r_shadow_bouncegrid_dynamic_x.integer * r_shadow_bouncegrid_dynamic_y.integer * r_shadow_bouncegrid_dynamic_z.integer < resolution[0] * resolution[1] * resolution[2]))
1874 // we know the resolution we want
1875 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1876 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1877 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1878 // now we can calculate the texture size
1879 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1880 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1881 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1882 size[0] = spacing[0] * resolution[0];
1883 size[1] = spacing[1] * resolution[1];
1884 size[2] = spacing[2] * resolution[2];
1885 // center the rendering on the view
1886 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1887 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1888 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1891 // recalculate the maxs in case the resolution was not satisfactory
1892 VectorAdd(mins, size, maxs);
1894 // check if this changed the texture size
1895 r_shadow_bouncegrid_state.createtexture = !(r_shadow_bouncegrid_state.texture && r_shadow_bouncegrid_state.resolution[0] == resolution[0] && r_shadow_bouncegrid_state.resolution[1] == resolution[1] && r_shadow_bouncegrid_state.resolution[2] == resolution[2] && r_shadow_bouncegrid_state.directional == r_shadow_bouncegrid_state.settings.directionalshading);
1896 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1897 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1898 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1899 VectorCopy(size, r_shadow_bouncegrid_state.size);
1900 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1901 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1902 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1904 // reallocate pixels for this update if needed...
1905 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1906 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1907 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1908 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1909 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1911 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1913 r_shadow_bouncegrid_state.highpixels = NULL;
1915 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1916 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1917 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1918 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1919 if (r_shadow_bouncegrid_state.photons) { Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL; }
1920 if (r_shadow_bouncegrid_state.photons_tasks) { Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL; }
1921 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
1923 r_shadow_bouncegrid_state.numpixels = numpixels;
1926 // update the bouncegrid matrix to put it in the world properly
1927 memset(m, 0, sizeof(m));
1928 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1929 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1930 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1931 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1932 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1933 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1935 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1938 static float R_Shadow_BounceGrid_RefractiveIndexAtPoint(vec3_t point)
1940 // check material at shadoworigin to see what the initial refractive index should be
1941 int hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
1942 int skipsupercontentsmask = 0;
1943 int skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
1944 trace_t trace = CL_TracePoint(point, r_shadow_bouncegrid_state.settings.staticmode ? MOVE_WORLDONLY : (r_shadow_bouncegrid_state.settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, true, false, NULL, true);
1945 if (trace.starttexture && (trace.starttexture->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)))
1946 return trace.starttexture->refractive_index;
1947 else if (trace.startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
1948 return 1.333f; // water
1950 return 1.0003f; // air
1953 // enumerate world rtlights and sum the overall amount of light in the world,
1954 // from that we can calculate a scaling factor to fairly distribute photons
1955 // to all the lights
1957 // this modifies rtlight->photoncolor and rtlight->photons
1958 static void R_Shadow_BounceGrid_AssignPhotons_Task(taskqueue_task_t *t)
1960 // get the range of light numbers we'll be looping over:
1961 // range = static lights
1962 // range1 = dynamic lights (optional)
1963 // range2 = range + range1
1964 unsigned int range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1965 unsigned int range1 = r_shadow_bouncegrid_state.settings.staticmode ? 0 : r_refdef.scene.numlights;
1966 unsigned int range2 = range + range1;
1967 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
1969 float normalphotonscaling;
1970 float photonscaling;
1971 float photonintensity;
1972 float photoncount = 0.0f;
1973 float lightintensity;
1979 unsigned int lightindex;
1984 float bounceminimumintensity2;
1985 float startrefractiveindex;
1987 randomseed_t randomseed;
1988 vec3_t baseshotcolor;
1990 normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1991 for (lightindex = 0;lightindex < range2;lightindex++)
1993 if (lightindex < range)
1995 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1998 rtlight = &light->rtlight;
1999 VectorClear(rtlight->bouncegrid_photoncolor);
2000 rtlight->bouncegrid_photons = 0;
2001 rtlight->bouncegrid_hits = 0;
2002 rtlight->bouncegrid_traces = 0;
2003 rtlight->bouncegrid_effectiveradius = 0;
2004 if (!(light->flags & flag))
2006 if (r_shadow_bouncegrid_state.settings.staticmode)
2008 // when static, we skip styled lights because they tend to change...
2009 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2012 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2017 rtlight = r_refdef.scene.lights[lightindex - range];
2018 VectorClear(rtlight->bouncegrid_photoncolor);
2019 rtlight->bouncegrid_photons = 0;
2020 rtlight->bouncegrid_hits = 0;
2021 rtlight->bouncegrid_traces = 0;
2022 rtlight->bouncegrid_effectiveradius = 0;
2024 // draw only visible lights (major speedup)
2025 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2026 cullmins[0] = rtlight->shadoworigin[0] - radius;
2027 cullmins[1] = rtlight->shadoworigin[1] - radius;
2028 cullmins[2] = rtlight->shadoworigin[2] - radius;
2029 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2030 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2031 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2032 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2033 if (!r_shadow_bouncegrid_state.settings.staticmode)
2035 // skip if the expanded light box does not touch any visible leafs
2036 if (r_refdef.scene.worldmodel
2037 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2038 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2040 // skip if the expanded light box is not visible to traceline
2041 // note that PrepareLight already did this check but for a smaller box, so we
2042 // end up casting more traces per frame per light when using bouncegrid, which
2043 // is probably fine (and they use the same timer)
2044 if (r_shadow_culllights_trace.integer)
2046 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
2047 rtlight->trace_timer = realtime;
2048 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2051 // skip if expanded light box is offscreen
2052 if (R_CullBox(cullmins, cullmaxs))
2054 // skip if overall light intensity is zero
2055 if (w * VectorLength2(rtlight->color) == 0.0f)
2058 // a light that does not emit any light before style is applied, can be
2059 // skipped entirely (it may just be a corona)
2060 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2062 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2063 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2064 // skip lights that will emit no photons
2065 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2067 // shoot particles from this light
2068 // use a calculation for the number of particles that will not
2069 // vary with lightstyle, otherwise we get randomized particle
2070 // distribution, the seeded random is only consistent for a
2071 // consistent number of particles on this light...
2072 s = rtlight->radius;
2073 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2074 if (lightindex >= range)
2075 lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2076 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2077 photoncount += rtlight->bouncegrid_photons;
2078 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2079 // if the lightstyle happens to be off right now, we can skip actually
2080 // firing the photons, but we did have to count them in the total.
2081 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2082 // rtlight->bouncegrid_photons = 0;
2084 // the user provided an energyperphoton value which we try to use
2085 // if that results in too many photons to shoot this frame, then we cap it
2086 // which causes photons to appear/disappear from frame to frame, so we don't
2087 // like doing that in the typical case
2088 photonscaling = 1.0f;
2089 photonintensity = 1.0f;
2090 if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2092 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2093 photonintensity = 1.0f / photonscaling;
2096 // modify the lights to reflect our computed scaling
2097 for (lightindex = 0; lightindex < range2; lightindex++)
2099 if (lightindex < range)
2101 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2104 rtlight = &light->rtlight;
2107 rtlight = r_refdef.scene.lights[lightindex - range];
2108 rtlight->bouncegrid_photons *= photonscaling;
2109 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2112 // compute a seed for the unstable random modes
2113 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2114 seed = realtime * 1000.0;
2116 for (lightindex = 0; lightindex < range2; lightindex++)
2118 if (lightindex < range)
2120 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2123 rtlight = &light->rtlight;
2126 rtlight = r_refdef.scene.lights[lightindex - range];
2127 // note that this code used to keep track of residual photons and
2128 // distribute them evenly to achieve exactly a desired photon count,
2129 // but that caused unwanted flickering in dynamic mode
2130 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2131 // skip if we won't be shooting any photons
2132 if (!shootparticles)
2134 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2135 //s = settings.particleintensity / shootparticles;
2136 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2137 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2138 if (VectorLength2(baseshotcolor) <= 0.0f)
2140 r_refdef.stats[r_stat_bouncegrid_lights]++;
2141 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2142 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2143 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2145 // check material at shadoworigin to see what the initial refractive index should be
2146 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2148 // for seeded random we start the RNG with the position of the light
2149 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2157 u.f[0] = rtlight->shadoworigin[0];
2158 u.f[1] = rtlight->shadoworigin[1];
2159 u.f[2] = rtlight->shadoworigin[2];
2161 switch (r_shadow_bouncegrid_state.settings.rng_type)
2165 // we have to shift the seed provided by the user because the result must be odd
2166 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2169 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2174 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2176 r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2177 VectorCopy(baseshotcolor, p->color);
2178 VectorCopy(rtlight->shadoworigin, p->start);
2179 switch (r_shadow_bouncegrid_state.settings.rng_type)
2183 // figure out a random direction for the initial photon to go
2184 VectorLehmerRandom(&randomseed, p->end);
2187 // figure out a random direction for the initial photon to go
2188 VectorCheeseRandom(seed, p->end);
2192 // we want a uniform distribution spherically, not merely within the sphere
2193 if (r_shadow_bouncegrid_state.settings.normalizevectors)
2194 VectorNormalize(p->end);
2196 VectorMA(p->start, radius, p->end, p->end);
2197 p->bounceminimumintensity2 = bounceminimumintensity2;
2198 p->startrefractiveindex = startrefractiveindex;
2206 static void R_Shadow_BounceGrid_Slice(int zi)
2208 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2209 int xi, yi; // pixel increments
2210 float color[32] = { 0 };
2211 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2212 float iradius = 1.0f / radius;
2213 int slicemins[3], slicemaxs[3];
2215 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2216 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2218 int samples = r_shadow_bouncegrid_state.settings.subsamples;
2219 float isamples = 1.0f / samples;
2220 float samplescolorscale = isamples * isamples * isamples;
2222 // we use these a lot, so get a local copy
2223 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2225 for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2227 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2229 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2231 r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2232 float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2234 VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2235 VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2237 pathmins[2] = min(pathstart[2], pathend[2]);
2238 slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2239 pathmaxs[2] = max(pathstart[2], pathend[2]);
2240 slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2242 // skip if the path doesn't touch this slice
2243 if (zi < slicemins[2] || zi >= slicemaxs[2])
2246 pathmins[0] = min(pathstart[0], pathend[0]);
2247 slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2248 slicemins[0] = max(slicemins[0], 1);
2249 pathmaxs[0] = max(pathstart[0], pathend[0]);
2250 slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2251 slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2253 pathmins[1] = min(pathstart[1], pathend[1]);
2254 slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2255 slicemins[1] = max(slicemins[1], 1);
2256 pathmaxs[1] = max(pathstart[1], pathend[1]);
2257 slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2258 slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2260 // skip if the path is out of bounds on X or Y
2261 if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2264 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2265 // accumulate average shotcolor
2266 VectorSubtract(pathend, pathstart, pathdelta);
2267 pathlength2 = VectorLength2(pathdelta);
2268 pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2269 VectorScale(pathdelta, pathilength, pathdir);
2270 // the color is scaled by the number of subsamples
2271 color[0] = path->color[0] * samplescolorscale;
2272 color[1] = path->color[1] * samplescolorscale;
2273 color[2] = path->color[2] * samplescolorscale;
2277 // store bentnormal in case the shader has a use for it,
2278 // bentnormal is an intensity-weighted average of the directions,
2279 // and will be normalized on conversion to texture pixels.
2280 float intensity = VectorLength(color);
2281 color[4] = pathdir[0] * intensity;
2282 color[5] = pathdir[1] * intensity;
2283 color[6] = pathdir[2] * intensity;
2284 color[7] = intensity;
2285 // for each color component (R, G, B) calculate the amount that a
2286 // direction contributes
2287 color[8] = color[0] * max(0.0f, pathdir[0]);
2288 color[9] = color[0] * max(0.0f, pathdir[1]);
2289 color[10] = color[0] * max(0.0f, pathdir[2]);
2291 color[12] = color[1] * max(0.0f, pathdir[0]);
2292 color[13] = color[1] * max(0.0f, pathdir[1]);
2293 color[14] = color[1] * max(0.0f, pathdir[2]);
2295 color[16] = color[2] * max(0.0f, pathdir[0]);
2296 color[17] = color[2] * max(0.0f, pathdir[1]);
2297 color[18] = color[2] * max(0.0f, pathdir[2]);
2299 // and do the same for negative directions
2300 color[20] = color[0] * max(0.0f, -pathdir[0]);
2301 color[21] = color[0] * max(0.0f, -pathdir[1]);
2302 color[22] = color[0] * max(0.0f, -pathdir[2]);
2304 color[24] = color[1] * max(0.0f, -pathdir[0]);
2305 color[25] = color[1] * max(0.0f, -pathdir[1]);
2306 color[26] = color[1] * max(0.0f, -pathdir[2]);
2308 color[28] = color[2] * max(0.0f, -pathdir[0]);
2309 color[29] = color[2] * max(0.0f, -pathdir[1]);
2310 color[30] = color[2] * max(0.0f, -pathdir[2]);
2314 for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2316 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2318 float sample[3], diff[3], nearest[3], along, distance2;
2319 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2321 // loop over the subsamples
2322 for (zs = 0; zs < samples; zs++)
2324 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2325 for (ys = 0; ys < samples; ys++)
2327 sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2328 for (xs = 0; xs < samples; xs++)
2330 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2332 // measure distance from subsample to line segment and see if it is within radius
2333 along = DotProduct(sample, pathdir) * pathilength;
2335 VectorCopy(pathstart, nearest);
2336 else if (along >= 1)
2337 VectorCopy(pathend, nearest);
2339 VectorLerp(pathstart, along, pathend, nearest);
2340 VectorSubtract(sample, nearest, diff);
2341 VectorScale(diff, iradius, diff);
2342 distance2 = VectorLength2(diff);
2343 if (distance2 < 1.0f)
2345 // contribute some color to this pixel, across all bands
2346 float w = 1.0f - sqrt(distance2);
2351 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2352 p[pixelsperband * 4 + 3] += color[7] * w;
2354 for (band = 0; band < pixelbands; band++)
2356 // add to the pixel color (RGB only - see above)
2357 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2358 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2359 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2371 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2373 R_Shadow_BounceGrid_Slice((int)t->i[0]);
2377 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2380 // we need to wait for the texture clear to finish before we start adding light to it
2381 if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2386 slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2387 for (i = 0; i < slices; i++)
2388 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2389 TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2390 TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2391 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2395 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2397 const float *inpixel;
2399 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2402 unsigned int x, y, z;
2403 unsigned int resolution[3];
2404 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2405 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2407 for (z = 1;z < resolution[2]-1;z++)
2409 for (y = 1;y < resolution[1]-1;y++)
2412 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2413 inpixel = inpixels + 4*index;
2414 outpixel = outpixels + 4*index;
2415 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2417 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2418 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2419 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2420 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2427 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2430 unsigned int resolution[3];
2431 if (r_shadow_bouncegrid_state.settings.blur)
2433 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2435 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2436 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2437 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2438 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2441 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2443 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2445 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2447 // toggle the state, highpixels now points to pixels[3] result
2448 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2449 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2454 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2456 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2457 unsigned char *pixelsbgra8 = NULL;
2458 unsigned char *pixelbgra8;
2459 unsigned short *pixelsrgba16f = NULL;
2460 unsigned short *pixelrgba16f;
2461 float *pixelsrgba32f = NULL;
2462 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2465 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2466 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2467 unsigned int pixelband;
2468 unsigned int x, y, z;
2469 unsigned int index, bandindex;
2470 unsigned int resolution[3];
2472 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2474 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2476 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2477 r_shadow_bouncegrid_state.texture = NULL;
2480 // if bentnormals exist, we need to normalize and bias them for the shader
2484 for (z = 0;z < resolution[2]-1;z++)
2486 for (y = 0;y < resolution[1]-1;y++)
2489 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2490 highpixel = highpixels + 4*index;
2491 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2493 // only convert pixels that were hit by photons
2494 if (highpixel[3] != 0.0f)
2495 VectorNormalize(highpixel);
2496 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2497 highpixel[pixelsperband * 4 + 3] = 1.0f;
2503 // start by clearing the pixels array - we won't be writing to all of it
2505 // then process only the pixels that have at least some color, skipping
2506 // the higher bands for speed on pixels that are black
2507 switch (floatcolors)
2510 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2511 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2512 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2513 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2516 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2518 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2520 for (z = 1;z < resolution[2]-1;z++)
2522 for (y = 1;y < resolution[1]-1;y++)
2526 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2527 highpixel = highpixels + 4*index;
2528 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2530 // only convert pixels that were hit by photons
2531 if (VectorLength2(highpixel))
2533 // normalize the bentnormal now
2536 VectorNormalize(highpixel + pixelsperband * 4);
2537 highpixel[pixelsperband * 4 + 3] = 1.0f;
2539 // process all of the pixelbands for this pixel
2540 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2542 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2543 bandpixel = highpixels + 4*bandindex;
2544 c[0] = (int)(bandpixel[0]*256.0f);
2545 c[1] = (int)(bandpixel[1]*256.0f);
2546 c[2] = (int)(bandpixel[2]*256.0f);
2547 c[3] = (int)(bandpixel[3]*256.0f);
2548 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2549 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2550 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2551 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2558 if (!r_shadow_bouncegrid_state.createtexture)
2559 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2561 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, pixelsbgra8, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2564 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2565 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2566 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2567 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2568 for (z = 1;z < resolution[2]-1;z++)
2570 for (y = 1;y < resolution[1]-1;y++)
2574 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2575 highpixel = highpixels + 4*index;
2576 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2578 // only convert pixels that were hit by photons
2579 if (VectorLength2(highpixel))
2581 // process all of the pixelbands for this pixel
2582 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2584 // time to have fun with IEEE 754 bit hacking...
2587 unsigned int raw[4];
2589 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2590 bandpixel = highpixels + 4*bandindex;
2591 VectorCopy4(bandpixel, u.f);
2592 VectorCopy4(u.raw, c);
2593 // this math supports negative numbers, snaps denormals to zero
2594 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2595 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2596 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2597 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2598 // this math does not support negative
2599 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2600 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2601 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2602 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2609 if (!r_shadow_bouncegrid_state.createtexture)
2610 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2612 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, (const unsigned char *)pixelsrgba16f, TEXTYPE_COLORBUFFER16F, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2615 // our native format happens to match, so this is easy.
2616 pixelsrgba32f = highpixels;
2618 if (!r_shadow_bouncegrid_state.createtexture)
2619 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2621 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, (const unsigned char *)pixelsrgba32f, TEXTYPE_COLORBUFFER32F, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2625 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2628 static void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2630 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2634 static void R_Shadow_BounceGrid_TracePhotons_Shot(r_shadow_bouncegrid_photon_t *p, int remainingbounces, vec3_t shotstart, vec3_t shotend, vec3_t shotcolor, float bounceminimumintensity2, float previousrefractiveindex)
2636 int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2638 vec3_t surfacenormal;
2639 vec3_t reflectstart, reflectend, reflectcolor;
2640 vec3_t refractstart, refractend, refractcolor;
2642 float reflectamount = 1.0f;
2644 // figure out what we want to interact with
2645 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2646 skipsupercontentsmask = 0;
2647 skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2648 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2649 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2650 if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2652 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2653 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2654 cliptrace = CL_TraceLine(shotstart, shotend, r_shadow_bouncegrid_state.settings.staticmode ? MOVE_WORLDONLY : (r_shadow_bouncegrid_state.settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value, true, false, NULL, true, true);
2658 // dynamic mode fires many rays and most will match the cache from the previous frame
2659 cliptrace = CL_Cache_TraceLineSurfaces(shotstart, shotend, r_shadow_bouncegrid_state.settings.staticmode ? MOVE_WORLDONLY : (r_shadow_bouncegrid_state.settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
2661 VectorCopy(cliptrace.endpos, shothit);
2662 if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2664 qboolean notculled = true;
2665 // cull paths that fail R_CullBox in dynamic mode
2666 if (!r_shadow_bouncegrid_state.settings.staticmode
2667 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2669 vec3_t cullmins, cullmaxs;
2670 cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2671 cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2672 cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2673 cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2674 cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2675 cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2676 if (R_CullBox(cullmins, cullmaxs))
2681 r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2682 VectorCopy(shotstart, path->start);
2683 VectorCopy(shothit, path->end);
2684 VectorCopy(shotcolor, path->color);
2687 if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2689 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2690 // also clamp the resulting color to never add energy, even if the user requests extreme values
2691 VectorCopy(cliptrace.plane.normal, surfacenormal);
2692 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2693 VectorClear(refractcolor);
2694 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2695 if (cliptrace.hittexture)
2697 if (cliptrace.hittexture->currentskinframe)
2698 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2699 if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2701 reflectamount *= cliptrace.hittexture->currentalpha;
2702 if (cliptrace.hittexture->currentskinframe)
2703 reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2705 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2709 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2710 VectorSubtract(shotstart, shotend, lightdir);
2711 VectorNormalize(lightdir);
2712 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2713 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2714 reflectamount *= Fresnel;
2715 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2717 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2718 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2719 // make sure we do not gain energy even if surface colors are out of bounds
2720 reflectcolor[0] = min(reflectcolor[0], 1.0f);
2721 reflectcolor[1] = min(reflectcolor[1], 1.0f);
2722 reflectcolor[2] = min(reflectcolor[2], 1.0f);
2723 refractcolor[0] = min(refractcolor[0], 1.0f);
2724 refractcolor[1] = min(refractcolor[1], 1.0f);
2725 refractcolor[2] = min(refractcolor[2], 1.0f);
2727 // reflected and refracted shots
2728 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2729 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2730 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2731 VectorMultiply(refractcolor, shotcolor, refractcolor);
2733 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2735 // reflect the remaining portion of the line across plane normal
2736 VectorSubtract(shotend, shothit, reflectend);
2737 VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2738 // calculate the new line start and end
2739 VectorCopy(shothit, reflectstart);
2740 VectorAdd(reflectstart, reflectend, reflectend);
2741 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2744 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2746 // Check what refractive index is on the other side
2747 float refractiveindex;
2748 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2749 refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2750 // reflect the remaining portion of the line across plane normal
2751 VectorSubtract(shotend, shothit, refractend);
2752 s = refractiveindex / previousrefractiveindex;
2753 VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2754 // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2755 // calculate the new line start and end
2756 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2757 VectorAdd(refractstart, refractend, refractend);
2758 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2763 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2765 r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2766 R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2770 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2773 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2774 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2775 TaskQueue_Setup(&r_shadow_bouncegrid_state.photons_done_task, NULL, TaskQueue_Task_CheckTasksDone, r_shadow_bouncegrid_state.numphotons, 0, r_shadow_bouncegrid_state.photons_tasks, NULL);
2776 if (r_shadow_bouncegrid_threaded.integer)
2778 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2779 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2783 // when not threaded we still have to report task status
2784 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2785 r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2786 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2791 void R_Shadow_UpdateBounceGridTexture(void)
2793 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2794 r_shadow_bouncegrid_settings_t settings;
2795 qboolean enable = false;
2796 qboolean settingschanged;
2798 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2800 R_Shadow_BounceGrid_GenerateSettings(&settings);
2802 // changing intensity does not require an update
2803 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2805 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2807 // when settings change, we free everything as it is just simpler that way.
2808 if (settingschanged || !enable)
2810 // not enabled, make sure we free anything we don't need anymore.
2811 if (r_shadow_bouncegrid_state.texture)
2813 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2814 r_shadow_bouncegrid_state.texture = NULL;
2816 r_shadow_bouncegrid_state.highpixels = NULL;
2817 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2818 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2819 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2820 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2821 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2822 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2823 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2824 r_shadow_bouncegrid_state.numpixels = 0;
2825 r_shadow_bouncegrid_state.numphotons = 0;
2826 r_shadow_bouncegrid_state.directional = false;
2832 // if all the settings seem identical to the previous update, return
2833 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2836 // store the new settings
2837 r_shadow_bouncegrid_state.settings = settings;
2839 R_Shadow_BounceGrid_UpdateSpacing();
2841 // allocate the highpixels array we'll be accumulating light into
2842 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2843 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2844 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2845 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2846 r_shadow_bouncegrid_state.highpixels_index = 0;
2847 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2849 // set up the tracking of photon data
2850 if (r_shadow_bouncegrid_state.photons == NULL)
2851 r_shadow_bouncegrid_state.photons = (r_shadow_bouncegrid_photon_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(r_shadow_bouncegrid_photon_t));
2852 if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2853 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2854 r_shadow_bouncegrid_state.numphotons = 0;
2856 // set up the tracking of slice tasks
2857 if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2858 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2860 memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2861 memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2862 memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2863 memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2864 memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2865 memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2866 memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2867 memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2868 memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2870 // clear the texture
2871 TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2872 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2874 // calculate weighting factors for distributing photons among the lights
2875 TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2876 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2878 // enqueue tasks to trace the photons from lights
2879 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2880 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2882 // accumulate the light paths into texture
2883 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueue_slices_task, &r_shadow_bouncegrid_state.photons_done_task, R_Shadow_BounceGrid_EnqueueSlices_Task, 0, 0, NULL, NULL);
2884 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2886 // apply a mild blur filter to the texture
2887 TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2888 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2890 TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2891 R_TimeReport("bouncegrid_gen");
2893 // convert the pixels to lower precision and upload the texture
2894 // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2895 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2896 R_TimeReport("bouncegrid_tex");
2898 // after we compute the static lighting we don't need to keep the highpixels array around
2899 if (settings.staticmode)
2901 r_shadow_bouncegrid_state.highpixels = NULL;
2902 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2903 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2904 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2905 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2906 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2907 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2908 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2912 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2914 R_Shadow_RenderMode_Reset();
2915 GL_BlendFunc(GL_ONE, GL_ONE);
2916 GL_DepthRange(0, 1);
2917 GL_DepthTest(r_showlighting.integer < 2);
2918 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2920 GL_DepthFunc(GL_EQUAL);
2921 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2924 void R_Shadow_RenderMode_End(void)
2926 R_Shadow_RenderMode_Reset();
2927 R_Shadow_RenderMode_ActiveLight(NULL);
2929 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2930 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2933 int bboxedges[12][2] =
2952 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2954 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2956 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2957 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2958 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2959 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2962 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2963 return true; // invisible
2964 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2965 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2966 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2967 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2968 r_refdef.stats[r_stat_lights_scissored]++;
2972 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2974 // used to display how many times a surface is lit for level design purposes
2975 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2976 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2980 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const float ambientcolor[3], const float diffusecolor[3], const float specularcolor[3])
2982 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2983 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2987 extern cvar_t gl_lightmaps;
2988 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2991 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2992 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2993 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2994 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2995 if (!r_shadow_usenormalmap.integer)
2997 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2998 VectorClear(diffusecolor);
2999 VectorClear(specularcolor);
3001 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
3002 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
3003 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
3004 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
3006 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
3009 VectorNegate(ambientcolor, ambientcolor);
3010 VectorNegate(diffusecolor, diffusecolor);
3011 VectorNegate(specularcolor, specularcolor);
3012 GL_BlendEquationSubtract(true);
3014 RSurf_SetupDepthAndCulling();
3015 switch (r_shadow_rendermode)
3017 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3018 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3019 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3021 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3022 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
3025 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3029 GL_BlendEquationSubtract(false);
3032 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
3034 matrix4x4_t tempmatrix = *matrix;
3035 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3037 // if this light has been compiled before, free the associated data
3038 R_RTLight_Uncompile(rtlight);
3040 // clear it completely to avoid any lingering data
3041 memset(rtlight, 0, sizeof(*rtlight));
3043 // copy the properties
3044 rtlight->matrix_lighttoworld = tempmatrix;
3045 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3046 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3047 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3048 VectorCopy(color, rtlight->color);
3049 rtlight->cubemapname[0] = 0;
3050 if (cubemapname && cubemapname[0])
3051 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3052 rtlight->shadow = shadow;
3053 rtlight->corona = corona;
3054 rtlight->style = style;
3055 rtlight->isstatic = isstatic;
3056 rtlight->coronasizescale = coronasizescale;
3057 rtlight->ambientscale = ambientscale;
3058 rtlight->diffusescale = diffusescale;
3059 rtlight->specularscale = specularscale;
3060 rtlight->flags = flags;
3062 // compute derived data
3063 //rtlight->cullradius = rtlight->radius;
3064 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3065 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3066 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3067 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3068 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3069 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3070 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3073 // compiles rtlight geometry
3074 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3075 void R_RTLight_Compile(rtlight_t *rtlight)
3078 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3079 int lighttris, shadowtris;
3080 entity_render_t *ent = r_refdef.scene.worldentity;
3081 dp_model_t *model = r_refdef.scene.worldmodel;
3082 unsigned char *data;
3084 // compile the light
3085 rtlight->compiled = true;
3086 rtlight->static_numleafs = 0;
3087 rtlight->static_numleafpvsbytes = 0;
3088 rtlight->static_leaflist = NULL;
3089 rtlight->static_leafpvs = NULL;
3090 rtlight->static_numsurfaces = 0;
3091 rtlight->static_surfacelist = NULL;
3092 rtlight->static_shadowmap_receivers = 0x3F;
3093 rtlight->static_shadowmap_casters = 0x3F;
3094 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3095 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3096 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3097 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3098 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3099 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3101 if (model && model->GetLightInfo)
3103 // this variable must be set for the CompileShadowMap code
3104 r_shadow_compilingrtlight = rtlight;
3105 R_FrameData_SetMark();
3106 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, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, 0, NULL, rtlight->shadow == 0);
3107 R_FrameData_ReturnToMark();
3108 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3109 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3110 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3111 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3112 rtlight->static_numsurfaces = numsurfaces;
3113 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3114 rtlight->static_numleafs = numleafs;
3115 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3116 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3117 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3118 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3119 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3120 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3121 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3122 if (rtlight->static_numsurfaces)
3123 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3124 if (rtlight->static_numleafs)
3125 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3126 if (rtlight->static_numleafpvsbytes)
3127 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3128 if (rtlight->static_numshadowtrispvsbytes)
3129 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3130 if (rtlight->static_numlighttrispvsbytes)
3131 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3132 R_FrameData_SetMark();
3133 if (model->CompileShadowMap && rtlight->shadow)
3134 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3135 R_FrameData_ReturnToMark();
3136 // now we're done compiling the rtlight
3137 r_shadow_compilingrtlight = NULL;
3141 // use smallest available cullradius - box radius or light radius
3142 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3143 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3146 if (rtlight->static_numlighttrispvsbytes)
3147 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3148 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3152 if (rtlight->static_numshadowtrispvsbytes)
3153 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3154 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3157 if (developer_extra.integer)
3158 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris);
3161 void R_RTLight_Uncompile(rtlight_t *rtlight)
3163 if (rtlight->compiled)
3165 if (rtlight->static_meshchain_shadow_shadowmap)
3166 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3167 rtlight->static_meshchain_shadow_shadowmap = NULL;
3168 // these allocations are grouped
3169 if (rtlight->static_surfacelist)
3170 Mem_Free(rtlight->static_surfacelist);
3171 rtlight->static_numleafs = 0;
3172 rtlight->static_numleafpvsbytes = 0;
3173 rtlight->static_leaflist = NULL;
3174 rtlight->static_leafpvs = NULL;
3175 rtlight->static_numsurfaces = 0;
3176 rtlight->static_surfacelist = NULL;
3177 rtlight->static_numshadowtrispvsbytes = 0;
3178 rtlight->static_shadowtrispvs = NULL;
3179 rtlight->static_numlighttrispvsbytes = 0;
3180 rtlight->static_lighttrispvs = NULL;
3181 rtlight->compiled = false;
3185 void R_Shadow_UncompileWorldLights(void)
3189 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3190 for (lightindex = 0;lightindex < range;lightindex++)
3192 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3195 R_RTLight_Uncompile(&light->rtlight);
3199 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3203 // reset the count of frustum planes
3204 // see rtlight->cached_frustumplanes definition for how much this array
3206 rtlight->cached_numfrustumplanes = 0;
3208 if (r_trippy.integer)
3211 // haven't implemented a culling path for ortho rendering
3212 if (!r_refdef.view.useperspective)
3214 // check if the light is on screen and copy the 4 planes if it is
3215 for (i = 0;i < 4;i++)
3216 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3219 for (i = 0;i < 4;i++)
3220 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3225 // generate a deformed frustum that includes the light origin, this is
3226 // used to cull shadow casting surfaces that can not possibly cast a
3227 // shadow onto the visible light-receiving surfaces, which can be a
3230 // if the light origin is onscreen the result will be 4 planes exactly
3231 // if the light origin is offscreen on only one axis the result will
3232 // be exactly 5 planes (split-side case)
3233 // if the light origin is offscreen on two axes the result will be
3234 // exactly 4 planes (stretched corner case)
3235 for (i = 0;i < 4;i++)
3237 // quickly reject standard frustum planes that put the light
3238 // origin outside the frustum
3239 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3242 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3244 // if all the standard frustum planes were accepted, the light is onscreen
3245 // otherwise we need to generate some more planes below...
3246 if (rtlight->cached_numfrustumplanes < 4)
3248 // at least one of the stock frustum planes failed, so we need to
3249 // create one or two custom planes to enclose the light origin
3250 for (i = 0;i < 4;i++)
3252 // create a plane using the view origin and light origin, and a
3253 // single point from the frustum corner set
3254 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3255 VectorNormalize(plane.normal);
3256 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3257 // see if this plane is backwards and flip it if so
3258 for (j = 0;j < 4;j++)
3259 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3263 VectorNegate(plane.normal, plane.normal);
3265 // flipped plane, test again to see if it is now valid
3266 for (j = 0;j < 4;j++)
3267 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3269 // if the plane is still not valid, then it is dividing the
3270 // frustum and has to be rejected
3274 // we have created a valid plane, compute extra info
3275 PlaneClassify(&plane);
3277 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3279 // if we've found 5 frustum planes then we have constructed a
3280 // proper split-side case and do not need to keep searching for
3281 // planes to enclose the light origin
3282 if (rtlight->cached_numfrustumplanes == 5)
3290 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3292 plane = rtlight->cached_frustumplanes[i];
3293 Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_refdef.view.frustumcorner[0], &plane), PlaneDiff(r_refdef.view.frustumcorner[1], &plane), PlaneDiff(r_refdef.view.frustumcorner[2], &plane), PlaneDiff(r_refdef.view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
3298 // now add the light-space box planes if the light box is rotated, as any
3299 // caster outside the oriented light box is irrelevant (even if it passed
3300 // the worldspace light box, which is axial)
3301 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3303 for (i = 0;i < 6;i++)
3307 v[i >> 1] = (i & 1) ? -1 : 1;
3308 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3309 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3310 plane.dist = VectorNormalizeLength(plane.normal);
3311 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3312 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3318 // add the world-space reduced box planes
3319 for (i = 0;i < 6;i++)
3321 VectorClear(plane.normal);
3322 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3323 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3324 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3333 // reduce all plane distances to tightly fit the rtlight cull box, which
3335 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3336 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3337 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3338 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3339 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3340 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3341 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3342 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3343 oldnum = rtlight->cached_numfrustumplanes;
3344 rtlight->cached_numfrustumplanes = 0;
3345 for (j = 0;j < oldnum;j++)
3347 // find the nearest point on the box to this plane
3348 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3349 for (i = 1;i < 8;i++)
3351 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3352 if (bestdist > dist)
3355 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rtlight->cached_frustumplanes[j].normal[0], rtlight->cached_frustumplanes[j].normal[1], rtlight->cached_frustumplanes[j].normal[2], rtlight->cached_frustumplanes[j].dist, bestdist);
3356 // if the nearest point is near or behind the plane, we want this
3357 // plane, otherwise the plane is useless as it won't cull anything
3358 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3360 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3361 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3368 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3370 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3372 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3374 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3375 if (mesh->sidetotals[r_shadow_shadowmapside])
3378 GL_CullFace(GL_NONE);
3379 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3380 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3381 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3385 else if (r_refdef.scene.worldentity->model)
3386 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
3388 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3391 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3393 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3394 vec_t relativeshadowradius;
3395 RSurf_ActiveModelEntity(ent, false, false, false);
3396 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3397 // we need to re-init the shader for each entity because the matrix changed
3398 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3399 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3400 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3401 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3402 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3403 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3404 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3405 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3406 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3409 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3411 // set up properties for rendering light onto this entity
3412 RSurf_ActiveModelEntity(ent, true, true, false);
3413 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3414 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3415 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3416 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3419 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3421 if (!r_refdef.scene.worldmodel->DrawLight)
3424 // set up properties for rendering light onto this entity
3425 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3426 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3427 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3428 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3429 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3431 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3433 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3436 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3438 dp_model_t *model = ent->model;
3439 if (!model->DrawLight)
3442 R_Shadow_SetupEntityLight(ent);
3444 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3446 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3449 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3453 int numleafs, numsurfaces;
3454 int *leaflist, *surfacelist;
3455 unsigned char *leafpvs;
3456 unsigned char *shadowtrispvs;
3457 unsigned char *lighttrispvs;
3458 //unsigned char *surfacesides;
3459 int numlightentities;
3460 int numlightentities_noselfshadow;
3461 int numshadowentities;
3462 int numshadowentities_noselfshadow;
3463 // FIXME: bounds check lightentities and shadowentities, etc.
3464 static entity_render_t *lightentities[MAX_EDICTS];
3465 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3466 static entity_render_t *shadowentities[MAX_EDICTS];
3467 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3469 qboolean castshadows;
3471 rtlight->draw = false;
3472 rtlight->cached_numlightentities = 0;
3473 rtlight->cached_numlightentities_noselfshadow = 0;
3474 rtlight->cached_numshadowentities = 0;
3475 rtlight->cached_numshadowentities_noselfshadow = 0;
3476 rtlight->cached_numsurfaces = 0;
3477 rtlight->cached_lightentities = NULL;
3478 rtlight->cached_lightentities_noselfshadow = NULL;
3479 rtlight->cached_shadowentities = NULL;
3480 rtlight->cached_shadowentities_noselfshadow = NULL;
3481 rtlight->cached_shadowtrispvs = NULL;
3482 rtlight->cached_lighttrispvs = NULL;
3483 rtlight->cached_surfacelist = NULL;
3484 rtlight->shadowmapsidesize = 0;
3486 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3487 // skip lights that are basically invisible (color 0 0 0)
3488 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3490 // loading is done before visibility checks because loading should happen
3491 // all at once at the start of a level, not when it stalls gameplay.
3492 // (especially important to benchmarks)
3494 if (rtlight->isstatic && !nolight && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3495 R_RTLight_Compile(rtlight);
3498 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3500 // look up the light style value at this time
3501 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3502 VectorScale(rtlight->color, f, rtlight->currentcolor);
3504 if (rtlight->selected)
3506 f = 2 + sin(realtime * M_PI * 4.0);
3507 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3511 // skip if lightstyle is currently off
3512 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3515 // skip processing on corona-only lights
3519 // skip if the light box is not touching any visible leafs
3520 if (r_shadow_culllights_pvs.integer
3521 && r_refdef.scene.worldmodel
3522 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3523 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3526 // skip if the light box is not visible to traceline
3527 if (r_shadow_culllights_trace.integer)
3529 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
3530 rtlight->trace_timer = realtime;
3531 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3535 // skip if the light box is off screen
3536 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3539 // in the typical case this will be quickly replaced by GetLightInfo
3540 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3541 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3543 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3545 // don't allow lights to be drawn if using r_shadow_bouncegrid 2, except if we're using static bouncegrid where dynamic lights still need to draw
3546 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3549 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3551 // compiled light, world available and can receive realtime lighting
3552 // retrieve leaf information
3553 numleafs = rtlight->static_numleafs;
3554 leaflist = rtlight->static_leaflist;
3555 leafpvs = rtlight->static_leafpvs;
3556 numsurfaces = rtlight->static_numsurfaces;
3557 surfacelist = rtlight->static_surfacelist;
3558 //surfacesides = NULL;
3559 shadowtrispvs = rtlight->static_shadowtrispvs;
3560 lighttrispvs = rtlight->static_lighttrispvs;
3562 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3564 // dynamic light, world available and can receive realtime lighting
3565 // calculate lit surfaces and leafs
3566 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes, rtlight->shadow == 0);
3567 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3568 leaflist = r_shadow_buffer_leaflist;
3569 leafpvs = r_shadow_buffer_leafpvs;
3570 surfacelist = r_shadow_buffer_surfacelist;
3571 //surfacesides = r_shadow_buffer_surfacesides;
3572 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3573 lighttrispvs = r_shadow_buffer_lighttrispvs;
3574 // if the reduced leaf bounds are offscreen, skip it
3575 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3586 //surfacesides = NULL;
3587 shadowtrispvs = NULL;
3588 lighttrispvs = NULL;
3590 // check if light is illuminating any visible leafs
3593 for (i = 0; i < numleafs; i++)
3594 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3600 // make a list of lit entities and shadow casting entities
3601 numlightentities = 0;
3602 numlightentities_noselfshadow = 0;
3603 numshadowentities = 0;
3604 numshadowentities_noselfshadow = 0;
3606 // add dynamic entities that are lit by the light
3607 for (i = 0; i < r_refdef.scene.numentities; i++)
3610 entity_render_t *ent = r_refdef.scene.entities[i];
3612 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3614 // skip the object entirely if it is not within the valid
3615 // shadow-casting region (which includes the lit region)
3616 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3618 if (!(model = ent->model))
3620 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3622 // this entity wants to receive light, is visible, and is
3623 // inside the light box
3624 // TODO: check if the surfaces in the model can receive light
3625 // so now check if it's in a leaf seen by the light
3626 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3628 if (ent->flags & RENDER_NOSELFSHADOW)
3629 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3631 lightentities[numlightentities++] = ent;
3632 // since it is lit, it probably also casts a shadow...
3633 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3634 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3635 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3637 // note: exterior models without the RENDER_NOSELFSHADOW
3638 // flag still create a RENDER_NOSELFSHADOW shadow but
3639 // are lit normally, this means that they are
3640 // self-shadowing but do not shadow other
3641 // RENDER_NOSELFSHADOW entities such as the gun
3642 // (very weird, but keeps the player shadow off the gun)
3643 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3644 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3646 shadowentities[numshadowentities++] = ent;
3649 else if (ent->flags & RENDER_SHADOW)
3651 // this entity is not receiving light, but may still need to
3653 // TODO: check if the surfaces in the model can cast shadow
3654 // now check if it is in a leaf seen by the light
3655 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3657 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3658 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3659 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3661 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3662 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3664 shadowentities[numshadowentities++] = ent;
3669 // return if there's nothing at all to light
3670 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3673 // count this light in the r_speeds
3674 r_refdef.stats[r_stat_lights]++;
3676 // flag it as worth drawing later
3677 rtlight->draw = true;
3679 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3680 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3682 numshadowentities = numshadowentities_noselfshadow = 0;
3683 rtlight->castshadows = castshadows;
3685 // cache all the animated entities that cast a shadow but are not visible
3686 for (i = 0; i < numshadowentities; i++)
3687 R_AnimCache_GetEntity(shadowentities[i], false, false);
3688 for (i = 0; i < numshadowentities_noselfshadow; i++)
3689 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3691 // we can convert noselfshadow to regular if there are no receivers of that type (or we're using r_shadow_deferred which doesn't support noselfshadow anyway)
3692 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3694 for (i = 0; i < numshadowentities_noselfshadow; i++)
3695 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3696 numshadowentities_noselfshadow = 0;
3699 // we can convert noselfshadow to regular if there are no casters of that type
3700 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3702 for (i = 0; i < numlightentities_noselfshadow; i++)
3703 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3704 numlightentities_noselfshadow = 0;
3707 // allocate some temporary memory for rendering this light later in the frame
3708 // reusable buffers need to be copied, static data can be used as-is
3709 rtlight->cached_numlightentities = numlightentities;
3710 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3711 rtlight->cached_numshadowentities = numshadowentities;
3712 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3713 rtlight->cached_numsurfaces = numsurfaces;
3714 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3715 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3716 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3717 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3718 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3720 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3721 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3722 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3723 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3724 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3728 // compiled light data
3729 rtlight->cached_shadowtrispvs = shadowtrispvs;
3730 rtlight->cached_lighttrispvs = lighttrispvs;
3731 rtlight->cached_surfacelist = surfacelist;
3734 if (R_Shadow_ShadowMappingEnabled())
3736 // figure out the shadowmapping parameters for this light
3737 vec3_t nearestpoint;
3740 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3741 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3742 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3743 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3744 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3745 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3746 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3747 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3748 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3752 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3756 unsigned char *shadowtrispvs, *surfacesides;
3757 int numlightentities;
3758 int numlightentities_noselfshadow;
3759 int numshadowentities;
3760 int numshadowentities_noselfshadow;
3761 entity_render_t **lightentities;
3762 entity_render_t **lightentities_noselfshadow;
3763 entity_render_t **shadowentities;
3764 entity_render_t **shadowentities_noselfshadow;
3766 static unsigned char entitysides[MAX_EDICTS];
3767 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3773 matrix4x4_t radiustolight;
3775 // check if we cached this light this frame (meaning it is worth drawing)
3776 if (!rtlight->draw || !rtlight->castshadows)
3779 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3780 if (rtlight->shadowmapatlassidesize == 0)
3782 rtlight->castshadows = false;
3786 // set up a scissor rectangle for this light
3787 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3790 // don't let sound skip if going slow
3791 if (r_refdef.scene.extraupdate)
3794 numlightentities = rtlight->cached_numlightentities;
3795 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3796 numshadowentities = rtlight->cached_numshadowentities;
3797 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3798 numsurfaces = rtlight->cached_numsurfaces;
3799 lightentities = rtlight->cached_lightentities;
3800 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3801 shadowentities = rtlight->cached_shadowentities;
3802 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3803 shadowtrispvs = rtlight->cached_shadowtrispvs;
3804 surfacelist = rtlight->cached_surfacelist;
3806 // make this the active rtlight for rendering purposes
3807 R_Shadow_RenderMode_ActiveLight(rtlight);
3809 radiustolight = rtlight->matrix_worldtolight;
3810 Matrix4x4_Abs(&radiustolight);
3812 size = rtlight->shadowmapatlassidesize;
3813 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3815 surfacesides = NULL;
3820 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3822 castermask = rtlight->static_shadowmap_casters;
3823 receivermask = rtlight->static_shadowmap_receivers;
3827 surfacesides = r_shadow_buffer_surfacesides;
3828 for (i = 0; i < numsurfaces; i++)
3830 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3831 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3832 castermask |= surfacesides[i];
3833 receivermask |= surfacesides[i];
3838 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3839 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3840 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3841 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3843 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3847 for (i = 0; i < numshadowentities; i++)
3848 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3849 for (i = 0; i < numshadowentities_noselfshadow; i++)
3850 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3853 // there is no need to render shadows for sides that have no receivers...
3854 castermask &= receivermask;
3856 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3858 // render shadow casters into shadowmaps for this light
3859 for (side = 0; side < 6; side++)
3861 int bit = 1 << side;
3862 if (castermask & bit)
3864 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3866 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3867 for (i = 0; i < numshadowentities; i++)
3868 if (entitysides[i] & bit)
3869 R_Shadow_DrawEntityShadow(shadowentities[i]);
3870 for (i = 0; i < numshadowentities_noselfshadow; i++)
3871 if (entitysides_noselfshadow[i] & bit)
3872 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3875 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3876 if (numshadowentities_noselfshadow)
3878 for (side = 0; side < 6; side++)
3880 int bit = 1 << side;
3881 if (castermask & bit)
3883 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3885 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3886 for (i = 0; i < numshadowentities; i++)
3887 if (entitysides[i] & bit)
3888 R_Shadow_DrawEntityShadow(shadowentities[i]);
3894 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3898 unsigned char *lighttrispvs;
3899 int numlightentities;
3900 int numlightentities_noselfshadow;
3901 entity_render_t **lightentities;
3902 entity_render_t **lightentities_noselfshadow;
3904 qboolean castshadows;
3906 // check if we cached this light this frame (meaning it is worth drawing)
3910 // set up a scissor rectangle for this light
3911 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3914 // don't let sound skip if going slow
3915 if (r_refdef.scene.extraupdate)
3918 numlightentities = rtlight->cached_numlightentities;
3919 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3920 numsurfaces = rtlight->cached_numsurfaces;
3921 lightentities = rtlight->cached_lightentities;
3922 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3923 lighttrispvs = rtlight->cached_lighttrispvs;
3924 surfacelist = rtlight->cached_surfacelist;
3925 castshadows = rtlight->castshadows;
3927 // make this the active rtlight for rendering purposes
3928 R_Shadow_RenderMode_ActiveLight(rtlight);
3930 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3932 // optionally draw the illuminated areas
3933 // for performance analysis by level designers
3934 R_Shadow_RenderMode_VisibleLighting(false);
3936 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3937 for (i = 0;i < numlightentities;i++)
3938 R_Shadow_DrawEntityLight(lightentities[i]);
3939 for (i = 0;i < numlightentities_noselfshadow;i++)
3940 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3943 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3945 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3946 Matrix4x4_Abs(&radiustolight);
3948 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3950 // render lighting using the depth texture as shadowmap
3951 // draw lighting in the unmasked areas
3952 if (numsurfaces + numlightentities)
3954 R_Shadow_RenderMode_Lighting(false, true, false);
3955 // draw lighting in the unmasked areas
3957 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3958 for (i = 0; i < numlightentities; i++)
3959 R_Shadow_DrawEntityLight(lightentities[i]);
3961 // offset to the noselfshadow part of the atlas and draw those too
3962 if (numlightentities_noselfshadow)
3964 R_Shadow_RenderMode_Lighting(false, true, true);
3965 for (i = 0; i < numlightentities_noselfshadow; i++)
3966 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3969 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3970 if (r_shadow_usingdeferredprepass)
3971 R_Shadow_RenderMode_DrawDeferredLight(true);
3975 // draw lighting in the unmasked areas
3976 R_Shadow_RenderMode_Lighting(false, false, false);
3978 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3979 for (i = 0;i < numlightentities;i++)
3980 R_Shadow_DrawEntityLight(lightentities[i]);
3981 for (i = 0;i < numlightentities_noselfshadow;i++)
3982 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3984 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3985 if (r_shadow_usingdeferredprepass)
3986 R_Shadow_RenderMode_DrawDeferredLight(false);
3990 static void R_Shadow_FreeDeferred(void)
3992 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3993 r_shadow_prepassgeometryfbo = 0;
3995 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3996 r_shadow_prepasslightingdiffusespecularfbo = 0;
3998 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3999 r_shadow_prepasslightingdiffusefbo = 0;
4001 if (r_shadow_prepassgeometrydepthbuffer)
4002 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4003 r_shadow_prepassgeometrydepthbuffer = NULL;
4005 if (r_shadow_prepassgeometrynormalmaptexture)
4006 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4007 r_shadow_prepassgeometrynormalmaptexture = NULL;
4009 if (r_shadow_prepasslightingdiffusetexture)
4010 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4011 r_shadow_prepasslightingdiffusetexture = NULL;
4013 if (r_shadow_prepasslightingspeculartexture)
4014 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4015 r_shadow_prepasslightingspeculartexture = NULL;
4018 void R_Shadow_DrawPrepass(void)
4022 entity_render_t *ent;
4023 float clearcolor[4];
4025 R_Mesh_ResetTextureState();
4027 GL_ColorMask(1,1,1,1);
4028 GL_BlendFunc(GL_ONE, GL_ZERO);
4031 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4032 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4033 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4034 if (r_timereport_active)
4035 R_TimeReport("prepasscleargeom");
4037 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4038 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4039 if (r_timereport_active)
4040 R_TimeReport("prepassworld");
4042 for (i = 0;i < r_refdef.scene.numentities;i++)
4044 if (!r_refdef.viewcache.entityvisible[i])
4046 ent = r_refdef.scene.entities[i];
4047 if (ent->model && ent->model->DrawPrepass != NULL)
4048 ent->model->DrawPrepass(ent);
4051 if (r_timereport_active)
4052 R_TimeReport("prepassmodels");
4054 GL_DepthMask(false);
4055 GL_ColorMask(1,1,1,1);
4058 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4059 Vector4Set(clearcolor, 0, 0, 0, 0);
4060 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4061 if (r_timereport_active)
4062 R_TimeReport("prepassclearlit");
4064 R_Shadow_RenderMode_Begin();
4066 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4067 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4069 R_Shadow_RenderMode_End();
4071 if (r_timereport_active)
4072 R_TimeReport("prepasslights");
4075 #define MAX_SCENELIGHTS 65536
4076 static qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4078 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4080 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4082 r_shadow_scenemaxlights *= 2;
4083 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4084 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4086 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4090 void R_Shadow_DrawLightSprites(void);
4091 void R_Shadow_PrepareLights(void)
4100 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4101 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4102 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4104 if (r_shadow_shadowmode_shadowmapping != r_shadow_shadowmapping.integer ||
4105 r_shadow_shadowmode_deferred != r_shadow_deferred.integer ||
4106 r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4107 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4108 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4109 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4110 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4111 r_shadow_shadowmapborder != shadowmapborder ||
4112 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4113 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4114 R_Shadow_FreeShadowMaps();
4116 r_shadow_usingshadowmaportho = false;
4118 switch (vid.renderpath)
4120 case RENDERPATH_GL32:
4122 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4124 r_shadow_usingdeferredprepass = false;
4125 if (r_shadow_prepass_width)
4126 R_Shadow_FreeDeferred();
4127 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4131 if (r_shadow_prepass_width != r_fb.screentexturewidth || r_shadow_prepass_height != r_fb.screentextureheight)
4133 R_Shadow_FreeDeferred();
4135 r_shadow_usingdeferredprepass = true;
4136 r_shadow_prepass_width = r_fb.screentexturewidth;
4137 r_shadow_prepass_height = r_fb.screentextureheight;
4138 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", r_fb.screentexturewidth, r_fb.screentextureheight, TEXTYPE_DEPTHBUFFER24);
4139 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4140 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4141 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4143 // set up the geometry pass fbo (depth + normalmap)
4144 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4145 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4146 // render depth into a renderbuffer and other important properties into the normalmap texture
4148 // set up the lighting pass fbo (diffuse + specular)
4149 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4150 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4151 // render diffuse into one texture and specular into another,
4152 // with depth and normalmap bound as textures,
4153 // with depth bound as attachment as well
4155 // set up the lighting pass fbo (diffuse)
4156 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4157 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4158 // render diffuse into one texture,
4159 // with depth and normalmap bound as textures,
4160 // with depth bound as attachment as well
4164 case RENDERPATH_GLES2:
4165 r_shadow_usingdeferredprepass = false;
4169 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
4171 r_shadow_scenenumlights = 0;
4172 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4173 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4174 for (lightindex = 0; lightindex < range; lightindex++)
4176 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4177 if (light && (light->flags & flag))
4179 R_Shadow_PrepareLight(&light->rtlight);
4180 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4183 if (r_refdef.scene.rtdlight)
4185 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4187 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4188 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4191 else if (gl_flashblend.integer)
4193 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4195 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4196 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4197 VectorScale(rtlight->color, f, rtlight->currentcolor);
4201 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4202 if (r_shadow_debuglight.integer >= 0)
4204 r_shadow_scenenumlights = 0;
4205 lightindex = r_shadow_debuglight.integer;
4206 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4209 R_Shadow_PrepareLight(&light->rtlight);
4210 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4214 // if we're doing shadowmaps we need to prepare the atlas layout now
4215 if (R_Shadow_ShadowMappingEnabled())
4219 // allocate shadowmaps in the atlas now
4220 // we may have to make multiple attempts to fit the shadowmaps in the limited space of the atlas, this will appear as lod popping of all shadowmaps whenever it changes, but at least we can still cast shadows from all lights...
4221 for (lod = 0; lod < 16; lod++)
4223 int packing_success = 0;
4224 int packing_failure = 0;
4225 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4226 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4227 if (r_shadow_shadowmapatlas_modelshadows_size)
4228 Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, &r_shadow_shadowmapatlas_modelshadows_x, &r_shadow_shadowmapatlas_modelshadows_y);
4229 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4231 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4232 int size = rtlight->shadowmapsidesize >> lod;
4234 if (!rtlight->castshadows)
4236 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4239 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4240 if (rtlight->cached_numshadowentities_noselfshadow)
4242 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4244 rtlight->shadowmapatlassidesize = size;
4249 // note down that we failed to pack this one, it will have to disable shadows
4250 rtlight->shadowmapatlassidesize = 0;
4254 // generally everything fits and we stop here on the first iteration
4255 if (packing_failure == 0)
4260 if (r_editlights.integer)
4261 R_Shadow_DrawLightSprites();
4264 void R_Shadow_DrawShadowMaps(void)
4266 R_Shadow_RenderMode_Begin();
4267 R_Shadow_RenderMode_ActiveLight(NULL);
4269 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4270 R_Shadow_ClearShadowMapTexture();
4272 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4273 if (r_shadow_shadowmapatlas_modelshadows_size)
4275 R_Shadow_DrawModelShadowMaps();
4276 // don't let sound skip if going slow
4277 if (r_refdef.scene.extraupdate)
4281 if (R_Shadow_ShadowMappingEnabled())
4284 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4285 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4288 R_Shadow_RenderMode_End();
4291 void R_Shadow_DrawLights(void)
4295 R_Shadow_RenderMode_Begin();
4297 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4298 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4300 R_Shadow_RenderMode_End();
4303 #define MAX_MODELSHADOWS 1024
4304 static int r_shadow_nummodelshadows;
4305 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4307 void R_Shadow_PrepareModelShadows(void)
4310 float scale, size, radius, dot1, dot2;
4311 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4312 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4313 entity_render_t *ent;
4315 r_shadow_nummodelshadows = 0;
4316 r_shadow_shadowmapatlas_modelshadows_size = 0;
4318 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4321 size = r_shadow_shadowmaptexturesize / 4;
4322 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4323 radius = 0.5f * size / scale;
4325 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4326 VectorCopy(prvmshadowdir, shadowdir);
4327 VectorNormalize(shadowdir);
4328 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4329 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4330 if (fabs(dot1) <= fabs(dot2))
4331 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4333 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4334 VectorNormalize(shadowforward);
4335 CrossProduct(shadowdir, shadowforward, shadowright);
4336 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4337 VectorCopy(prvmshadowfocus, shadowfocus);
4338 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4339 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4340 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4341 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4342 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4344 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4346 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4347 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4348 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4349 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4350 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4351 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4353 for (i = 0; i < r_refdef.scene.numentities; i++)
4355 ent = r_refdef.scene.entities[i];
4356 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4358 // cast shadows from anything of the map (submodels are optional)
4359 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4361 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4363 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4364 R_AnimCache_GetEntity(ent, false, false);
4368 if (r_shadow_nummodelshadows)
4370 r_shadow_shadowmapatlas_modelshadows_x = 0;
4371 r_shadow_shadowmapatlas_modelshadows_y = 0;
4372 r_shadow_shadowmapatlas_modelshadows_size = size;
4376 static void R_Shadow_DrawModelShadowMaps(void)
4379 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4380 entity_render_t *ent;
4381 vec3_t relativelightorigin;
4382 vec3_t relativelightdirection, relativeforward, relativeright;
4383 vec3_t relativeshadowmins, relativeshadowmaxs;
4384 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4385 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4387 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4388 r_viewport_t viewport;
4390 size = r_shadow_shadowmapatlas_modelshadows_size;
4391 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4392 radius = 0.5f / scale;
4393 nearclip = -r_shadows_throwdistance.value;
4394 farclip = r_shadows_throwdistance.value;
4395 bias = (r_shadows_shadowmapbias.value < 0) ? r_shadow_shadowmapping_bias.value : r_shadows_shadowmapbias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4397 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4398 r_shadow_modelshadowmap_parameters[0] = size;
4399 r_shadow_modelshadowmap_parameters[1] = size;
4400 r_shadow_modelshadowmap_parameters[2] = 1.0;
4401 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4402 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4403 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4404 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4405 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4406 r_shadow_usingshadowmaportho = true;
4408 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4409 VectorCopy(prvmshadowdir, shadowdir);
4410 VectorNormalize(shadowdir);
4411 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4412 VectorCopy(prvmshadowfocus, shadowfocus);
4413 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4414 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4415 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4416 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4417 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4418 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4419 if (fabs(dot1) <= fabs(dot2))
4420 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4422 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4423 VectorNormalize(shadowforward);
4424 VectorM(scale, shadowforward, &m[0]);
4425 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4427 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4428 CrossProduct(shadowdir, shadowforward, shadowright);
4429 VectorM(scale, shadowright, &m[4]);
4430 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4431 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4432 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4433 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4434 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4435 R_Viewport_InitOrtho(&viewport, &cameramatrix, r_shadow_shadowmapatlas_modelshadows_x, r_shadow_shadowmapatlas_modelshadows_y, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, 0, 0, 1, 1, 0, -1, NULL);
4436 R_SetViewport(&viewport);
4438 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4440 // render into a slightly restricted region so that the borders of the
4441 // shadowmap area fade away, rather than streaking across everything
4442 // outside the usable area
4443 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4445 for (i = 0;i < r_shadow_nummodelshadows;i++)
4447 ent = r_shadow_modelshadows[i];
4448 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4449 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4450 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4451 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4452 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4453 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4454 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4455 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4456 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4457 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4458 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4459 RSurf_ActiveModelEntity(ent, false, false, false);
4460 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4461 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4467 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4469 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4471 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4472 Cvar_SetValueQuick(&r_test, 0);
4477 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4478 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4479 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4480 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4481 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4482 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4485 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4488 vec3_t centerorigin;
4492 // if it's too close, skip it
4493 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4495 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4498 if (usequery && r_numqueries + 2 <= r_maxqueries)
4500 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4501 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4502 // we count potential samples in the middle of the screen, we count actual samples at the light location, this allows counting potential samples of off-screen lights
4503 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4505 switch(vid.renderpath)
4507 case RENDERPATH_GL32:
4508 case RENDERPATH_GLES2:
4511 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4512 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4513 GL_DepthFunc(GL_ALWAYS);
4514 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4515 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4516 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4517 qglEndQuery(GL_SAMPLES_PASSED);
4518 GL_DepthFunc(GL_LEQUAL);
4519 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4520 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4521 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4522 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4523 qglEndQuery(GL_SAMPLES_PASSED);
4529 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4532 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4534 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4537 unsigned int occlude = 0;
4539 // now we have to check the query result
4540 if (rtlight->corona_queryindex_visiblepixels)
4542 switch(vid.renderpath)
4544 case RENDERPATH_GL32:
4545 case RENDERPATH_GLES2:
4547 // store the pixel counts into a uniform buffer for the shader to
4548 // use - we'll never know the results on the cpu without
4549 // synchronizing and we don't want that
4550 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4551 if (!r_shadow_occlusion_buf) {
4552 qglGenBuffers(1, &r_shadow_occlusion_buf);
4553 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4554 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4556 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4558 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4559 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4560 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4561 occlude = MATERIALFLAG_OCCLUDE;
4562 cscale *= rtlight->corona_visibility;
4572 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4575 VectorScale(rtlight->currentcolor, cscale, color);
4576 if (VectorLength(color) > (1.0f / 256.0f))
4579 qboolean negated = (color[0] + color[1] + color[2] < 0);
4582 VectorNegate(color, color);
4583 GL_BlendEquationSubtract(true);
4585 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4586 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4587 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4589 GL_BlendEquationSubtract(false);
4593 void R_Shadow_DrawCoronas(void)
4596 qboolean usequery = false;
4601 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4603 if (r_fb.water.renderingscene)
4605 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4606 R_EntityMatrix(&identitymatrix);
4608 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4610 // check occlusion of coronas, using occlusion queries or raytraces
4612 switch (vid.renderpath)
4614 case RENDERPATH_GL32:
4615 case RENDERPATH_GLES2:
4616 usequery = r_coronas_occlusionquery.integer;
4620 GL_ColorMask(0,0,0,0);
4621 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4622 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4625 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4626 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4628 qglGenQueries(r_maxqueries - i, r_queries + i);
4631 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4632 GL_BlendFunc(GL_ONE, GL_ZERO);
4633 GL_CullFace(GL_NONE);
4634 GL_DepthMask(false);
4635 GL_DepthRange(0, 1);
4636 GL_PolygonOffset(0, 0);
4638 R_Mesh_ResetTextureState();
4639 R_SetupShader_Generic_NoTexture(false, false);
4644 for (lightindex = 0;lightindex < range;lightindex++)
4646 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4649 rtlight = &light->rtlight;
4650 rtlight->corona_visibility = 0;
4651 rtlight->corona_queryindex_visiblepixels = 0;
4652 rtlight->corona_queryindex_allpixels = 0;
4653 if (!(rtlight->flags & flag))
4655 if (rtlight->corona <= 0)
4657 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4659 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4661 for (i = 0;i < r_refdef.scene.numlights;i++)
4663 rtlight = r_refdef.scene.lights[i];
4664 rtlight->corona_visibility = 0;
4665 rtlight->corona_queryindex_visiblepixels = 0;
4666 rtlight->corona_queryindex_allpixels = 0;
4667 if (!(rtlight->flags & flag))
4669 if (rtlight->corona <= 0)
4671 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4674 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4676 // now draw the coronas using the query data for intensity info
4677 for (lightindex = 0;lightindex < range;lightindex++)
4679 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4682 rtlight = &light->rtlight;
4683 if (rtlight->corona_visibility <= 0)
4685 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4687 for (i = 0;i < r_refdef.scene.numlights;i++)
4689 rtlight = r_refdef.scene.lights[i];
4690 if (rtlight->corona_visibility <= 0)
4692 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4698 static dlight_t *R_Shadow_NewWorldLight(void)
4700 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4703 static 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)
4707 // note that style is no longer validated here, -1 is used for unstyled lights and >= MAX_LIGHTSTYLES is accepted for sake of editing rtlights files that might be out of bounds but perfectly formatted
4709 // validate parameters
4713 // copy to light properties
4714 VectorCopy(origin, light->origin);
4715 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4716 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4717 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4719 light->color[0] = max(color[0], 0);
4720 light->color[1] = max(color[1], 0);
4721 light->color[2] = max(color[2], 0);
4723 light->color[0] = color[0];
4724 light->color[1] = color[1];
4725 light->color[2] = color[2];
4726 light->radius = max(radius, 0);
4727 light->style = style;
4728 light->shadow = shadowenable;
4729 light->corona = corona;
4730 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4731 light->coronasizescale = coronasizescale;
4732 light->ambientscale = ambientscale;
4733 light->diffusescale = diffusescale;
4734 light->specularscale = specularscale;
4735 light->flags = flags;
4737 // update renderable light data
4738 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4739 R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
4742 static void R_Shadow_FreeWorldLight(dlight_t *light)
4744 if (r_shadow_selectedlight == light)
4745 r_shadow_selectedlight = NULL;
4746 R_RTLight_Uncompile(&light->rtlight);
4747 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4750 void R_Shadow_ClearWorldLights(void)
4754 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4755 for (lightindex = 0;lightindex < range;lightindex++)
4757 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4759 R_Shadow_FreeWorldLight(light);
4761 r_shadow_selectedlight = NULL;
4764 static void R_Shadow_SelectLight(dlight_t *light)
4766 if (r_shadow_selectedlight)
4767 r_shadow_selectedlight->selected = false;
4768 r_shadow_selectedlight = light;
4769 if (r_shadow_selectedlight)
4770 r_shadow_selectedlight->selected = true;
4773 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4775 // this is never batched (there can be only one)
4777 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4778 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4779 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4782 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4787 skinframe_t *skinframe;
4790 // this is never batched (due to the ent parameter changing every time)
4791 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4792 const dlight_t *light = (dlight_t *)ent;
4795 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4798 VectorScale(light->color, intensity, spritecolor);
4799 if (VectorLength(spritecolor) < 0.1732f)
4800 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4801 if (VectorLength(spritecolor) > 1.0f)
4802 VectorNormalize(spritecolor);
4804 // draw light sprite
4805 if (light->cubemapname[0] && !light->shadow)
4806 skinframe = r_editlights_sprcubemapnoshadowlight;
4807 else if (light->cubemapname[0])
4808 skinframe = r_editlights_sprcubemaplight;
4809 else if (!light->shadow)
4810 skinframe = r_editlights_sprnoshadowlight;
4812 skinframe = r_editlights_sprlight;
4814 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, spritecolor[0], spritecolor[1], spritecolor[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4815 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4817 // draw selection sprite if light is selected
4818 if (light->selected)
4820 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4821 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4822 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4826 void R_Shadow_DrawLightSprites(void)
4830 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4831 for (lightindex = 0;lightindex < range;lightindex++)
4833 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4835 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4837 if (!r_editlights_lockcursor)
4838 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4841 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4846 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4847 if (lightindex >= range)
4849 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4852 rtlight = &light->rtlight;
4853 //if (!(rtlight->flags & flag))
4855 VectorCopy(rtlight->shadoworigin, origin);
4856 *radius = rtlight->radius;
4857 VectorCopy(rtlight->color, color);
4861 static void R_Shadow_SelectLightInView(void)
4863 float bestrating, rating, temp[3];
4867 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4871 if (r_editlights_lockcursor)
4873 for (lightindex = 0;lightindex < range;lightindex++)
4875 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4878 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4879 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4882 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4883 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
4885 bestrating = rating;
4890 R_Shadow_SelectLight(best);
4893 void R_Shadow_LoadWorldLights(void)
4895 int n, a, style, shadow, flags;
4896 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4897 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4898 if (cl.worldmodel == NULL)
4900 Con_Print("No map loaded.\n");
4903 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4904 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4914 for (;COM_Parse(t, true) && strcmp(
4915 if (COM_Parse(t, true))
4917 if (com_token[0] == '!')
4920 origin[0] = atof(com_token+1);
4923 origin[0] = atof(com_token);
4928 while (*s && *s != '\n' && *s != '\r')
4934 // check for modifier flags
4941 #if _MSC_VER >= 1400
4942 #define sscanf sscanf_s
4944 cubemapname[sizeof(cubemapname)-1] = 0;
4945 #if MAX_QPATH != 128
4946 #error update this code if MAX_QPATH changes
4948 a = sscanf(t, "%f %f %f %f %f %f %f %d %127s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname
4949 #if _MSC_VER >= 1400
4950 , (unsigned int)sizeof(cubemapname)
4952 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4955 flags = LIGHTFLAG_REALTIMEMODE;
4963 coronasizescale = 0.25f;
4965 VectorClear(angles);
4968 if (a < 9 || !strcmp(cubemapname, "\"\""))
4970 // remove quotes on cubemapname
4971 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4974 namelen = strlen(cubemapname) - 2;
4975 memmove(cubemapname, cubemapname + 1, namelen);
4976 cubemapname[namelen] = '\0';
4980 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);
4983 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4991 Con_Printf("invalid rtlights file \"%s\"\n", name);
4992 Mem_Free(lightsstring);
4996 void R_Shadow_SaveWorldLights(void)
5000 size_t bufchars, bufmaxchars;
5002 char name[MAX_QPATH];
5003 char line[MAX_INPUTLINE];
5004 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5005 // I hate lines which are 3 times my screen size :( --blub
5008 if (cl.worldmodel == NULL)
5010 Con_Print("No map loaded.\n");
5013 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5014 bufchars = bufmaxchars = 0;
5016 for (lightindex = 0;lightindex < range;lightindex++)
5018 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5021 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5022 dpsnprintf(line, sizeof(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);
5023 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5024 dpsnprintf(line, sizeof(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]);
5026 dpsnprintf(line, sizeof(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);
5027 if (bufchars + strlen(line) > bufmaxchars)
5029 bufmaxchars = bufchars + strlen(line) + 2048;
5031 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5035 memcpy(buf, oldbuf, bufchars);
5041 memcpy(buf + bufchars, line, strlen(line));
5042 bufchars += strlen(line);
5046 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5051 void R_Shadow_LoadLightsFile(void)
5054 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5055 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5056 if (cl.worldmodel == NULL)
5058 Con_Print("No map loaded.\n");
5061 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5062 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5070 while (*s && *s != '\n' && *s != '\r')
5076 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);
5080 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);
5083 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5084 radius = bound(15, radius, 4096);
5085 VectorScale(color, (2.0f / (8388608.0f)), color);
5086 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5094 Con_Printf("invalid lights file \"%s\"\n", name);
5095 Mem_Free(lightsstring);
5099 // tyrlite/hmap2 light types in the delay field
5100 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5102 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5114 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5115 char key[256], value[MAX_INPUTLINE];
5118 if (cl.worldmodel == NULL)
5120 Con_Print("No map loaded.\n");
5123 // try to load a .ent file first
5124 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5125 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5126 // and if that is not found, fall back to the bsp file entity string
5128 data = cl.worldmodel->brush.entities;
5131 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5133 type = LIGHTTYPE_MINUSX;
5134 origin[0] = origin[1] = origin[2] = 0;
5135 originhack[0] = originhack[1] = originhack[2] = 0;
5136 angles[0] = angles[1] = angles[2] = 0;
5137 color[0] = color[1] = color[2] = 1;
5138 light[0] = light[1] = light[2] = 1;light[3] = 300;
5139 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5149 if (!COM_ParseToken_Simple(&data, false, false, true))
5151 if (com_token[0] == '}')
5152 break; // end of entity
5153 if (com_token[0] == '_')
5154 strlcpy(key, com_token + 1, sizeof(key));
5156 strlcpy(key, com_token, sizeof(key));
5157 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5158 key[strlen(key)-1] = 0;
5159 if (!COM_ParseToken_Simple(&data, false, false, true))
5161 strlcpy(value, com_token, sizeof(value));
5163 // now that we have the key pair worked out...
5164 if (!strcmp("light", key))
5166 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5170 light[0] = vec[0] * (1.0f / 256.0f);
5171 light[1] = vec[0] * (1.0f / 256.0f);
5172 light[2] = vec[0] * (1.0f / 256.0f);
5178 light[0] = vec[0] * (1.0f / 255.0f);
5179 light[1] = vec[1] * (1.0f / 255.0f);
5180 light[2] = vec[2] * (1.0f / 255.0f);
5184 else if (!strcmp("delay", key))
5186 else if (!strcmp("origin", key))
5187 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5188 else if (!strcmp("angle", key))
5189 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5190 else if (!strcmp("angles", key))
5191 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5192 else if (!strcmp("color", key))
5193 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5194 else if (!strcmp("wait", key))
5195 fadescale = atof(value);
5196 else if (!strcmp("classname", key))
5198 if (!strncmp(value, "light", 5))
5201 if (!strcmp(value, "light_fluoro"))
5206 overridecolor[0] = 1;
5207 overridecolor[1] = 1;
5208 overridecolor[2] = 1;
5210 if (!strcmp(value, "light_fluorospark"))
5215 overridecolor[0] = 1;
5216 overridecolor[1] = 1;
5217 overridecolor[2] = 1;
5219 if (!strcmp(value, "light_globe"))
5224 overridecolor[0] = 1;
5225 overridecolor[1] = 0.8;
5226 overridecolor[2] = 0.4;
5228 if (!strcmp(value, "light_flame_large_yellow"))
5233 overridecolor[0] = 1;
5234 overridecolor[1] = 0.5;
5235 overridecolor[2] = 0.1;
5237 if (!strcmp(value, "light_flame_small_yellow"))
5242 overridecolor[0] = 1;
5243 overridecolor[1] = 0.5;
5244 overridecolor[2] = 0.1;
5246 if (!strcmp(value, "light_torch_small_white"))
5251 overridecolor[0] = 1;
5252 overridecolor[1] = 0.5;
5253 overridecolor[2] = 0.1;
5255 if (!strcmp(value, "light_torch_small_walltorch"))
5260 overridecolor[0] = 1;
5261 overridecolor[1] = 0.5;
5262 overridecolor[2] = 0.1;
5266 else if (!strcmp("style", key))
5267 style = atoi(value);
5268 else if (!strcmp("skin", key))
5269 skin = (int)atof(value);
5270 else if (!strcmp("pflags", key))
5271 pflags = (int)atof(value);
5272 //else if (!strcmp("effects", key))
5273 // effects = (int)atof(value);
5274 else if (cl.worldmodel->type == mod_brushq3)
5276 if (!strcmp("scale", key))
5277 lightscale = atof(value);
5278 if (!strcmp("fade", key))
5279 fadescale = atof(value);
5284 if (lightscale <= 0)
5288 if (color[0] == color[1] && color[0] == color[2])
5290 color[0] *= overridecolor[0];
5291 color[1] *= overridecolor[1];
5292 color[2] *= overridecolor[2];
5294 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5295 color[0] = color[0] * light[0];
5296 color[1] = color[1] * light[1];
5297 color[2] = color[2] * light[2];
5300 case LIGHTTYPE_MINUSX:
5302 case LIGHTTYPE_RECIPX:
5304 VectorScale(color, (1.0f / 16.0f), color);
5306 case LIGHTTYPE_RECIPXX:
5308 VectorScale(color, (1.0f / 16.0f), color);
5311 case LIGHTTYPE_NONE:
5315 case LIGHTTYPE_MINUSXX:
5318 VectorAdd(origin, originhack, origin);
5320 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5323 Mem_Free(entfiledata);
5327 static void R_Shadow_SetCursorLocationForView(void)
5330 vec3_t dest, endpos;
5332 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5333 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5334 if (trace.fraction < 1)
5336 dist = trace.fraction * r_editlights_cursordistance.value;
5337 push = r_editlights_cursorpushback.value;
5341 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5342 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5346 VectorClear( endpos );
5348 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5349 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5350 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5353 void R_Shadow_UpdateWorldLightSelection(void)
5355 if (r_editlights.integer)
5357 R_Shadow_SetCursorLocationForView();
5358 R_Shadow_SelectLightInView();
5361 R_Shadow_SelectLight(NULL);
5364 static void R_Shadow_EditLights_Clear_f(cmd_state_t *cmd)
5366 R_Shadow_ClearWorldLights();
5369 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd)
5373 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5374 R_Shadow_ClearWorldLights();
5375 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5377 R_Shadow_LoadWorldLights();
5378 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5379 R_Shadow_LoadLightsFile();
5381 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5383 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5384 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5388 static void R_Shadow_EditLights_Save_f(cmd_state_t *cmd)
5392 R_Shadow_SaveWorldLights();
5395 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(cmd_state_t *cmd)
5397 R_Shadow_ClearWorldLights();
5398 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5401 static void R_Shadow_EditLights_ImportLightsFile_f(cmd_state_t *cmd)
5403 R_Shadow_ClearWorldLights();
5404 R_Shadow_LoadLightsFile();
5407 static void R_Shadow_EditLights_Spawn_f(cmd_state_t *cmd)
5410 if (!r_editlights.integer)
5412 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5415 if (Cmd_Argc(cmd) != 1)
5417 Con_Print("r_editlights_spawn does not take parameters\n");
5420 color[0] = color[1] = color[2] = 1;
5421 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5424 static void R_Shadow_EditLights_Edit_f(cmd_state_t *cmd)
5426 vec3_t origin, angles, color;
5427 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5428 int style, shadows, flags, normalmode, realtimemode;
5429 char cubemapname[MAX_INPUTLINE];
5430 if (!r_editlights.integer)
5432 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5435 if (!r_shadow_selectedlight)
5437 Con_Print("No selected light.\n");
5440 VectorCopy(r_shadow_selectedlight->origin, origin);
5441 VectorCopy(r_shadow_selectedlight->angles, angles);
5442 VectorCopy(r_shadow_selectedlight->color, color);
5443 radius = r_shadow_selectedlight->radius;
5444 style = r_shadow_selectedlight->style;
5445 if (*r_shadow_selectedlight->cubemapname)
5446 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5449 shadows = r_shadow_selectedlight->shadow;
5450 corona = r_shadow_selectedlight->corona;
5451 coronasizescale = r_shadow_selectedlight->coronasizescale;
5452 ambientscale = r_shadow_selectedlight->ambientscale;
5453 diffusescale = r_shadow_selectedlight->diffusescale;
5454 specularscale = r_shadow_selectedlight->specularscale;
5455 flags = r_shadow_selectedlight->flags;
5456 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5457 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5458 if (!strcmp(Cmd_Argv(cmd, 1), "origin"))
5460 if (Cmd_Argc(cmd) != 5)
5462 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5465 origin[0] = atof(Cmd_Argv(cmd, 2));
5466 origin[1] = atof(Cmd_Argv(cmd, 3));
5467 origin[2] = atof(Cmd_Argv(cmd, 4));
5469 else if (!strcmp(Cmd_Argv(cmd, 1), "originscale"))
5471 if (Cmd_Argc(cmd) != 5)
5473 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5476 origin[0] *= atof(Cmd_Argv(cmd, 2));
5477 origin[1] *= atof(Cmd_Argv(cmd, 3));
5478 origin[2] *= atof(Cmd_Argv(cmd, 4));
5480 else if (!strcmp(Cmd_Argv(cmd, 1), "originx"))
5482 if (Cmd_Argc(cmd) != 3)
5484 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5487 origin[0] = atof(Cmd_Argv(cmd, 2));
5489 else if (!strcmp(Cmd_Argv(cmd, 1), "originy"))
5491 if (Cmd_Argc(cmd) != 3)
5493 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5496 origin[1] = atof(Cmd_Argv(cmd, 2));
5498 else if (!strcmp(Cmd_Argv(cmd, 1), "originz"))
5500 if (Cmd_Argc(cmd) != 3)
5502 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5505 origin[2] = atof(Cmd_Argv(cmd, 2));
5507 else if (!strcmp(Cmd_Argv(cmd, 1), "move"))
5509 if (Cmd_Argc(cmd) != 5)
5511 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5514 origin[0] += atof(Cmd_Argv(cmd, 2));
5515 origin[1] += atof(Cmd_Argv(cmd, 3));
5516 origin[2] += atof(Cmd_Argv(cmd, 4));
5518 else if (!strcmp(Cmd_Argv(cmd, 1), "movex"))
5520 if (Cmd_Argc(cmd) != 3)
5522 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5525 origin[0] += atof(Cmd_Argv(cmd, 2));
5527 else if (!strcmp(Cmd_Argv(cmd, 1), "movey"))
5529 if (Cmd_Argc(cmd) != 3)
5531 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5534 origin[1] += atof(Cmd_Argv(cmd, 2));
5536 else if (!strcmp(Cmd_Argv(cmd, 1), "movez"))
5538 if (Cmd_Argc(cmd) != 3)
5540 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5543 origin[2] += atof(Cmd_Argv(cmd, 2));
5545 else if (!strcmp(Cmd_Argv(cmd, 1), "angles"))
5547 if (Cmd_Argc(cmd) != 5)
5549 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5552 angles[0] = atof(Cmd_Argv(cmd, 2));
5553 angles[1] = atof(Cmd_Argv(cmd, 3));
5554 angles[2] = atof(Cmd_Argv(cmd, 4));
5556 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesx"))
5558 if (Cmd_Argc(cmd) != 3)
5560 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5563 angles[0] = atof(Cmd_Argv(cmd, 2));
5565 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesy"))
5567 if (Cmd_Argc(cmd) != 3)
5569 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5572 angles[1] = atof(Cmd_Argv(cmd, 2));
5574 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesz"))
5576 if (Cmd_Argc(cmd) != 3)
5578 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5581 angles[2] = atof(Cmd_Argv(cmd, 2));
5583 else if (!strcmp(Cmd_Argv(cmd, 1), "color"))
5585 if (Cmd_Argc(cmd) != 5)
5587 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(cmd, 1));
5590 color[0] = atof(Cmd_Argv(cmd, 2));
5591 color[1] = atof(Cmd_Argv(cmd, 3));
5592 color[2] = atof(Cmd_Argv(cmd, 4));
5594 else if (!strcmp(Cmd_Argv(cmd, 1), "radius"))
5596 if (Cmd_Argc(cmd) != 3)
5598 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5601 radius = atof(Cmd_Argv(cmd, 2));
5603 else if (!strcmp(Cmd_Argv(cmd, 1), "colorscale"))
5605 if (Cmd_Argc(cmd) == 3)
5607 double scale = atof(Cmd_Argv(cmd, 2));
5614 if (Cmd_Argc(cmd) != 5)
5616 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(cmd, 1));
5619 color[0] *= atof(Cmd_Argv(cmd, 2));
5620 color[1] *= atof(Cmd_Argv(cmd, 3));
5621 color[2] *= atof(Cmd_Argv(cmd, 4));
5624 else if (!strcmp(Cmd_Argv(cmd, 1), "radiusscale") || !strcmp(Cmd_Argv(cmd, 1), "sizescale"))
5626 if (Cmd_Argc(cmd) != 3)
5628 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5631 radius *= atof(Cmd_Argv(cmd, 2));
5633 else if (!strcmp(Cmd_Argv(cmd, 1), "style"))
5635 if (Cmd_Argc(cmd) != 3)
5637 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5640 style = atoi(Cmd_Argv(cmd, 2));
5642 else if (!strcmp(Cmd_Argv(cmd, 1), "cubemap"))
5644 if (Cmd_Argc(cmd) > 3)
5646 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5649 if (Cmd_Argc(cmd) == 3)
5650 strlcpy(cubemapname, Cmd_Argv(cmd, 2), sizeof(cubemapname));
5654 else if (!strcmp(Cmd_Argv(cmd, 1), "shadows"))
5656 if (Cmd_Argc(cmd) != 3)
5658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5661 shadows = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5663 else if (!strcmp(Cmd_Argv(cmd, 1), "corona"))
5665 if (Cmd_Argc(cmd) != 3)
5667 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5670 corona = atof(Cmd_Argv(cmd, 2));
5672 else if (!strcmp(Cmd_Argv(cmd, 1), "coronasize"))
5674 if (Cmd_Argc(cmd) != 3)
5676 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5679 coronasizescale = atof(Cmd_Argv(cmd, 2));
5681 else if (!strcmp(Cmd_Argv(cmd, 1), "ambient"))
5683 if (Cmd_Argc(cmd) != 3)
5685 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5688 ambientscale = atof(Cmd_Argv(cmd, 2));
5690 else if (!strcmp(Cmd_Argv(cmd, 1), "diffuse"))
5692 if (Cmd_Argc(cmd) != 3)
5694 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5697 diffusescale = atof(Cmd_Argv(cmd, 2));
5699 else if (!strcmp(Cmd_Argv(cmd, 1), "specular"))
5701 if (Cmd_Argc(cmd) != 3)
5703 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5706 specularscale = atof(Cmd_Argv(cmd, 2));
5708 else if (!strcmp(Cmd_Argv(cmd, 1), "normalmode"))
5710 if (Cmd_Argc(cmd) != 3)
5712 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5715 normalmode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5717 else if (!strcmp(Cmd_Argv(cmd, 1), "realtimemode"))
5719 if (Cmd_Argc(cmd) != 3)
5721 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5724 realtimemode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5728 Con_Print("usage: r_editlights_edit [property] [value]\n");
5729 Con_Print("Selected light's properties:\n");
5730 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5731 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5732 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5733 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5734 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5735 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5736 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5737 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5738 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5739 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5740 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5741 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5742 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5743 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5746 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5747 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5750 static void R_Shadow_EditLights_EditAll_f(cmd_state_t *cmd)
5753 dlight_t *light, *oldselected;
5756 if (!r_editlights.integer)
5758 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5762 oldselected = r_shadow_selectedlight;
5763 // EditLights doesn't seem to have a "remove" command or something so:
5764 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5765 for (lightindex = 0;lightindex < range;lightindex++)
5767 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5770 R_Shadow_SelectLight(light);
5771 R_Shadow_EditLights_Edit_f(&cmd_client);
5773 // return to old selected (to not mess editing once selection is locked)
5774 R_Shadow_SelectLight(oldselected);
5777 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5779 int lightnumber, lightcount;
5780 size_t lightindex, range;
5785 if (!r_editlights.integer)
5788 // update cvars so QC can query them
5789 if (r_shadow_selectedlight)
5791 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5792 Cvar_SetQuick(&r_editlights_current_origin, temp);
5793 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5794 Cvar_SetQuick(&r_editlights_current_angles, temp);
5795 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5796 Cvar_SetQuick(&r_editlights_current_color, temp);
5797 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5798 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5799 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5800 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5801 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5802 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5803 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5804 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5805 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5806 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5807 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5810 // draw properties on screen
5811 if (!r_editlights_drawproperties.integer)
5813 x = vid_conwidth.value - 320;
5815 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5818 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5819 for (lightindex = 0;lightindex < range;lightindex++)
5821 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5824 if (light == r_shadow_selectedlight)
5825 lightnumber = (int)lightindex;
5828 dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5829 dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5831 if (r_shadow_selectedlight == NULL)
5833 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5834 dpsnprintf(temp, sizeof(temp), "Origin : %.0f %.0f %.0f\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, NULL, true, FONT_DEFAULT);y += 8;
5835 dpsnprintf(temp, sizeof(temp), "Angles : %.0f %.0f %.0f\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, NULL, true, FONT_DEFAULT);y += 8;
5836 dpsnprintf(temp, sizeof(temp), "Color : %.2f %.2f %.2f\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, NULL, true, FONT_DEFAULT);y += 8;
5837 dpsnprintf(temp, sizeof(temp), "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5838 dpsnprintf(temp, sizeof(temp), "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5839 dpsnprintf(temp, sizeof(temp), "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5840 dpsnprintf(temp, sizeof(temp), "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5841 dpsnprintf(temp, sizeof(temp), "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5842 dpsnprintf(temp, sizeof(temp), "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5843 dpsnprintf(temp, sizeof(temp), "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5844 dpsnprintf(temp, sizeof(temp), "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5845 dpsnprintf(temp, sizeof(temp), "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5846 dpsnprintf(temp, sizeof(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, NULL, true, FONT_DEFAULT);y += 8;
5847 dpsnprintf(temp, sizeof(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, NULL, true, FONT_DEFAULT);y += 8;
5849 dpsnprintf(temp, sizeof(temp), "Render stats\n"); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5850 dpsnprintf(temp, sizeof(temp), "Current color: %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.currentcolor[0], r_shadow_selectedlight->rtlight.currentcolor[1], r_shadow_selectedlight->rtlight.currentcolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5851 dpsnprintf(temp, sizeof(temp), "Shadow size : %ix%ix6\n", r_shadow_selectedlight->rtlight.shadowmapatlassidesize, r_shadow_selectedlight->rtlight.shadowmapatlassidesize); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5852 dpsnprintf(temp, sizeof(temp), "World surfs : %i\n", r_shadow_selectedlight->rtlight.cached_numsurfaces); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5853 dpsnprintf(temp, sizeof(temp), "Shadow ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numshadowentities, r_shadow_selectedlight->rtlight.cached_numshadowentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5854 dpsnprintf(temp, sizeof(temp), "Lit ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numlightentities, r_shadow_selectedlight->rtlight.cached_numlightentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5855 dpsnprintf(temp, sizeof(temp), "BG photons : %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photons); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5856 dpsnprintf(temp, sizeof(temp), "BG radius : %.0f\n", r_shadow_selectedlight->rtlight.bouncegrid_effectiveradius); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5857 dpsnprintf(temp, sizeof(temp), "BG color : %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[0], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[1], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5858 dpsnprintf(temp, sizeof(temp), "BG stats : %i traces %i hits\n", r_shadow_selectedlight->rtlight.bouncegrid_traces, r_shadow_selectedlight->rtlight.bouncegrid_hits); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5861 static void R_Shadow_EditLights_ToggleShadow_f(cmd_state_t *cmd)
5863 if (!r_editlights.integer)
5865 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5868 if (!r_shadow_selectedlight)
5870 Con_Print("No selected light.\n");
5873 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);
5876 static void R_Shadow_EditLights_ToggleCorona_f(cmd_state_t *cmd)
5878 if (!r_editlights.integer)
5880 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5883 if (!r_shadow_selectedlight)
5885 Con_Print("No selected light.\n");
5888 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);
5891 static void R_Shadow_EditLights_Remove_f(cmd_state_t *cmd)
5893 if (!r_editlights.integer)
5895 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5898 if (!r_shadow_selectedlight)
5900 Con_Print("No selected light.\n");
5903 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5904 r_shadow_selectedlight = NULL;
5907 static void R_Shadow_EditLights_Help_f(cmd_state_t *cmd)
5910 "Documentation on r_editlights system:\n"
5912 "r_editlights : enable/disable editing mode\n"
5913 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5914 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5915 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5916 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5917 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5919 "r_editlights_help : this help\n"
5920 "r_editlights_clear : remove all lights\n"
5921 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5922 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5923 "r_editlights_save : save to .rtlights file\n"
5924 "r_editlights_spawn : create a light with default settings\n"
5925 "r_editlights_edit command : edit selected light - more documentation below\n"
5926 "r_editlights_remove : remove selected light\n"
5927 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5928 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5929 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5931 "origin x y z : set light location\n"
5932 "originx x: set x component of light location\n"
5933 "originy y: set y component of light location\n"
5934 "originz z: set z component of light location\n"
5935 "move x y z : adjust light location\n"
5936 "movex x: adjust x component of light location\n"
5937 "movey y: adjust y component of light location\n"
5938 "movez z: adjust z component of light location\n"
5939 "angles x y z : set light angles\n"
5940 "anglesx x: set x component of light angles\n"
5941 "anglesy y: set y component of light angles\n"
5942 "anglesz z: set z component of light angles\n"
5943 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5944 "radius radius : set radius (size) of light\n"
5945 "colorscale grey : multiply color of light (1 does nothing)\n"
5946 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5947 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5948 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5949 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5950 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5951 "cubemap basename : set filter cubemap of light\n"
5952 "shadows 1/0 : turn on/off shadows\n"
5953 "corona n : set corona intensity\n"
5954 "coronasize n : set corona size (0-1)\n"
5955 "ambient n : set ambient intensity (0-1)\n"
5956 "diffuse n : set diffuse intensity (0-1)\n"
5957 "specular n : set specular intensity (0-1)\n"
5958 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5959 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5960 "<nothing> : print light properties to console\n"
5964 static void R_Shadow_EditLights_CopyInfo_f(cmd_state_t *cmd)
5966 if (!r_editlights.integer)
5968 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5971 if (!r_shadow_selectedlight)
5973 Con_Print("No selected light.\n");
5976 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5977 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5978 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5979 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5980 if (*r_shadow_selectedlight->cubemapname)
5981 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5983 r_shadow_bufferlight.cubemapname[0] = 0;
5984 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5985 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5986 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5987 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5988 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5989 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5990 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5993 static void R_Shadow_EditLights_PasteInfo_f(cmd_state_t *cmd)
5995 if (!r_editlights.integer)
5997 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6000 if (!r_shadow_selectedlight)
6002 Con_Print("No selected light.\n");
6005 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);
6008 static void R_Shadow_EditLights_Lock_f(cmd_state_t *cmd)
6010 if (!r_editlights.integer)
6012 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6015 if (r_editlights_lockcursor)
6017 r_editlights_lockcursor = false;
6020 if (!r_shadow_selectedlight)
6022 Con_Print("No selected light to lock on.\n");
6025 r_editlights_lockcursor = true;
6028 static void R_Shadow_EditLights_Init(void)
6030 Cvar_RegisterVariable(&r_editlights);
6031 Cvar_RegisterVariable(&r_editlights_cursordistance);
6032 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6033 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6034 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6035 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6036 Cvar_RegisterVariable(&r_editlights_drawproperties);
6037 Cvar_RegisterVariable(&r_editlights_current_origin);
6038 Cvar_RegisterVariable(&r_editlights_current_angles);
6039 Cvar_RegisterVariable(&r_editlights_current_color);
6040 Cvar_RegisterVariable(&r_editlights_current_radius);
6041 Cvar_RegisterVariable(&r_editlights_current_corona);
6042 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6043 Cvar_RegisterVariable(&r_editlights_current_style);
6044 Cvar_RegisterVariable(&r_editlights_current_shadows);
6045 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6046 Cvar_RegisterVariable(&r_editlights_current_ambient);
6047 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6048 Cvar_RegisterVariable(&r_editlights_current_specular);
6049 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6050 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6051 Cmd_AddCommand(&cmd_client, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6052 Cmd_AddCommand(&cmd_client, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6053 Cmd_AddCommand(&cmd_client, "r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
6054 Cmd_AddCommand(&cmd_client, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6055 Cmd_AddCommand(&cmd_client, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6056 Cmd_AddCommand(&cmd_client, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6057 Cmd_AddCommand(&cmd_client, "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)");
6058 Cmd_AddCommand(&cmd_client, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6059 Cmd_AddCommand(&cmd_client, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6060 Cmd_AddCommand(&cmd_client, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6061 Cmd_AddCommand(&cmd_client, "r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6062 Cmd_AddCommand(&cmd_client, "r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6063 Cmd_AddCommand(&cmd_client, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6064 Cmd_AddCommand(&cmd_client, "r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
6065 Cmd_AddCommand(&cmd_client, "r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6071 =============================================================================
6075 =============================================================================
6078 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6080 int i, numlights, flag, q;
6083 float relativepoint[3];
6088 float sa[3], sx[3], sy[3], sz[3], sd[3];
6091 // use first order spherical harmonics to combine directional lights
6092 for (q = 0; q < 3; q++)
6093 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6095 if (flags & LP_LIGHTMAP)
6097 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6099 float tempambient[3];
6100 for (q = 0; q < 3; q++)
6101 tempambient[q] = color[q] = relativepoint[q] = 0;
6102 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6103 // calculate a weighted average light direction as well
6104 intensity = VectorLength(color);
6105 for (q = 0; q < 3; q++)
6107 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6108 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6109 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6110 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6111 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6116 // unlit map - fullbright but scaled by lightmapintensity
6117 for (q = 0; q < 3; q++)
6118 sa[q] += lightmapintensity;
6122 if (flags & LP_RTWORLD)
6124 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6125 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6126 for (i = 0; i < numlights; i++)
6128 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6131 light = &dlight->rtlight;
6132 if (!(light->flags & flag))
6135 lightradius2 = light->radius * light->radius;
6136 VectorSubtract(light->shadoworigin, p, relativepoint);
6137 dist2 = VectorLength2(relativepoint);
6138 if (dist2 >= lightradius2)
6140 dist = sqrt(dist2) / light->radius;
6141 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6142 if (intensity <= 0.0f)
6144 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6146 for (q = 0; q < 3; q++)
6147 color[q] = light->currentcolor[q] * intensity;
6148 intensity = VectorLength(color);
6149 VectorNormalize(relativepoint);
6150 for (q = 0; q < 3; q++)
6152 sa[q] += 0.5f * color[q];
6153 sx[q] += relativepoint[0] * color[q];
6154 sy[q] += relativepoint[1] * color[q];
6155 sz[q] += relativepoint[2] * color[q];
6156 sd[q] += intensity * relativepoint[q];
6159 // FIXME: sample bouncegrid too!
6162 if (flags & LP_DYNLIGHT)
6165 for (i = 0;i < r_refdef.scene.numlights;i++)
6167 light = r_refdef.scene.lights[i];
6169 lightradius2 = light->radius * light->radius;
6170 VectorSubtract(light->shadoworigin, p, relativepoint);
6171 dist2 = VectorLength2(relativepoint);
6172 if (dist2 >= lightradius2)
6174 dist = sqrt(dist2) / light->radius;
6175 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6176 if (intensity <= 0.0f)
6178 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6180 for (q = 0; q < 3; q++)
6181 color[q] = light->currentcolor[q] * intensity;
6182 intensity = VectorLength(color);
6183 VectorNormalize(relativepoint);
6184 for (q = 0; q < 3; q++)
6186 sa[q] += 0.5f * color[q];
6187 sx[q] += relativepoint[0] * color[q];
6188 sy[q] += relativepoint[1] * color[q];
6189 sz[q] += relativepoint[2] * color[q];
6190 sd[q] += intensity * relativepoint[q];
6195 // calculate the weighted-average light direction (bentnormal)
6196 for (q = 0; q < 3; q++)
6197 lightdir[q] = sd[q];
6198 VectorNormalize(lightdir);
6199 for (q = 0; q < 3; q++)
6201 // extract the diffuse color along the chosen direction and scale it
6202 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6203 // subtract some of diffuse from ambient
6204 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;