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_SHADOWMAP2D
29 r_shadow_shadowmode_t;
31 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
32 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
33 int r_shadow_scenemaxlights;
34 int r_shadow_scenenumlights;
35 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
36 qboolean r_shadow_usingshadowmap2d;
37 qboolean r_shadow_usingshadowmaportho;
38 int r_shadow_shadowmapside;
39 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
40 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
41 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
42 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
44 int r_shadow_drawbuffer;
45 int r_shadow_readbuffer;
47 int r_shadow_cullface_front, r_shadow_cullface_back;
48 GLuint r_shadow_fbo2d;
49 r_shadow_shadowmode_t r_shadow_shadowmode;
50 int r_shadow_shadowmapfilterquality;
51 int r_shadow_shadowmapdepthbits;
52 int r_shadow_shadowmapmaxsize;
53 int r_shadow_shadowmaptexturesize;
54 qboolean r_shadow_shadowmapvsdct;
55 qboolean r_shadow_shadowmapsampler;
56 qboolean r_shadow_shadowmapshadowsampler;
57 int r_shadow_shadowmappcf;
58 int r_shadow_shadowmapborder;
59 matrix4x4_t r_shadow_shadowmapmatrix;
60 int r_shadow_lightscissor[4];
61 qboolean r_shadow_usingdeferredprepass;
62 qboolean r_shadow_shadowmapdepthtexture;
63 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
64 int r_shadow_shadowmapatlas_modelshadows_x;
65 int r_shadow_shadowmapatlas_modelshadows_y;
66 int r_shadow_shadowmapatlas_modelshadows_size;
67 int maxshadowtriangles;
70 int maxshadowvertices;
71 float *shadowvertex3f;
81 unsigned char *shadowsides;
89 int r_shadow_buffer_numleafpvsbytes;
90 unsigned char *r_shadow_buffer_visitingleafpvs;
91 unsigned char *r_shadow_buffer_leafpvs;
92 int *r_shadow_buffer_leaflist;
94 int r_shadow_buffer_numsurfacepvsbytes;
95 unsigned char *r_shadow_buffer_surfacepvs;
96 int *r_shadow_buffer_surfacelist;
97 unsigned char *r_shadow_buffer_surfacesides;
99 int r_shadow_buffer_numshadowtrispvsbytes;
100 unsigned char *r_shadow_buffer_shadowtrispvs;
101 int r_shadow_buffer_numlighttrispvsbytes;
102 unsigned char *r_shadow_buffer_lighttrispvs;
104 rtexturepool_t *r_shadow_texturepool;
105 rtexture_t *r_shadow_attenuationgradienttexture;
106 skinframe_t *r_shadow_lightcorona;
107 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
108 rtexture_t *r_shadow_shadowmap2ddepthtexture;
109 rtexture_t *r_shadow_shadowmapvsdcttexture;
111 GLuint r_shadow_prepassgeometryfbo;
112 GLuint r_shadow_prepasslightingdiffusespecularfbo;
113 GLuint r_shadow_prepasslightingdiffusefbo;
114 int r_shadow_prepass_width;
115 int r_shadow_prepass_height;
116 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
117 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
118 rtexture_t *r_shadow_prepasslightingdiffusetexture;
119 rtexture_t *r_shadow_prepasslightingspeculartexture;
121 int r_shadow_viewfbo;
122 rtexture_t *r_shadow_viewdepthtexture;
123 rtexture_t *r_shadow_viewcolortexture;
126 int r_shadow_viewwidth;
127 int r_shadow_viewheight;
129 // lights are reloaded when this changes
130 char r_shadow_mapname[MAX_QPATH];
132 // buffer for doing corona fading
133 unsigned int r_shadow_occlusion_buf = 0;
135 // used only for light filters (cubemaps)
136 rtexturepool_t *r_shadow_filters_texturepool;
138 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"};
139 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"};
140 cvar_t r_shadow_debuglight = {CVAR_CLIENT, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
141 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"};
142 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)"};
143 cvar_t r_shadow_usenormalmap = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
144 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)"};
145 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"};
146 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"};
147 cvar_t r_shadow_glossexponent = {CVAR_CLIENT, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
148 cvar_t r_shadow_gloss2exponent = {CVAR_CLIENT, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
149 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)"};
150 cvar_t r_shadow_lightattenuationdividebias = {CVAR_CLIENT, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
151 cvar_t r_shadow_lightattenuationlinearscale = {CVAR_CLIENT, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
152 cvar_t r_shadow_lightintensityscale = {CVAR_CLIENT, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
153 cvar_t r_shadow_lightradiusscale = {CVAR_CLIENT, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
154 cvar_t r_shadow_projectdistance = {CVAR_CLIENT, "r_shadow_projectdistance", "0", "how far to cast shadows"};
155 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)"};
156 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"};
157 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
158 cvar_t r_shadow_realtime_dlight_svbspculling = {CVAR_CLIENT, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
159 cvar_t r_shadow_realtime_dlight_portalculling = {CVAR_CLIENT, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
160 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)"};
161 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)"};
162 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"};
163 cvar_t r_shadow_realtime_world_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
164 cvar_t r_shadow_realtime_world_compile = {CVAR_CLIENT, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
165 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"};
166 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)"};
167 cvar_t r_shadow_realtime_world_compileportalculling = {CVAR_CLIENT, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
168 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)"};
169 cvar_t r_shadow_shadowmapping = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
170 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)"};
171 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
172 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
173 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
174 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"};
175 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..."};
176 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"};
177 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"};
178 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
179 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
180 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
181 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
182 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)"};
183 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
184 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
185 cvar_t r_shadow_sortsurfaces = {CVAR_CLIENT, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
186 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"};
187 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"};
188 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
189 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)"};
190 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"};
191 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"};
192 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)"};
193 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)"};
194 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"};
195 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)"};
196 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"};
197 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"};
198 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)"};
199 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"};
200 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"};
201 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
202 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)"};
203 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)"};
204 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"};
205 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)"};
206 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
207 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"};
208 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"};
209 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"};
210 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"};
211 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"};
212 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)"};
213 cvar_t r_shadow_bouncegrid_intensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
214 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"};
215 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)"};
216 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"};
217 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
218 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"};
219 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)"};
220 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)"};
221 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"};
222 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"};
223 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"};
224 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"};
225 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
226 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)"};
227 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"};
228 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)"};
229 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"};
230 cvar_t r_coronas = {CVAR_CLIENT | CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
231 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"};
232 cvar_t r_coronas_occlusionquery = {CVAR_CLIENT | CVAR_SAVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"};
233 cvar_t gl_flashblend = {CVAR_CLIENT | CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
234 cvar_t r_editlights = {CVAR_CLIENT, "r_editlights", "0", "enables .rtlights file editing mode"};
235 cvar_t r_editlights_cursordistance = {CVAR_CLIENT, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
236 cvar_t r_editlights_cursorpushback = {CVAR_CLIENT, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
237 cvar_t r_editlights_cursorpushoff = {CVAR_CLIENT, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
238 cvar_t r_editlights_cursorgrid = {CVAR_CLIENT, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
239 cvar_t r_editlights_quakelightsizescale = {CVAR_CLIENT | CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
240 cvar_t r_editlights_drawproperties = {CVAR_CLIENT, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
241 cvar_t r_editlights_current_origin = {CVAR_CLIENT, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
242 cvar_t r_editlights_current_angles = {CVAR_CLIENT, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
243 cvar_t r_editlights_current_color = {CVAR_CLIENT, "r_editlights_current_color", "1 1 1", "color of selected light"};
244 cvar_t r_editlights_current_radius = {CVAR_CLIENT, "r_editlights_current_radius", "0", "radius of selected light"};
245 cvar_t r_editlights_current_corona = {CVAR_CLIENT, "r_editlights_current_corona", "0", "corona intensity of selected light"};
246 cvar_t r_editlights_current_coronasize = {CVAR_CLIENT, "r_editlights_current_coronasize", "0", "corona size of selected light"};
247 cvar_t r_editlights_current_style = {CVAR_CLIENT, "r_editlights_current_style", "0", "style of selected light"};
248 cvar_t r_editlights_current_shadows = {CVAR_CLIENT, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
249 cvar_t r_editlights_current_cubemap = {CVAR_CLIENT, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
250 cvar_t r_editlights_current_ambient = {CVAR_CLIENT, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
251 cvar_t r_editlights_current_diffuse = {CVAR_CLIENT, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
252 cvar_t r_editlights_current_specular = {CVAR_CLIENT, "r_editlights_current_specular", "1", "specular intensity of selected light"};
253 cvar_t r_editlights_current_normalmode = {CVAR_CLIENT, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
254 cvar_t r_editlights_current_realtimemode = {CVAR_CLIENT, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
256 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
258 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
259 #define ATTENTABLESIZE 256
260 // 1D gradient, 2D circle and 3D sphere attenuation textures
261 #define ATTEN1DSIZE 32
262 #define ATTEN2DSIZE 64
263 #define ATTEN3DSIZE 32
265 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
266 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
267 static float r_shadow_attentable[ATTENTABLESIZE+1];
269 rtlight_t *r_shadow_compilingrtlight;
270 static memexpandablearray_t r_shadow_worldlightsarray;
271 dlight_t *r_shadow_selectedlight;
272 dlight_t r_shadow_bufferlight;
273 vec3_t r_editlights_cursorlocation;
274 qboolean r_editlights_lockcursor;
276 extern int con_vislines;
278 void R_Shadow_UncompileWorldLights(void);
279 void R_Shadow_ClearWorldLights(void);
280 void R_Shadow_SaveWorldLights(void);
281 void R_Shadow_LoadWorldLights(void);
282 void R_Shadow_LoadLightsFile(void);
283 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
284 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd);
285 static void R_Shadow_MakeTextures(void);
287 #define EDLIGHTSPRSIZE 8
288 skinframe_t *r_editlights_sprcursor;
289 skinframe_t *r_editlights_sprlight;
290 skinframe_t *r_editlights_sprnoshadowlight;
291 skinframe_t *r_editlights_sprcubemaplight;
292 skinframe_t *r_editlights_sprcubemapnoshadowlight;
293 skinframe_t *r_editlights_sprselection;
295 static void R_Shadow_DrawModelShadowMaps(void);
296 static void R_Shadow_MakeShadowMap(int texturesize);
297 static void R_Shadow_MakeVSDCT(void);
298 static void R_Shadow_SetShadowMode(void)
300 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
301 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
302 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
303 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
304 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
305 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
306 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
307 r_shadow_shadowmapsampler = false;
308 r_shadow_shadowmappcf = 0;
309 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
310 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
311 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
312 if (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)
314 switch(vid.renderpath)
316 case RENDERPATH_GL32:
317 if(r_shadow_shadowmapfilterquality < 0)
319 if (!r_fb.usedepthtextures)
320 r_shadow_shadowmappcf = 1;
321 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
323 r_shadow_shadowmapsampler = true;
324 r_shadow_shadowmappcf = 1;
326 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
327 r_shadow_shadowmappcf = 1;
328 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
329 r_shadow_shadowmappcf = 1;
331 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
335 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
336 switch (r_shadow_shadowmapfilterquality)
341 r_shadow_shadowmappcf = 1;
344 r_shadow_shadowmappcf = 1;
347 r_shadow_shadowmappcf = 2;
351 if (!r_fb.usedepthtextures)
352 r_shadow_shadowmapsampler = false;
353 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
355 case RENDERPATH_GLES2:
360 if(R_CompileShader_CheckStaticParms())
361 R_GLSL_Restart_f(&cmd_client);
364 qboolean R_Shadow_ShadowMappingEnabled(void)
366 switch (r_shadow_shadowmode)
368 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
375 static void R_Shadow_FreeShadowMaps(void)
377 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
379 R_Shadow_SetShadowMode();
381 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
385 if (r_shadow_shadowmap2ddepthtexture)
386 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
387 r_shadow_shadowmap2ddepthtexture = NULL;
389 if (r_shadow_shadowmap2ddepthbuffer)
390 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
391 r_shadow_shadowmap2ddepthbuffer = NULL;
393 if (r_shadow_shadowmapvsdcttexture)
394 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
395 r_shadow_shadowmapvsdcttexture = NULL;
398 static void r_shadow_start(void)
400 // allocate vertex processing arrays
401 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
402 r_shadow_attenuationgradienttexture = NULL;
403 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
404 r_shadow_shadowmap2ddepthtexture = NULL;
405 r_shadow_shadowmap2ddepthbuffer = NULL;
406 r_shadow_shadowmapvsdcttexture = NULL;
407 r_shadow_shadowmapmaxsize = 0;
408 r_shadow_shadowmaptexturesize = 0;
409 r_shadow_shadowmapfilterquality = -1;
410 r_shadow_shadowmapdepthbits = 0;
411 r_shadow_shadowmapvsdct = false;
412 r_shadow_shadowmapsampler = false;
413 r_shadow_shadowmappcf = 0;
416 R_Shadow_FreeShadowMaps();
418 r_shadow_texturepool = NULL;
419 r_shadow_filters_texturepool = NULL;
420 R_Shadow_MakeTextures();
421 r_shadow_scenemaxlights = 0;
422 r_shadow_scenenumlights = 0;
423 r_shadow_scenelightlist = NULL;
424 maxshadowtriangles = 0;
425 shadowelements = NULL;
426 maxshadowvertices = 0;
427 shadowvertex3f = NULL;
435 shadowmarklist = NULL;
440 shadowsideslist = NULL;
441 r_shadow_buffer_numleafpvsbytes = 0;
442 r_shadow_buffer_visitingleafpvs = NULL;
443 r_shadow_buffer_leafpvs = NULL;
444 r_shadow_buffer_leaflist = NULL;
445 r_shadow_buffer_numsurfacepvsbytes = 0;
446 r_shadow_buffer_surfacepvs = NULL;
447 r_shadow_buffer_surfacelist = NULL;
448 r_shadow_buffer_surfacesides = NULL;
449 r_shadow_buffer_numshadowtrispvsbytes = 0;
450 r_shadow_buffer_shadowtrispvs = NULL;
451 r_shadow_buffer_numlighttrispvsbytes = 0;
452 r_shadow_buffer_lighttrispvs = NULL;
454 r_shadow_usingdeferredprepass = false;
455 r_shadow_prepass_width = r_shadow_prepass_height = 0;
457 // determine renderpath specific capabilities, we don't need to figure
458 // these out per frame...
459 switch(vid.renderpath)
461 case RENDERPATH_GL32:
462 r_shadow_bouncegrid_state.allowdirectionalshading = true;
463 r_shadow_bouncegrid_state.capable = true;
465 case RENDERPATH_GLES2:
466 // for performance reasons, do not use directional shading on GLES devices
467 r_shadow_bouncegrid_state.capable = true;
472 static void R_Shadow_FreeDeferred(void);
473 static void r_shadow_shutdown(void)
476 R_Shadow_UncompileWorldLights();
478 R_Shadow_FreeShadowMaps();
480 r_shadow_usingdeferredprepass = false;
481 if (r_shadow_prepass_width)
482 R_Shadow_FreeDeferred();
483 r_shadow_prepass_width = r_shadow_prepass_height = 0;
486 r_shadow_scenemaxlights = 0;
487 r_shadow_scenenumlights = 0;
488 if (r_shadow_scenelightlist)
489 Mem_Free(r_shadow_scenelightlist);
490 r_shadow_scenelightlist = NULL;
491 r_shadow_bouncegrid_state.highpixels = NULL;
492 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
493 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
494 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
495 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
496 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
497 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
498 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
499 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
500 r_shadow_attenuationgradienttexture = NULL;
501 R_FreeTexturePool(&r_shadow_texturepool);
502 R_FreeTexturePool(&r_shadow_filters_texturepool);
503 maxshadowtriangles = 0;
505 Mem_Free(shadowelements);
506 shadowelements = NULL;
508 Mem_Free(shadowvertex3f);
509 shadowvertex3f = NULL;
512 Mem_Free(vertexupdate);
515 Mem_Free(vertexremap);
521 Mem_Free(shadowmark);
524 Mem_Free(shadowmarklist);
525 shadowmarklist = NULL;
530 Mem_Free(shadowsides);
533 Mem_Free(shadowsideslist);
534 shadowsideslist = NULL;
535 r_shadow_buffer_numleafpvsbytes = 0;
536 if (r_shadow_buffer_visitingleafpvs)
537 Mem_Free(r_shadow_buffer_visitingleafpvs);
538 r_shadow_buffer_visitingleafpvs = NULL;
539 if (r_shadow_buffer_leafpvs)
540 Mem_Free(r_shadow_buffer_leafpvs);
541 r_shadow_buffer_leafpvs = NULL;
542 if (r_shadow_buffer_leaflist)
543 Mem_Free(r_shadow_buffer_leaflist);
544 r_shadow_buffer_leaflist = NULL;
545 r_shadow_buffer_numsurfacepvsbytes = 0;
546 if (r_shadow_buffer_surfacepvs)
547 Mem_Free(r_shadow_buffer_surfacepvs);
548 r_shadow_buffer_surfacepvs = NULL;
549 if (r_shadow_buffer_surfacelist)
550 Mem_Free(r_shadow_buffer_surfacelist);
551 r_shadow_buffer_surfacelist = NULL;
552 if (r_shadow_buffer_surfacesides)
553 Mem_Free(r_shadow_buffer_surfacesides);
554 r_shadow_buffer_surfacesides = NULL;
555 r_shadow_buffer_numshadowtrispvsbytes = 0;
556 if (r_shadow_buffer_shadowtrispvs)
557 Mem_Free(r_shadow_buffer_shadowtrispvs);
558 r_shadow_buffer_numlighttrispvsbytes = 0;
559 if (r_shadow_buffer_lighttrispvs)
560 Mem_Free(r_shadow_buffer_lighttrispvs);
563 static void r_shadow_newmap(void)
565 r_shadow_bouncegrid_state.highpixels = NULL;
566 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
567 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
568 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
569 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
570 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
571 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
572 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
574 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
575 if (r_shadow_lightcorona) { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
576 if (r_editlights_sprcursor) { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
577 if (r_editlights_sprlight) { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
578 if (r_editlights_sprnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
579 if (r_editlights_sprcubemaplight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
580 if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
581 if (r_editlights_sprselection) { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
582 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
583 R_Shadow_EditLights_Reload_f(&cmd_client);
586 void R_Shadow_Init(void)
588 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
589 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
590 Cvar_RegisterVariable(&r_shadow_usebihculling);
591 Cvar_RegisterVariable(&r_shadow_usenormalmap);
592 Cvar_RegisterVariable(&r_shadow_debuglight);
593 Cvar_RegisterVariable(&r_shadow_deferred);
594 Cvar_RegisterVariable(&r_shadow_gloss);
595 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
596 Cvar_RegisterVariable(&r_shadow_glossintensity);
597 Cvar_RegisterVariable(&r_shadow_glossexponent);
598 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
599 Cvar_RegisterVariable(&r_shadow_glossexact);
600 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
601 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
602 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
603 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
604 Cvar_RegisterVariable(&r_shadow_projectdistance);
605 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
606 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
607 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
608 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
609 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
610 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
611 Cvar_RegisterVariable(&r_shadow_realtime_world);
612 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
613 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
614 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
615 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
616 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
617 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
618 Cvar_RegisterVariable(&r_shadow_scissor);
619 Cvar_RegisterVariable(&r_shadow_shadowmapping);
620 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
621 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
622 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
623 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
624 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
625 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
626 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
627 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
628 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
629 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
630 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
631 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
632 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
633 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
634 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
635 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
636 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
637 Cvar_RegisterVariable(&r_shadow_culllights_trace);
638 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
639 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
640 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
641 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
642 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
643 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
644 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
645 Cvar_RegisterVariable(&r_shadow_bouncegrid);
646 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
647 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
648 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
649 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
650 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
651 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
652 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
653 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
654 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
655 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
656 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
657 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
658 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
659 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
660 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
661 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
662 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
663 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
664 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
665 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
666 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
667 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
668 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
669 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
670 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
671 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
672 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
673 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
674 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
675 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
676 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
677 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
678 Cvar_RegisterVariable(&r_shadow_bouncegrid_subsamples);
679 Cvar_RegisterVariable(&r_shadow_bouncegrid_threaded);
680 Cvar_RegisterVariable(&r_coronas);
681 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
682 Cvar_RegisterVariable(&r_coronas_occlusionquery);
683 Cvar_RegisterVariable(&gl_flashblend);
684 R_Shadow_EditLights_Init();
685 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
686 r_shadow_scenemaxlights = 0;
687 r_shadow_scenenumlights = 0;
688 r_shadow_scenelightlist = NULL;
689 maxshadowtriangles = 0;
690 shadowelements = NULL;
691 maxshadowvertices = 0;
692 shadowvertex3f = NULL;
700 shadowmarklist = NULL;
705 shadowsideslist = NULL;
706 r_shadow_buffer_numleafpvsbytes = 0;
707 r_shadow_buffer_visitingleafpvs = NULL;
708 r_shadow_buffer_leafpvs = NULL;
709 r_shadow_buffer_leaflist = NULL;
710 r_shadow_buffer_numsurfacepvsbytes = 0;
711 r_shadow_buffer_surfacepvs = NULL;
712 r_shadow_buffer_surfacelist = NULL;
713 r_shadow_buffer_surfacesides = NULL;
714 r_shadow_buffer_shadowtrispvs = NULL;
715 r_shadow_buffer_lighttrispvs = NULL;
716 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
719 matrix4x4_t matrix_attenuationxyz =
722 {0.5, 0.0, 0.0, 0.5},
723 {0.0, 0.5, 0.0, 0.5},
724 {0.0, 0.0, 0.5, 0.5},
729 matrix4x4_t matrix_attenuationz =
732 {0.0, 0.0, 0.5, 0.5},
733 {0.0, 0.0, 0.0, 0.5},
734 {0.0, 0.0, 0.0, 0.5},
739 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
741 numvertices = ((numvertices + 255) & ~255) * vertscale;
742 numtriangles = ((numtriangles + 255) & ~255) * triscale;
743 // make sure shadowelements is big enough for this volume
744 if (maxshadowtriangles < numtriangles)
746 maxshadowtriangles = numtriangles;
748 Mem_Free(shadowelements);
749 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
751 // make sure shadowvertex3f is big enough for this volume
752 if (maxshadowvertices < numvertices)
754 maxshadowvertices = numvertices;
756 Mem_Free(shadowvertex3f);
757 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
761 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
763 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
764 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
765 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
766 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
767 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
769 if (r_shadow_buffer_visitingleafpvs)
770 Mem_Free(r_shadow_buffer_visitingleafpvs);
771 if (r_shadow_buffer_leafpvs)
772 Mem_Free(r_shadow_buffer_leafpvs);
773 if (r_shadow_buffer_leaflist)
774 Mem_Free(r_shadow_buffer_leaflist);
775 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
776 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
777 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
778 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
780 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
782 if (r_shadow_buffer_surfacepvs)
783 Mem_Free(r_shadow_buffer_surfacepvs);
784 if (r_shadow_buffer_surfacelist)
785 Mem_Free(r_shadow_buffer_surfacelist);
786 if (r_shadow_buffer_surfacesides)
787 Mem_Free(r_shadow_buffer_surfacesides);
788 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
789 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
790 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
791 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
793 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
795 if (r_shadow_buffer_shadowtrispvs)
796 Mem_Free(r_shadow_buffer_shadowtrispvs);
797 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
798 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
800 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
802 if (r_shadow_buffer_lighttrispvs)
803 Mem_Free(r_shadow_buffer_lighttrispvs);
804 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
805 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
809 void R_Shadow_PrepareShadowMark(int numtris)
811 // make sure shadowmark is big enough for this volume
812 if (maxshadowmark < numtris)
814 maxshadowmark = numtris;
816 Mem_Free(shadowmark);
818 Mem_Free(shadowmarklist);
819 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
820 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
824 // if shadowmarkcount wrapped we clear the array and adjust accordingly
825 if (shadowmarkcount == 0)
828 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
833 void R_Shadow_PrepareShadowSides(int numtris)
835 if (maxshadowsides < numtris)
837 maxshadowsides = numtris;
839 Mem_Free(shadowsides);
841 Mem_Free(shadowsideslist);
842 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
843 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
848 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
850 // p1, p2, p3 are in the cubemap's local coordinate system
851 // bias = border/(size - border)
854 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
855 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
856 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
857 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
859 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
860 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
861 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
862 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
864 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
865 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
866 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
868 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
869 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
870 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
871 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
873 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
874 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
875 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
876 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
878 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
879 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
880 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
882 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
883 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
884 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
885 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
887 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
888 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
889 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
890 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
892 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
893 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
894 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
899 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
901 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
902 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
905 VectorSubtract(maxs, mins, radius);
906 VectorScale(radius, 0.5f, radius);
907 VectorAdd(mins, radius, center);
908 Matrix4x4_Transform(worldtolight, center, lightcenter);
909 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
910 VectorSubtract(lightcenter, lightradius, pmin);
911 VectorAdd(lightcenter, lightradius, pmax);
913 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
914 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
915 if(ap1 > bias*an1 && ap2 > bias*an2)
917 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
918 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
919 if(an1 > bias*ap1 && an2 > bias*ap2)
921 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
922 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
924 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
925 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
926 if(ap1 > bias*an1 && ap2 > bias*an2)
928 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
929 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
930 if(an1 > bias*ap1 && an2 > bias*ap2)
932 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
933 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
935 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
936 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
937 if(ap1 > bias*an1 && ap2 > bias*an2)
939 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
940 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
941 if(an1 > bias*ap1 && an2 > bias*ap2)
943 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
944 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
949 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
951 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
953 // p is in the cubemap's local coordinate system
954 // bias = border/(size - border)
955 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
956 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
957 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
959 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
960 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
961 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
962 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
963 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
964 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
968 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
972 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
973 float scale = (size - 2*border)/size, len;
974 float bias = border / (float)(size - border), dp, dn, ap, an;
975 // check if cone enclosing side would cross frustum plane
976 scale = 2 / (scale*scale + 2);
977 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
978 for (i = 0;i < 5;i++)
980 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
982 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
983 len = scale*VectorLength2(n);
984 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
985 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
986 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
988 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
990 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
991 len = scale*VectorLength2(n);
992 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
993 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
994 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
996 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
997 // check if frustum corners/origin cross plane sides
999 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1000 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1001 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1002 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1003 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1004 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1005 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1006 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1007 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1008 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1009 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1010 for (i = 0;i < 4;i++)
1012 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1013 VectorSubtract(n, p, n);
1014 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1015 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1016 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1017 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1018 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1019 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1020 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1021 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1022 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1025 // finite version, assumes corners are a finite distance from origin dependent on far plane
1026 for (i = 0;i < 5;i++)
1028 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1029 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1030 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1031 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1032 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1033 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1034 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1035 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1036 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1037 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1040 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1043 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)
1051 int mask, surfacemask = 0;
1052 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1054 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1055 tend = firsttriangle + numtris;
1056 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1058 // surface box entirely inside light box, no box cull
1059 if (projectdirection)
1061 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1063 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1064 TriangleNormal(v[0], v[1], v[2], normal);
1065 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1067 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1068 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1069 surfacemask |= mask;
1072 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;
1073 shadowsides[numshadowsides] = mask;
1074 shadowsideslist[numshadowsides++] = t;
1081 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1083 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1084 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1086 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1087 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1088 surfacemask |= mask;
1091 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;
1092 shadowsides[numshadowsides] = mask;
1093 shadowsideslist[numshadowsides++] = t;
1101 // surface box not entirely inside light box, cull each triangle
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)
1109 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1111 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1112 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1113 surfacemask |= mask;
1116 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;
1117 shadowsides[numshadowsides] = mask;
1118 shadowsideslist[numshadowsides++] = t;
1125 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1127 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1128 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1129 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1131 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1132 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1133 surfacemask |= mask;
1136 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;
1137 shadowsides[numshadowsides] = mask;
1138 shadowsideslist[numshadowsides++] = t;
1147 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)
1149 int i, j, outtriangles = 0;
1150 int *outelement3i[6];
1151 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1153 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1154 // make sure shadowelements is big enough for this mesh
1155 if (maxshadowtriangles < outtriangles)
1156 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1158 // compute the offset and size of the separate index lists for each cubemap side
1160 for (i = 0;i < 6;i++)
1162 outelement3i[i] = shadowelements + outtriangles * 3;
1163 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1164 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1165 outtriangles += sidetotals[i];
1168 // gather up the (sparse) triangles into separate index lists for each cubemap side
1169 for (i = 0;i < numsidetris;i++)
1171 const int *element = elements + sidetris[i] * 3;
1172 for (j = 0;j < 6;j++)
1174 if (sides[i] & (1 << j))
1176 outelement3i[j][0] = element[0];
1177 outelement3i[j][1] = element[1];
1178 outelement3i[j][2] = element[2];
1179 outelement3i[j] += 3;
1184 Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1187 static void R_Shadow_MakeTextures_MakeCorona(void)
1191 unsigned char pixels[32][32][4];
1192 for (y = 0;y < 32;y++)
1194 dy = (y - 15.5f) * (1.0f / 16.0f);
1195 for (x = 0;x < 32;x++)
1197 dx = (x - 15.5f) * (1.0f / 16.0f);
1198 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1199 a = bound(0, a, 255);
1200 pixels[y][x][0] = a;
1201 pixels[y][x][1] = a;
1202 pixels[y][x][2] = a;
1203 pixels[y][x][3] = 255;
1206 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1209 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1211 float dist = sqrt(x*x+y*y+z*z);
1212 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1213 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1214 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1217 static void R_Shadow_MakeTextures(void)
1220 float intensity, dist;
1222 R_Shadow_FreeShadowMaps();
1223 R_FreeTexturePool(&r_shadow_texturepool);
1224 r_shadow_texturepool = R_AllocTexturePool();
1225 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1226 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1227 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1228 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1229 for (x = 0;x <= ATTENTABLESIZE;x++)
1231 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1232 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1233 r_shadow_attentable[x] = bound(0, intensity, 1);
1235 // 1D gradient texture
1236 for (x = 0;x < ATTEN1DSIZE;x++)
1237 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1238 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1241 R_Shadow_MakeTextures_MakeCorona();
1243 // Editor light sprites
1244 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1261 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1262 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1279 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1280 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1297 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1298 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1315 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1316 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1333 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1334 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1351 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1354 void R_Shadow_RenderMode_Begin(void)
1361 if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1362 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1363 R_Shadow_MakeTextures();
1366 R_Mesh_ResetTextureState();
1367 GL_BlendFunc(GL_ONE, GL_ZERO);
1368 GL_DepthRange(0, 1);
1369 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1371 GL_DepthMask(false);
1372 GL_Color(0, 0, 0, 1);
1373 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1375 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1376 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1380 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1381 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1382 r_shadow_drawbuffer = drawbuffer;
1383 r_shadow_readbuffer = readbuffer;
1385 r_shadow_cullface_front = r_refdef.view.cullface_front;
1386 r_shadow_cullface_back = r_refdef.view.cullface_back;
1389 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1391 rsurface.rtlight = rtlight;
1394 void R_Shadow_RenderMode_Reset(void)
1396 R_Mesh_ResetTextureState();
1397 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1398 R_SetViewport(&r_refdef.view.viewport);
1399 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1400 GL_DepthRange(0, 1);
1402 GL_DepthMask(false);
1403 GL_DepthFunc(GL_LEQUAL);
1404 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1405 r_refdef.view.cullface_front = r_shadow_cullface_front;
1406 r_refdef.view.cullface_back = r_shadow_cullface_back;
1407 GL_CullFace(r_refdef.view.cullface_back);
1408 GL_Color(1, 1, 1, 1);
1409 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1410 GL_BlendFunc(GL_ONE, GL_ZERO);
1411 R_SetupShader_Generic_NoTexture(false, false);
1412 r_shadow_usingshadowmap2d = false;
1415 void R_Shadow_ClearStencil(void)
1417 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1418 r_refdef.stats[r_stat_lights_clears]++;
1421 static void R_Shadow_MakeVSDCT(void)
1423 // maps to a 2x3 texture rectangle with normalized coordinates
1428 // stores abs(dir.xy), offset.xy/2.5
1429 unsigned char data[4*6] =
1431 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1432 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1433 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1434 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1435 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1436 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1438 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1441 static void R_Shadow_MakeShadowMap(int texturesize)
1443 switch (r_shadow_shadowmode)
1445 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1446 if (r_shadow_shadowmap2ddepthtexture) return;
1447 if (r_fb.usedepthtextures)
1449 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);
1450 r_shadow_shadowmap2ddepthbuffer = NULL;
1451 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1455 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1456 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1457 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1465 void R_Shadow_ClearShadowMapTexture(void)
1467 r_viewport_t viewport;
1468 float clearcolor[4];
1470 // if they don't exist, create our textures now
1471 if (!r_shadow_shadowmap2ddepthtexture)
1472 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1473 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1474 R_Shadow_MakeVSDCT();
1476 // we're setting up to render shadowmaps, so change rendermode
1477 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1479 R_Mesh_ResetTextureState();
1480 R_Shadow_RenderMode_Reset();
1481 if (r_shadow_shadowmap2ddepthbuffer)
1482 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1484 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1485 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1486 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1490 // we have to set a viewport to clear anything in some renderpaths (D3D)
1491 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1492 R_SetViewport(&viewport);
1493 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1494 if (r_shadow_shadowmap2ddepthbuffer)
1495 GL_ColorMask(1, 1, 1, 1);
1497 GL_ColorMask(0, 0, 0, 0);
1498 switch (vid.renderpath)
1500 case RENDERPATH_GL32:
1501 case RENDERPATH_GLES2:
1502 GL_CullFace(r_refdef.view.cullface_back);
1505 Vector4Set(clearcolor, 1, 1, 1, 1);
1506 if (r_shadow_shadowmap2ddepthbuffer)
1507 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1509 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1512 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1514 int size = rsurface.rtlight->shadowmapatlassidesize;
1515 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1516 float farclip = 1.0f;
1517 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1518 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1519 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1520 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1521 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1522 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1523 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1524 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1525 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1526 if (r_shadow_shadowmap2ddepthbuffer)
1528 // completely different meaning than in depthtexture approach
1529 r_shadow_lightshadowmap_parameters[1] = 0;
1530 r_shadow_lightshadowmap_parameters[3] = -bias;
1534 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1536 float nearclip, farclip, bias;
1537 r_viewport_t viewport;
1540 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1542 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1544 R_Mesh_ResetTextureState();
1545 R_Shadow_RenderMode_Reset();
1546 if (r_shadow_shadowmap2ddepthbuffer)
1547 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1549 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1550 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1551 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1556 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1558 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1560 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1561 R_SetViewport(&viewport);
1562 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1563 flipped = (side & 1) ^ (side >> 2);
1564 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1565 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1567 if (r_shadow_shadowmap2ddepthbuffer)
1568 GL_ColorMask(1,1,1,1);
1570 GL_ColorMask(0,0,0,0);
1571 switch(vid.renderpath)
1573 case RENDERPATH_GL32:
1574 case RENDERPATH_GLES2:
1575 GL_CullFace(r_refdef.view.cullface_back);
1579 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1580 r_shadow_shadowmapside = side;
1583 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1585 R_Mesh_ResetTextureState();
1588 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1589 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1590 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1591 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1594 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1595 R_Shadow_RenderMode_Reset();
1596 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1598 GL_DepthFunc(GL_EQUAL);
1599 // do global setup needed for the chosen lighting mode
1600 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1601 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1602 r_shadow_usingshadowmap2d = shadowmapping;
1603 r_shadow_rendermode = r_shadow_lightingrendermode;
1606 static const unsigned short bboxelements[36] =
1616 static const float bboxpoints[8][3] =
1628 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1631 float vertex3f[8*3];
1632 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1633 // do global setup needed for the chosen lighting mode
1634 R_Shadow_RenderMode_Reset();
1635 r_shadow_rendermode = r_shadow_lightingrendermode;
1636 R_EntityMatrix(&identitymatrix);
1637 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1638 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1639 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1641 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1643 r_shadow_usingshadowmap2d = shadowmapping;
1645 // render the lighting
1646 R_SetupShader_DeferredLight(rsurface.rtlight);
1647 for (i = 0;i < 8;i++)
1648 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1649 GL_ColorMask(1,1,1,1);
1650 GL_DepthMask(false);
1651 GL_DepthRange(0, 1);
1652 GL_PolygonOffset(0, 0);
1654 GL_DepthFunc(GL_GREATER);
1655 GL_CullFace(r_refdef.view.cullface_back);
1656 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1657 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1660 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1662 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1669 // see if there are really any lights to render...
1670 if (enable && r_shadow_bouncegrid_static.integer)
1673 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1674 for (lightindex = 0;lightindex < range;lightindex++)
1676 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1677 if (!light || !(light->flags & flag))
1679 rtlight = &light->rtlight;
1680 // when static, we skip styled lights because they tend to change...
1681 if (rtlight->style > 0)
1683 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1684 if (!VectorLength2(lightcolor))
1694 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1696 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1697 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1698 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1699 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1701 // prevent any garbage in alignment padded areas as we'll be using memcmp
1702 memset(settings, 0, sizeof(*settings));
1704 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1705 settings->staticmode = s;
1706 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1707 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1708 settings->lightpathsize = bound(0.0f, r_shadow_bouncegrid_lightpathsize.value, 1024.0f);
1709 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1710 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1711 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1712 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1713 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1714 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1715 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1716 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) / 65536.0f;
1717 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1718 settings->energyperphoton = 4096.0f / quality;
1719 settings->spacing[0] = spacing;
1720 settings->spacing[1] = spacing;
1721 settings->spacing[2] = spacing;
1722 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1723 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1724 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1725 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1726 settings->subsamples = bound(1, r_shadow_bouncegrid_subsamples.integer, 4);
1728 // bound the values for sanity
1729 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1730 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1731 settings->maxbounce = bound(0, settings->maxbounce, 16);
1732 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1733 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1734 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1737 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1748 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1750 // get the spacing values
1751 spacing[0] = settings->spacing[0];
1752 spacing[1] = settings->spacing[1];
1753 spacing[2] = settings->spacing[2];
1754 ispacing[0] = 1.0f / spacing[0];
1755 ispacing[1] = 1.0f / spacing[1];
1756 ispacing[2] = 1.0f / spacing[2];
1758 // calculate texture size enclosing entire world bounds at the spacing
1759 if (r_refdef.scene.worldmodel)
1763 qboolean bounds_set = false;
1767 // calculate bounds enclosing world lights as they should be noticably tighter
1768 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1769 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1770 for (lightindex = 0;lightindex < range;lightindex++)
1772 const vec_t *rtlmins, *rtlmaxs;
1774 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1778 rtlight = &light->rtlight;
1779 rtlmins = rtlight->cullmins;
1780 rtlmaxs = rtlight->cullmaxs;
1784 VectorCopy(rtlmins, mins);
1785 VectorCopy(rtlmaxs, maxs);
1790 mins[0] = min(mins[0], rtlmins[0]);
1791 mins[1] = min(mins[1], rtlmins[1]);
1792 mins[2] = min(mins[2], rtlmins[2]);
1793 maxs[0] = max(maxs[0], rtlmaxs[0]);
1794 maxs[1] = max(maxs[1], rtlmaxs[1]);
1795 maxs[2] = max(maxs[2], rtlmaxs[2]);
1799 // limit to no larger than the world bounds
1800 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1801 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1802 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1803 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1804 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1805 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1807 VectorMA(mins, -2.0f, spacing, mins);
1808 VectorMA(maxs, 2.0f, spacing, maxs);
1812 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1813 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1815 VectorSubtract(maxs, mins, size);
1816 // now we can calculate the resolution we want
1817 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1818 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1819 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1820 // figure out the exact texture size (honoring power of 2 if required)
1821 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1822 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1823 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1824 size[0] = spacing[0] * resolution[0];
1825 size[1] = spacing[1] * resolution[1];
1826 size[2] = spacing[2] * resolution[2];
1828 // if dynamic we may or may not want to use the world bounds
1829 // if the dynamic size is smaller than the world bounds, use it instead
1830 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]))
1832 // we know the resolution we want
1833 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1834 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1835 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1836 // now we can calculate the texture size
1837 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1838 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1839 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1840 size[0] = spacing[0] * resolution[0];
1841 size[1] = spacing[1] * resolution[1];
1842 size[2] = spacing[2] * resolution[2];
1843 // center the rendering on the view
1844 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1845 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1846 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1849 // recalculate the maxs in case the resolution was not satisfactory
1850 VectorAdd(mins, size, maxs);
1852 // check if this changed the texture size
1853 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);
1854 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1855 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1856 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1857 VectorCopy(size, r_shadow_bouncegrid_state.size);
1858 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1859 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1860 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1862 // reallocate pixels for this update if needed...
1863 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1864 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1865 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1866 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1867 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1869 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1871 r_shadow_bouncegrid_state.highpixels = NULL;
1873 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1874 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1875 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1876 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1877 if (r_shadow_bouncegrid_state.photons) { Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL; }
1878 if (r_shadow_bouncegrid_state.photons_tasks) { Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL; }
1879 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
1881 r_shadow_bouncegrid_state.numpixels = numpixels;
1884 // update the bouncegrid matrix to put it in the world properly
1885 memset(m, 0, sizeof(m));
1886 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1887 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1888 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1889 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1890 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1891 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1893 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1896 static float R_Shadow_BounceGrid_RefractiveIndexAtPoint(vec3_t point)
1898 // check material at shadoworigin to see what the initial refractive index should be
1899 int hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
1900 int skipsupercontentsmask = 0;
1901 int skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
1902 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);
1903 if (trace.starttexture && (trace.starttexture->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)))
1904 return trace.starttexture->refractive_index;
1905 else if (trace.startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
1906 return 1.333f; // water
1908 return 1.0003f; // air
1911 // enumerate world rtlights and sum the overall amount of light in the world,
1912 // from that we can calculate a scaling factor to fairly distribute photons
1913 // to all the lights
1915 // this modifies rtlight->photoncolor and rtlight->photons
1916 static void R_Shadow_BounceGrid_AssignPhotons_Task(taskqueue_task_t *t)
1918 // get the range of light numbers we'll be looping over:
1919 // range = static lights
1920 // range1 = dynamic lights (optional)
1921 // range2 = range + range1
1922 unsigned int range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1923 unsigned int range1 = r_shadow_bouncegrid_state.settings.staticmode ? 0 : r_refdef.scene.numlights;
1924 unsigned int range2 = range + range1;
1925 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
1927 float normalphotonscaling;
1928 float photonscaling;
1929 float photonintensity;
1930 float photoncount = 0.0f;
1931 float lightintensity;
1937 unsigned int lightindex;
1942 float bounceminimumintensity2;
1943 float startrefractiveindex;
1945 randomseed_t randomseed;
1946 vec3_t baseshotcolor;
1948 normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1949 for (lightindex = 0;lightindex < range2;lightindex++)
1951 if (lightindex < range)
1953 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1956 rtlight = &light->rtlight;
1957 VectorClear(rtlight->bouncegrid_photoncolor);
1958 rtlight->bouncegrid_photons = 0;
1959 rtlight->bouncegrid_hits = 0;
1960 rtlight->bouncegrid_traces = 0;
1961 rtlight->bouncegrid_effectiveradius = 0;
1962 if (!(light->flags & flag))
1964 if (r_shadow_bouncegrid_state.settings.staticmode)
1966 // when static, we skip styled lights because they tend to change...
1967 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
1970 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
1975 rtlight = r_refdef.scene.lights[lightindex - range];
1976 VectorClear(rtlight->bouncegrid_photoncolor);
1977 rtlight->bouncegrid_photons = 0;
1978 rtlight->bouncegrid_hits = 0;
1979 rtlight->bouncegrid_traces = 0;
1980 rtlight->bouncegrid_effectiveradius = 0;
1982 // draw only visible lights (major speedup)
1983 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
1984 cullmins[0] = rtlight->shadoworigin[0] - radius;
1985 cullmins[1] = rtlight->shadoworigin[1] - radius;
1986 cullmins[2] = rtlight->shadoworigin[2] - radius;
1987 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
1988 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
1989 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
1990 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
1991 if (!r_shadow_bouncegrid_state.settings.staticmode)
1993 // skip if the expanded light box does not touch any visible leafs
1994 if (r_refdef.scene.worldmodel
1995 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
1996 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
1998 // skip if the expanded light box is not visible to traceline
1999 // note that PrepareLight already did this check but for a smaller box, so we
2000 // end up casting more traces per frame per light when using bouncegrid, which
2001 // is probably fine (and they use the same timer)
2002 if (r_shadow_culllights_trace.integer)
2004 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))
2005 rtlight->trace_timer = realtime;
2006 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2009 // skip if expanded light box is offscreen
2010 if (R_CullBox(cullmins, cullmaxs))
2012 // skip if overall light intensity is zero
2013 if (w * VectorLength2(rtlight->color) == 0.0f)
2016 // a light that does not emit any light before style is applied, can be
2017 // skipped entirely (it may just be a corona)
2018 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2020 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2021 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2022 // skip lights that will emit no photons
2023 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2025 // shoot particles from this light
2026 // use a calculation for the number of particles that will not
2027 // vary with lightstyle, otherwise we get randomized particle
2028 // distribution, the seeded random is only consistent for a
2029 // consistent number of particles on this light...
2030 s = rtlight->radius;
2031 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2032 if (lightindex >= range)
2033 lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2034 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2035 photoncount += rtlight->bouncegrid_photons;
2036 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2037 // if the lightstyle happens to be off right now, we can skip actually
2038 // firing the photons, but we did have to count them in the total.
2039 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2040 // rtlight->bouncegrid_photons = 0;
2042 // the user provided an energyperphoton value which we try to use
2043 // if that results in too many photons to shoot this frame, then we cap it
2044 // which causes photons to appear/disappear from frame to frame, so we don't
2045 // like doing that in the typical case
2046 photonscaling = 1.0f;
2047 photonintensity = 1.0f;
2048 if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2050 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2051 photonintensity = 1.0f / photonscaling;
2054 // modify the lights to reflect our computed scaling
2055 for (lightindex = 0; lightindex < range2; lightindex++)
2057 if (lightindex < range)
2059 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2062 rtlight = &light->rtlight;
2065 rtlight = r_refdef.scene.lights[lightindex - range];
2066 rtlight->bouncegrid_photons *= photonscaling;
2067 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2070 // compute a seed for the unstable random modes
2071 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2072 seed = realtime * 1000.0;
2074 for (lightindex = 0; lightindex < range2; lightindex++)
2076 if (lightindex < range)
2078 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2081 rtlight = &light->rtlight;
2084 rtlight = r_refdef.scene.lights[lightindex - range];
2085 // note that this code used to keep track of residual photons and
2086 // distribute them evenly to achieve exactly a desired photon count,
2087 // but that caused unwanted flickering in dynamic mode
2088 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2089 // skip if we won't be shooting any photons
2090 if (!shootparticles)
2092 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2093 //s = settings.particleintensity / shootparticles;
2094 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2095 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2096 if (VectorLength2(baseshotcolor) <= 0.0f)
2098 r_refdef.stats[r_stat_bouncegrid_lights]++;
2099 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2100 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2101 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2103 // check material at shadoworigin to see what the initial refractive index should be
2104 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2106 // for seeded random we start the RNG with the position of the light
2107 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2115 u.f[0] = rtlight->shadoworigin[0];
2116 u.f[1] = rtlight->shadoworigin[1];
2117 u.f[2] = rtlight->shadoworigin[2];
2119 switch (r_shadow_bouncegrid_state.settings.rng_type)
2123 // we have to shift the seed provided by the user because the result must be odd
2124 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2127 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2132 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2134 r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2135 VectorCopy(baseshotcolor, p->color);
2136 VectorCopy(rtlight->shadoworigin, p->start);
2137 switch (r_shadow_bouncegrid_state.settings.rng_type)
2141 // figure out a random direction for the initial photon to go
2142 VectorLehmerRandom(&randomseed, p->end);
2145 // figure out a random direction for the initial photon to go
2146 VectorCheeseRandom(seed, p->end);
2150 // we want a uniform distribution spherically, not merely within the sphere
2151 if (r_shadow_bouncegrid_state.settings.normalizevectors)
2152 VectorNormalize(p->end);
2154 VectorMA(p->start, radius, p->end, p->end);
2155 p->bounceminimumintensity2 = bounceminimumintensity2;
2156 p->startrefractiveindex = startrefractiveindex;
2164 static void R_Shadow_BounceGrid_Slice(int zi)
2166 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2167 int xi, yi; // pixel increments
2168 float color[32] = { 0 };
2169 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2170 float iradius = 1.0f / radius;
2171 int slicemins[3], slicemaxs[3];
2173 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2174 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2176 int samples = r_shadow_bouncegrid_state.settings.subsamples;
2177 float isamples = 1.0f / samples;
2178 float samplescolorscale = isamples * isamples * isamples;
2180 // we use these a lot, so get a local copy
2181 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2183 for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2185 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2187 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2189 r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2190 float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2192 VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2193 VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2195 pathmins[2] = min(pathstart[2], pathend[2]);
2196 slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2197 pathmaxs[2] = max(pathstart[2], pathend[2]);
2198 slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2200 // skip if the path doesn't touch this slice
2201 if (zi < slicemins[2] || zi >= slicemaxs[2])
2204 pathmins[0] = min(pathstart[0], pathend[0]);
2205 slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2206 slicemins[0] = max(slicemins[0], 1);
2207 pathmaxs[0] = max(pathstart[0], pathend[0]);
2208 slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2209 slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2211 pathmins[1] = min(pathstart[1], pathend[1]);
2212 slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2213 slicemins[1] = max(slicemins[1], 1);
2214 pathmaxs[1] = max(pathstart[1], pathend[1]);
2215 slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2216 slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2218 // skip if the path is out of bounds on X or Y
2219 if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2222 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2223 // accumulate average shotcolor
2224 VectorSubtract(pathend, pathstart, pathdelta);
2225 pathlength2 = VectorLength2(pathdelta);
2226 pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2227 VectorScale(pathdelta, pathilength, pathdir);
2228 // the color is scaled by the number of subsamples
2229 color[0] = path->color[0] * samplescolorscale;
2230 color[1] = path->color[1] * samplescolorscale;
2231 color[2] = path->color[2] * samplescolorscale;
2235 // store bentnormal in case the shader has a use for it,
2236 // bentnormal is an intensity-weighted average of the directions,
2237 // and will be normalized on conversion to texture pixels.
2238 float intensity = VectorLength(color);
2239 color[4] = pathdir[0] * intensity;
2240 color[5] = pathdir[1] * intensity;
2241 color[6] = pathdir[2] * intensity;
2242 color[7] = intensity;
2243 // for each color component (R, G, B) calculate the amount that a
2244 // direction contributes
2245 color[8] = color[0] * max(0.0f, pathdir[0]);
2246 color[9] = color[0] * max(0.0f, pathdir[1]);
2247 color[10] = color[0] * max(0.0f, pathdir[2]);
2249 color[12] = color[1] * max(0.0f, pathdir[0]);
2250 color[13] = color[1] * max(0.0f, pathdir[1]);
2251 color[14] = color[1] * max(0.0f, pathdir[2]);
2253 color[16] = color[2] * max(0.0f, pathdir[0]);
2254 color[17] = color[2] * max(0.0f, pathdir[1]);
2255 color[18] = color[2] * max(0.0f, pathdir[2]);
2257 // and do the same for negative directions
2258 color[20] = color[0] * max(0.0f, -pathdir[0]);
2259 color[21] = color[0] * max(0.0f, -pathdir[1]);
2260 color[22] = color[0] * max(0.0f, -pathdir[2]);
2262 color[24] = color[1] * max(0.0f, -pathdir[0]);
2263 color[25] = color[1] * max(0.0f, -pathdir[1]);
2264 color[26] = color[1] * max(0.0f, -pathdir[2]);
2266 color[28] = color[2] * max(0.0f, -pathdir[0]);
2267 color[29] = color[2] * max(0.0f, -pathdir[1]);
2268 color[30] = color[2] * max(0.0f, -pathdir[2]);
2272 for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2274 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2276 float sample[3], diff[3], nearest[3], along, distance2;
2277 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2279 // loop over the subsamples
2280 for (zs = 0; zs < samples; zs++)
2282 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2283 for (ys = 0; ys < samples; ys++)
2285 sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2286 for (xs = 0; xs < samples; xs++)
2288 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2290 // measure distance from subsample to line segment and see if it is within radius
2291 along = DotProduct(sample, pathdir) * pathilength;
2293 VectorCopy(pathstart, nearest);
2294 else if (along >= 1)
2295 VectorCopy(pathend, nearest);
2297 VectorLerp(pathstart, along, pathend, nearest);
2298 VectorSubtract(sample, nearest, diff);
2299 VectorScale(diff, iradius, diff);
2300 distance2 = VectorLength2(diff);
2301 if (distance2 < 1.0f)
2303 // contribute some color to this pixel, across all bands
2304 float w = 1.0f - sqrt(distance2);
2309 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2310 p[pixelsperband * 4 + 3] += color[7] * w;
2312 for (band = 0; band < pixelbands; band++)
2314 // add to the pixel color (RGB only - see above)
2315 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2316 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2317 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2329 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2331 R_Shadow_BounceGrid_Slice((int)t->i[0]);
2335 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2338 // we need to wait for the texture clear to finish before we start adding light to it
2339 if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2344 slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2345 for (i = 0; i < slices; i++)
2346 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2347 TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2348 TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2349 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2353 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2355 const float *inpixel;
2357 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2360 unsigned int x, y, z;
2361 unsigned int resolution[3];
2362 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2363 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2365 for (z = 1;z < resolution[2]-1;z++)
2367 for (y = 1;y < resolution[1]-1;y++)
2370 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2371 inpixel = inpixels + 4*index;
2372 outpixel = outpixels + 4*index;
2373 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2375 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2376 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2377 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2378 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2385 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2388 unsigned int resolution[3];
2389 if (r_shadow_bouncegrid_state.settings.blur)
2391 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2393 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2394 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2395 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2396 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2399 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2401 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2403 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2405 // toggle the state, highpixels now points to pixels[3] result
2406 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2407 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2412 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2414 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2415 unsigned char *pixelsbgra8 = NULL;
2416 unsigned char *pixelbgra8;
2417 unsigned short *pixelsrgba16f = NULL;
2418 unsigned short *pixelrgba16f;
2419 float *pixelsrgba32f = NULL;
2420 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2423 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2424 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2425 unsigned int pixelband;
2426 unsigned int x, y, z;
2427 unsigned int index, bandindex;
2428 unsigned int resolution[3];
2430 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2432 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2434 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2435 r_shadow_bouncegrid_state.texture = NULL;
2438 // if bentnormals exist, we need to normalize and bias them for the shader
2442 for (z = 0;z < resolution[2]-1;z++)
2444 for (y = 0;y < resolution[1]-1;y++)
2447 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2448 highpixel = highpixels + 4*index;
2449 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2451 // only convert pixels that were hit by photons
2452 if (highpixel[3] != 0.0f)
2453 VectorNormalize(highpixel);
2454 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2455 highpixel[pixelsperband * 4 + 3] = 1.0f;
2461 // start by clearing the pixels array - we won't be writing to all of it
2463 // then process only the pixels that have at least some color, skipping
2464 // the higher bands for speed on pixels that are black
2465 switch (floatcolors)
2468 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2469 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2470 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2471 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2474 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2476 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2478 for (z = 1;z < resolution[2]-1;z++)
2480 for (y = 1;y < resolution[1]-1;y++)
2484 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2485 highpixel = highpixels + 4*index;
2486 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2488 // only convert pixels that were hit by photons
2489 if (VectorLength2(highpixel))
2491 // normalize the bentnormal now
2494 VectorNormalize(highpixel + pixelsperband * 4);
2495 highpixel[pixelsperband * 4 + 3] = 1.0f;
2497 // process all of the pixelbands for this pixel
2498 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2500 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2501 bandpixel = highpixels + 4*bandindex;
2502 c[0] = (int)(bandpixel[0]*256.0f);
2503 c[1] = (int)(bandpixel[1]*256.0f);
2504 c[2] = (int)(bandpixel[2]*256.0f);
2505 c[3] = (int)(bandpixel[3]*256.0f);
2506 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2507 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2508 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2509 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2516 if (!r_shadow_bouncegrid_state.createtexture)
2517 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2519 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);
2522 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2523 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2524 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2525 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2526 for (z = 1;z < resolution[2]-1;z++)
2528 for (y = 1;y < resolution[1]-1;y++)
2532 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2533 highpixel = highpixels + 4*index;
2534 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2536 // only convert pixels that were hit by photons
2537 if (VectorLength2(highpixel))
2539 // process all of the pixelbands for this pixel
2540 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2542 // time to have fun with IEEE 754 bit hacking...
2545 unsigned int raw[4];
2547 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2548 bandpixel = highpixels + 4*bandindex;
2549 VectorCopy4(bandpixel, u.f);
2550 VectorCopy4(u.raw, c);
2551 // this math supports negative numbers, snaps denormals to zero
2552 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2553 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2554 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2555 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2556 // this math does not support negative
2557 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2558 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2559 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2560 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2567 if (!r_shadow_bouncegrid_state.createtexture)
2568 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2570 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);
2573 // our native format happens to match, so this is easy.
2574 pixelsrgba32f = highpixels;
2576 if (!r_shadow_bouncegrid_state.createtexture)
2577 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2579 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);
2583 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2586 void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2588 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2592 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)
2594 int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2596 vec3_t surfacenormal;
2597 vec3_t reflectstart, reflectend, reflectcolor;
2598 vec3_t refractstart, refractend, refractcolor;
2600 float reflectamount = 1.0f;
2602 // figure out what we want to interact with
2603 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2604 skipsupercontentsmask = 0;
2605 skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2606 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2607 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2608 if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2610 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2611 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2612 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);
2616 // dynamic mode fires many rays and most will match the cache from the previous frame
2617 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);
2619 VectorCopy(cliptrace.endpos, shothit);
2620 if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2622 qboolean notculled = true;
2623 // cull paths that fail R_CullBox in dynamic mode
2624 if (!r_shadow_bouncegrid_state.settings.staticmode
2625 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2627 vec3_t cullmins, cullmaxs;
2628 cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2629 cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2630 cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2631 cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2632 cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2633 cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2634 if (R_CullBox(cullmins, cullmaxs))
2639 r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2640 VectorCopy(shotstart, path->start);
2641 VectorCopy(shothit, path->end);
2642 VectorCopy(shotcolor, path->color);
2645 if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2647 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2648 // also clamp the resulting color to never add energy, even if the user requests extreme values
2649 VectorCopy(cliptrace.plane.normal, surfacenormal);
2650 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2651 VectorClear(refractcolor);
2652 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2653 if (cliptrace.hittexture)
2655 if (cliptrace.hittexture->currentskinframe)
2656 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2657 if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2659 reflectamount *= cliptrace.hittexture->currentalpha;
2660 if (cliptrace.hittexture->currentskinframe)
2661 reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2663 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2667 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2668 VectorSubtract(shotstart, shotend, lightdir);
2669 VectorNormalize(lightdir);
2670 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2671 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2672 reflectamount *= Fresnel;
2673 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2675 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2676 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2677 // make sure we do not gain energy even if surface colors are out of bounds
2678 reflectcolor[0] = min(reflectcolor[0], 1.0f);
2679 reflectcolor[1] = min(reflectcolor[1], 1.0f);
2680 reflectcolor[2] = min(reflectcolor[2], 1.0f);
2681 refractcolor[0] = min(refractcolor[0], 1.0f);
2682 refractcolor[1] = min(refractcolor[1], 1.0f);
2683 refractcolor[2] = min(refractcolor[2], 1.0f);
2685 // reflected and refracted shots
2686 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2687 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2688 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2689 VectorMultiply(refractcolor, shotcolor, refractcolor);
2691 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2693 // reflect the remaining portion of the line across plane normal
2694 VectorSubtract(shotend, shothit, reflectend);
2695 VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2696 // calculate the new line start and end
2697 VectorCopy(shothit, reflectstart);
2698 VectorAdd(reflectstart, reflectend, reflectend);
2699 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2702 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2704 // Check what refractive index is on the other side
2705 float refractiveindex;
2706 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2707 refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2708 // reflect the remaining portion of the line across plane normal
2709 VectorSubtract(shotend, shothit, refractend);
2710 s = refractiveindex / previousrefractiveindex;
2711 VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2712 // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2713 // calculate the new line start and end
2714 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2715 VectorAdd(refractstart, refractend, refractend);
2716 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2721 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2723 r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2724 R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2728 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2731 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2732 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2733 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);
2734 if (r_shadow_bouncegrid_threaded.integer)
2736 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2737 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2741 // when not threaded we still have to report task status
2742 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2743 r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2744 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2749 void R_Shadow_UpdateBounceGridTexture(void)
2751 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2752 r_shadow_bouncegrid_settings_t settings;
2753 qboolean enable = false;
2754 qboolean settingschanged;
2756 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2758 R_Shadow_BounceGrid_GenerateSettings(&settings);
2760 // changing intensity does not require an update
2761 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2763 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2765 // when settings change, we free everything as it is just simpler that way.
2766 if (settingschanged || !enable)
2768 // not enabled, make sure we free anything we don't need anymore.
2769 if (r_shadow_bouncegrid_state.texture)
2771 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2772 r_shadow_bouncegrid_state.texture = NULL;
2774 r_shadow_bouncegrid_state.highpixels = NULL;
2775 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2776 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2777 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2778 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2779 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2780 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2781 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2782 r_shadow_bouncegrid_state.numpixels = 0;
2783 r_shadow_bouncegrid_state.numphotons = 0;
2784 r_shadow_bouncegrid_state.directional = false;
2790 // if all the settings seem identical to the previous update, return
2791 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2794 // store the new settings
2795 r_shadow_bouncegrid_state.settings = settings;
2797 R_Shadow_BounceGrid_UpdateSpacing();
2799 // allocate the highpixels array we'll be accumulating light into
2800 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2801 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2802 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2803 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2804 r_shadow_bouncegrid_state.highpixels_index = 0;
2805 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2807 // set up the tracking of photon data
2808 if (r_shadow_bouncegrid_state.photons == NULL)
2809 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));
2810 if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2811 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2812 r_shadow_bouncegrid_state.numphotons = 0;
2814 // set up the tracking of slice tasks
2815 if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2816 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2818 memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2819 memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2820 memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2821 memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2822 memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2823 memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2824 memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2825 memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2826 memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2828 // clear the texture
2829 TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2830 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2832 // calculate weighting factors for distributing photons among the lights
2833 TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2834 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2836 // enqueue tasks to trace the photons from lights
2837 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2838 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2840 // accumulate the light paths into texture
2841 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);
2842 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2844 // apply a mild blur filter to the texture
2845 TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2846 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2848 TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2849 R_TimeReport("bouncegrid_gen");
2851 // convert the pixels to lower precision and upload the texture
2852 // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2853 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2854 R_TimeReport("bouncegrid_tex");
2856 // after we compute the static lighting we don't need to keep the highpixels array around
2857 if (settings.staticmode)
2859 r_shadow_bouncegrid_state.highpixels = NULL;
2860 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2861 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2862 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2863 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2864 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2865 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2866 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2870 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2872 R_Shadow_RenderMode_Reset();
2873 GL_BlendFunc(GL_ONE, GL_ONE);
2874 GL_DepthRange(0, 1);
2875 GL_DepthTest(r_showlighting.integer < 2);
2876 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2878 GL_DepthFunc(GL_EQUAL);
2879 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2882 void R_Shadow_RenderMode_End(void)
2884 R_Shadow_RenderMode_Reset();
2885 R_Shadow_RenderMode_ActiveLight(NULL);
2887 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2888 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2891 int bboxedges[12][2] =
2910 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2912 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2914 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2915 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2916 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2917 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2920 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2921 return true; // invisible
2922 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2923 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2924 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2925 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2926 r_refdef.stats[r_stat_lights_scissored]++;
2930 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2932 // used to display how many times a surface is lit for level design purposes
2933 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2934 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2938 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])
2940 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2941 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2945 extern cvar_t gl_lightmaps;
2946 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2949 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2950 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2951 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2952 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2953 if (!r_shadow_usenormalmap.integer)
2955 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2956 VectorClear(diffusecolor);
2957 VectorClear(specularcolor);
2959 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2960 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2961 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2962 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2964 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2967 VectorNegate(ambientcolor, ambientcolor);
2968 VectorNegate(diffusecolor, diffusecolor);
2969 VectorNegate(specularcolor, specularcolor);
2970 GL_BlendEquationSubtract(true);
2972 RSurf_SetupDepthAndCulling();
2973 switch (r_shadow_rendermode)
2975 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2976 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2977 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2979 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2980 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2983 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2987 GL_BlendEquationSubtract(false);
2990 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)
2992 matrix4x4_t tempmatrix = *matrix;
2993 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2995 // if this light has been compiled before, free the associated data
2996 R_RTLight_Uncompile(rtlight);
2998 // clear it completely to avoid any lingering data
2999 memset(rtlight, 0, sizeof(*rtlight));
3001 // copy the properties
3002 rtlight->matrix_lighttoworld = tempmatrix;
3003 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3004 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3005 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3006 VectorCopy(color, rtlight->color);
3007 rtlight->cubemapname[0] = 0;
3008 if (cubemapname && cubemapname[0])
3009 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3010 rtlight->shadow = shadow;
3011 rtlight->corona = corona;
3012 rtlight->style = style;
3013 rtlight->isstatic = isstatic;
3014 rtlight->coronasizescale = coronasizescale;
3015 rtlight->ambientscale = ambientscale;
3016 rtlight->diffusescale = diffusescale;
3017 rtlight->specularscale = specularscale;
3018 rtlight->flags = flags;
3020 // compute derived data
3021 //rtlight->cullradius = rtlight->radius;
3022 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3023 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3024 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3025 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3026 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3027 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3028 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3031 // compiles rtlight geometry
3032 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3033 void R_RTLight_Compile(rtlight_t *rtlight)
3036 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3037 int lighttris, shadowtris;
3038 entity_render_t *ent = r_refdef.scene.worldentity;
3039 dp_model_t *model = r_refdef.scene.worldmodel;
3040 unsigned char *data;
3042 // compile the light
3043 rtlight->compiled = true;
3044 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3045 rtlight->static_numleafs = 0;
3046 rtlight->static_numleafpvsbytes = 0;
3047 rtlight->static_leaflist = NULL;
3048 rtlight->static_leafpvs = NULL;
3049 rtlight->static_numsurfaces = 0;
3050 rtlight->static_surfacelist = NULL;
3051 rtlight->static_shadowmap_receivers = 0x3F;
3052 rtlight->static_shadowmap_casters = 0x3F;
3053 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3054 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3055 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3056 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3057 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3058 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3060 if (model && model->GetLightInfo)
3062 // this variable must be set for the CompileShadowMap code
3063 r_shadow_compilingrtlight = rtlight;
3064 R_FrameData_SetMark();
3065 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);
3066 R_FrameData_ReturnToMark();
3067 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3068 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3069 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3070 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3071 rtlight->static_numsurfaces = numsurfaces;
3072 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3073 rtlight->static_numleafs = numleafs;
3074 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3075 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3076 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3077 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3078 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3079 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3080 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3081 if (rtlight->static_numsurfaces)
3082 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3083 if (rtlight->static_numleafs)
3084 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3085 if (rtlight->static_numleafpvsbytes)
3086 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3087 if (rtlight->static_numshadowtrispvsbytes)
3088 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3089 if (rtlight->static_numlighttrispvsbytes)
3090 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3091 R_FrameData_SetMark();
3092 if (model->CompileShadowMap && rtlight->shadow)
3093 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3094 R_FrameData_ReturnToMark();
3095 // now we're done compiling the rtlight
3096 r_shadow_compilingrtlight = NULL;
3100 // use smallest available cullradius - box radius or light radius
3101 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3102 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3105 if (rtlight->static_numlighttrispvsbytes)
3106 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3107 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3111 if (rtlight->static_numshadowtrispvsbytes)
3112 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3113 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3116 if (developer_extra.integer)
3117 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);
3120 void R_RTLight_Uncompile(rtlight_t *rtlight)
3122 if (rtlight->compiled)
3124 if (rtlight->static_meshchain_shadow_shadowmap)
3125 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3126 rtlight->static_meshchain_shadow_shadowmap = NULL;
3127 // these allocations are grouped
3128 if (rtlight->static_surfacelist)
3129 Mem_Free(rtlight->static_surfacelist);
3130 rtlight->static_numleafs = 0;
3131 rtlight->static_numleafpvsbytes = 0;
3132 rtlight->static_leaflist = NULL;
3133 rtlight->static_leafpvs = NULL;
3134 rtlight->static_numsurfaces = 0;
3135 rtlight->static_surfacelist = NULL;
3136 rtlight->static_numshadowtrispvsbytes = 0;
3137 rtlight->static_shadowtrispvs = NULL;
3138 rtlight->static_numlighttrispvsbytes = 0;
3139 rtlight->static_lighttrispvs = NULL;
3140 rtlight->compiled = false;
3144 void R_Shadow_UncompileWorldLights(void)
3148 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3149 for (lightindex = 0;lightindex < range;lightindex++)
3151 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3154 R_RTLight_Uncompile(&light->rtlight);
3158 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3162 // reset the count of frustum planes
3163 // see rtlight->cached_frustumplanes definition for how much this array
3165 rtlight->cached_numfrustumplanes = 0;
3167 if (r_trippy.integer)
3170 // haven't implemented a culling path for ortho rendering
3171 if (!r_refdef.view.useperspective)
3173 // check if the light is on screen and copy the 4 planes if it is
3174 for (i = 0;i < 4;i++)
3175 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3178 for (i = 0;i < 4;i++)
3179 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3184 // generate a deformed frustum that includes the light origin, this is
3185 // used to cull shadow casting surfaces that can not possibly cast a
3186 // shadow onto the visible light-receiving surfaces, which can be a
3189 // if the light origin is onscreen the result will be 4 planes exactly
3190 // if the light origin is offscreen on only one axis the result will
3191 // be exactly 5 planes (split-side case)
3192 // if the light origin is offscreen on two axes the result will be
3193 // exactly 4 planes (stretched corner case)
3194 for (i = 0;i < 4;i++)
3196 // quickly reject standard frustum planes that put the light
3197 // origin outside the frustum
3198 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3201 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3203 // if all the standard frustum planes were accepted, the light is onscreen
3204 // otherwise we need to generate some more planes below...
3205 if (rtlight->cached_numfrustumplanes < 4)
3207 // at least one of the stock frustum planes failed, so we need to
3208 // create one or two custom planes to enclose the light origin
3209 for (i = 0;i < 4;i++)
3211 // create a plane using the view origin and light origin, and a
3212 // single point from the frustum corner set
3213 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3214 VectorNormalize(plane.normal);
3215 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3216 // see if this plane is backwards and flip it if so
3217 for (j = 0;j < 4;j++)
3218 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3222 VectorNegate(plane.normal, plane.normal);
3224 // flipped plane, test again to see if it is now valid
3225 for (j = 0;j < 4;j++)
3226 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3228 // if the plane is still not valid, then it is dividing the
3229 // frustum and has to be rejected
3233 // we have created a valid plane, compute extra info
3234 PlaneClassify(&plane);
3236 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3238 // if we've found 5 frustum planes then we have constructed a
3239 // proper split-side case and do not need to keep searching for
3240 // planes to enclose the light origin
3241 if (rtlight->cached_numfrustumplanes == 5)
3249 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3251 plane = rtlight->cached_frustumplanes[i];
3252 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));
3257 // now add the light-space box planes if the light box is rotated, as any
3258 // caster outside the oriented light box is irrelevant (even if it passed
3259 // the worldspace light box, which is axial)
3260 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3262 for (i = 0;i < 6;i++)
3266 v[i >> 1] = (i & 1) ? -1 : 1;
3267 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3268 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3269 plane.dist = VectorNormalizeLength(plane.normal);
3270 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3271 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3277 // add the world-space reduced box planes
3278 for (i = 0;i < 6;i++)
3280 VectorClear(plane.normal);
3281 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3282 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3283 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3292 // reduce all plane distances to tightly fit the rtlight cull box, which
3294 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3295 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3296 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3297 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3298 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3299 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3300 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3301 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3302 oldnum = rtlight->cached_numfrustumplanes;
3303 rtlight->cached_numfrustumplanes = 0;
3304 for (j = 0;j < oldnum;j++)
3306 // find the nearest point on the box to this plane
3307 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3308 for (i = 1;i < 8;i++)
3310 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3311 if (bestdist > dist)
3314 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);
3315 // if the nearest point is near or behind the plane, we want this
3316 // plane, otherwise the plane is useless as it won't cull anything
3317 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3319 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3320 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3327 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3329 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3331 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3333 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3334 if (mesh->sidetotals[r_shadow_shadowmapside])
3337 GL_CullFace(GL_NONE);
3338 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3339 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3340 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);
3344 else if (r_refdef.scene.worldentity->model)
3345 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);
3347 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3350 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3352 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3353 vec_t relativeshadowradius;
3354 RSurf_ActiveModelEntity(ent, false, false, false);
3355 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3356 // we need to re-init the shader for each entity because the matrix changed
3357 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3358 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3359 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3360 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3361 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3362 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3363 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3364 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3365 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3368 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3370 // set up properties for rendering light onto this entity
3371 RSurf_ActiveModelEntity(ent, true, true, false);
3372 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3373 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3374 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3375 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3378 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3380 if (!r_refdef.scene.worldmodel->DrawLight)
3383 // set up properties for rendering light onto this entity
3384 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3385 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3386 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3387 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3388 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3390 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3392 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3395 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3397 dp_model_t *model = ent->model;
3398 if (!model->DrawLight)
3401 R_Shadow_SetupEntityLight(ent);
3403 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3405 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3408 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3412 int numleafs, numsurfaces;
3413 int *leaflist, *surfacelist;
3414 unsigned char *leafpvs;
3415 unsigned char *shadowtrispvs;
3416 unsigned char *lighttrispvs;
3417 //unsigned char *surfacesides;
3418 int numlightentities;
3419 int numlightentities_noselfshadow;
3420 int numshadowentities;
3421 int numshadowentities_noselfshadow;
3422 // FIXME: bounds check lightentities and shadowentities, etc.
3423 static entity_render_t *lightentities[MAX_EDICTS];
3424 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3425 static entity_render_t *shadowentities[MAX_EDICTS];
3426 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3428 qboolean castshadows;
3430 rtlight->draw = false;
3431 rtlight->cached_numlightentities = 0;
3432 rtlight->cached_numlightentities_noselfshadow = 0;
3433 rtlight->cached_numshadowentities = 0;
3434 rtlight->cached_numshadowentities_noselfshadow = 0;
3435 rtlight->cached_numsurfaces = 0;
3436 rtlight->cached_lightentities = NULL;
3437 rtlight->cached_lightentities_noselfshadow = NULL;
3438 rtlight->cached_shadowentities = NULL;
3439 rtlight->cached_shadowentities_noselfshadow = NULL;
3440 rtlight->cached_shadowtrispvs = NULL;
3441 rtlight->cached_lighttrispvs = NULL;
3442 rtlight->cached_surfacelist = NULL;
3443 rtlight->shadowmapsidesize = 0;
3445 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3446 // skip lights that are basically invisible (color 0 0 0)
3447 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3449 // loading is done before visibility checks because loading should happen
3450 // all at once at the start of a level, not when it stalls gameplay.
3451 // (especially important to benchmarks)
3453 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3455 if (rtlight->compiled)
3456 R_RTLight_Uncompile(rtlight);
3457 R_RTLight_Compile(rtlight);
3461 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3463 // look up the light style value at this time
3464 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3465 VectorScale(rtlight->color, f, rtlight->currentcolor);
3467 if (rtlight->selected)
3469 f = 2 + sin(realtime * M_PI * 4.0);
3470 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3474 // skip if lightstyle is currently off
3475 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3478 // skip processing on corona-only lights
3482 // skip if the light box is not touching any visible leafs
3483 if (r_shadow_culllights_pvs.integer
3484 && r_refdef.scene.worldmodel
3485 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3486 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3489 // skip if the light box is not visible to traceline
3490 if (r_shadow_culllights_trace.integer)
3492 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))
3493 rtlight->trace_timer = realtime;
3494 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3498 // skip if the light box is off screen
3499 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3502 // in the typical case this will be quickly replaced by GetLightInfo
3503 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3504 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3506 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3508 // 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
3509 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3512 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3514 // compiled light, world available and can receive realtime lighting
3515 // retrieve leaf information
3516 numleafs = rtlight->static_numleafs;
3517 leaflist = rtlight->static_leaflist;
3518 leafpvs = rtlight->static_leafpvs;
3519 numsurfaces = rtlight->static_numsurfaces;
3520 surfacelist = rtlight->static_surfacelist;
3521 //surfacesides = NULL;
3522 shadowtrispvs = rtlight->static_shadowtrispvs;
3523 lighttrispvs = rtlight->static_lighttrispvs;
3525 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3527 // dynamic light, world available and can receive realtime lighting
3528 // calculate lit surfaces and leafs
3529 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);
3530 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3531 leaflist = r_shadow_buffer_leaflist;
3532 leafpvs = r_shadow_buffer_leafpvs;
3533 surfacelist = r_shadow_buffer_surfacelist;
3534 //surfacesides = r_shadow_buffer_surfacesides;
3535 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3536 lighttrispvs = r_shadow_buffer_lighttrispvs;
3537 // if the reduced leaf bounds are offscreen, skip it
3538 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3549 //surfacesides = NULL;
3550 shadowtrispvs = NULL;
3551 lighttrispvs = NULL;
3553 // check if light is illuminating any visible leafs
3556 for (i = 0; i < numleafs; i++)
3557 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3563 // make a list of lit entities and shadow casting entities
3564 numlightentities = 0;
3565 numlightentities_noselfshadow = 0;
3566 numshadowentities = 0;
3567 numshadowentities_noselfshadow = 0;
3569 // add dynamic entities that are lit by the light
3570 for (i = 0; i < r_refdef.scene.numentities; i++)
3573 entity_render_t *ent = r_refdef.scene.entities[i];
3575 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3577 // skip the object entirely if it is not within the valid
3578 // shadow-casting region (which includes the lit region)
3579 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3581 if (!(model = ent->model))
3583 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3585 // this entity wants to receive light, is visible, and is
3586 // inside the light box
3587 // TODO: check if the surfaces in the model can receive light
3588 // so now check if it's in a leaf seen by the light
3589 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))
3591 if (ent->flags & RENDER_NOSELFSHADOW)
3592 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3594 lightentities[numlightentities++] = ent;
3595 // since it is lit, it probably also casts a shadow...
3596 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3597 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3598 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3600 // note: exterior models without the RENDER_NOSELFSHADOW
3601 // flag still create a RENDER_NOSELFSHADOW shadow but
3602 // are lit normally, this means that they are
3603 // self-shadowing but do not shadow other
3604 // RENDER_NOSELFSHADOW entities such as the gun
3605 // (very weird, but keeps the player shadow off the gun)
3606 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3607 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3609 shadowentities[numshadowentities++] = ent;
3612 else if (ent->flags & RENDER_SHADOW)
3614 // this entity is not receiving light, but may still need to
3616 // TODO: check if the surfaces in the model can cast shadow
3617 // now check if it is in a leaf seen by the light
3618 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))
3620 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3621 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3622 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3624 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3625 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3627 shadowentities[numshadowentities++] = ent;
3632 // return if there's nothing at all to light
3633 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3636 // count this light in the r_speeds
3637 r_refdef.stats[r_stat_lights]++;
3639 // flag it as worth drawing later
3640 rtlight->draw = true;
3642 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3643 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3645 numshadowentities = numshadowentities_noselfshadow = 0;
3646 rtlight->castshadows = castshadows;
3648 // cache all the animated entities that cast a shadow but are not visible
3649 for (i = 0; i < numshadowentities; i++)
3650 R_AnimCache_GetEntity(shadowentities[i], false, false);
3651 for (i = 0; i < numshadowentities_noselfshadow; i++)
3652 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3654 // 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)
3655 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3657 for (i = 0; i < numshadowentities_noselfshadow; i++)
3658 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3659 numshadowentities_noselfshadow = 0;
3662 // we can convert noselfshadow to regular if there are no casters of that type
3663 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3665 for (i = 0; i < numlightentities_noselfshadow; i++)
3666 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3667 numlightentities_noselfshadow = 0;
3670 // allocate some temporary memory for rendering this light later in the frame
3671 // reusable buffers need to be copied, static data can be used as-is
3672 rtlight->cached_numlightentities = numlightentities;
3673 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3674 rtlight->cached_numshadowentities = numshadowentities;
3675 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3676 rtlight->cached_numsurfaces = numsurfaces;
3677 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3678 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3679 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3680 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3681 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3683 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3684 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3685 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3686 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3687 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3691 // compiled light data
3692 rtlight->cached_shadowtrispvs = shadowtrispvs;
3693 rtlight->cached_lighttrispvs = lighttrispvs;
3694 rtlight->cached_surfacelist = surfacelist;
3697 if (R_Shadow_ShadowMappingEnabled())
3699 // figure out the shadowmapping parameters for this light
3700 vec3_t nearestpoint;
3703 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3704 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3705 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3706 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3707 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3708 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3709 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3710 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3711 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3715 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3719 unsigned char *shadowtrispvs, *surfacesides;
3720 int numlightentities;
3721 int numlightentities_noselfshadow;
3722 int numshadowentities;
3723 int numshadowentities_noselfshadow;
3724 entity_render_t **lightentities;
3725 entity_render_t **lightentities_noselfshadow;
3726 entity_render_t **shadowentities;
3727 entity_render_t **shadowentities_noselfshadow;
3729 static unsigned char entitysides[MAX_EDICTS];
3730 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3736 matrix4x4_t radiustolight;
3738 // check if we cached this light this frame (meaning it is worth drawing)
3739 if (!rtlight->draw || !rtlight->castshadows)
3742 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3743 if (rtlight->shadowmapatlassidesize == 0)
3745 rtlight->castshadows = false;
3749 // set up a scissor rectangle for this light
3750 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3753 // don't let sound skip if going slow
3754 if (r_refdef.scene.extraupdate)
3757 numlightentities = rtlight->cached_numlightentities;
3758 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3759 numshadowentities = rtlight->cached_numshadowentities;
3760 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3761 numsurfaces = rtlight->cached_numsurfaces;
3762 lightentities = rtlight->cached_lightentities;
3763 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3764 shadowentities = rtlight->cached_shadowentities;
3765 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3766 shadowtrispvs = rtlight->cached_shadowtrispvs;
3767 surfacelist = rtlight->cached_surfacelist;
3769 // make this the active rtlight for rendering purposes
3770 R_Shadow_RenderMode_ActiveLight(rtlight);
3772 radiustolight = rtlight->matrix_worldtolight;
3773 Matrix4x4_Abs(&radiustolight);
3775 size = rtlight->shadowmapatlassidesize;
3776 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3778 surfacesides = NULL;
3783 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3785 castermask = rtlight->static_shadowmap_casters;
3786 receivermask = rtlight->static_shadowmap_receivers;
3790 surfacesides = r_shadow_buffer_surfacesides;
3791 for (i = 0; i < numsurfaces; i++)
3793 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3794 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3795 castermask |= surfacesides[i];
3796 receivermask |= surfacesides[i];
3801 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3802 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3803 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3804 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3806 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3810 for (i = 0; i < numshadowentities; i++)
3811 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3812 for (i = 0; i < numshadowentities_noselfshadow; i++)
3813 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3816 // there is no need to render shadows for sides that have no receivers...
3817 castermask &= receivermask;
3819 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3821 // render shadow casters into shadowmaps for this light
3822 for (side = 0; side < 6; side++)
3824 int bit = 1 << side;
3825 if (castermask & bit)
3827 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3829 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3830 for (i = 0; i < numshadowentities; i++)
3831 if (entitysides[i] & bit)
3832 R_Shadow_DrawEntityShadow(shadowentities[i]);
3833 for (i = 0; i < numshadowentities_noselfshadow; i++)
3834 if (entitysides_noselfshadow[i] & bit)
3835 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3838 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3839 if (numshadowentities_noselfshadow)
3841 for (side = 0; side < 6; side++)
3843 int bit = 1 << side;
3844 if (castermask & bit)
3846 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3848 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3849 for (i = 0; i < numshadowentities; i++)
3850 if (entitysides[i] & bit)
3851 R_Shadow_DrawEntityShadow(shadowentities[i]);
3857 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3861 unsigned char *lighttrispvs;
3862 int numlightentities;
3863 int numlightentities_noselfshadow;
3864 entity_render_t **lightentities;
3865 entity_render_t **lightentities_noselfshadow;
3866 entity_render_t **shadowentities;
3867 entity_render_t **shadowentities_noselfshadow;
3869 qboolean castshadows;
3871 // check if we cached this light this frame (meaning it is worth drawing)
3875 // set up a scissor rectangle for this light
3876 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3879 // don't let sound skip if going slow
3880 if (r_refdef.scene.extraupdate)
3883 numlightentities = rtlight->cached_numlightentities;
3884 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3885 numsurfaces = rtlight->cached_numsurfaces;
3886 lightentities = rtlight->cached_lightentities;
3887 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3888 shadowentities = rtlight->cached_shadowentities;
3889 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3890 lighttrispvs = rtlight->cached_lighttrispvs;
3891 surfacelist = rtlight->cached_surfacelist;
3892 castshadows = rtlight->castshadows;
3894 // make this the active rtlight for rendering purposes
3895 R_Shadow_RenderMode_ActiveLight(rtlight);
3897 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3899 // optionally draw the illuminated areas
3900 // for performance analysis by level designers
3901 R_Shadow_RenderMode_VisibleLighting(false);
3903 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3904 for (i = 0;i < numlightentities;i++)
3905 R_Shadow_DrawEntityLight(lightentities[i]);
3906 for (i = 0;i < numlightentities_noselfshadow;i++)
3907 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3910 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3914 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3915 Matrix4x4_Abs(&radiustolight);
3917 size = rtlight->shadowmapatlassidesize;
3918 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3920 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3922 // render lighting using the depth texture as shadowmap
3923 // draw lighting in the unmasked areas
3924 if (numsurfaces + numlightentities)
3926 R_Shadow_RenderMode_Lighting(false, true, false);
3927 // draw lighting in the unmasked areas
3929 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3930 for (i = 0; i < numlightentities; i++)
3931 R_Shadow_DrawEntityLight(lightentities[i]);
3933 // offset to the noselfshadow part of the atlas and draw those too
3934 if (numlightentities_noselfshadow)
3936 R_Shadow_RenderMode_Lighting(false, true, true);
3937 for (i = 0; i < numlightentities_noselfshadow; i++)
3938 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3941 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3942 if (r_shadow_usingdeferredprepass)
3943 R_Shadow_RenderMode_DrawDeferredLight(true);
3947 // draw lighting in the unmasked areas
3948 R_Shadow_RenderMode_Lighting(false, false, false);
3950 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3951 for (i = 0;i < numlightentities;i++)
3952 R_Shadow_DrawEntityLight(lightentities[i]);
3953 for (i = 0;i < numlightentities_noselfshadow;i++)
3954 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3956 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3957 if (r_shadow_usingdeferredprepass)
3958 R_Shadow_RenderMode_DrawDeferredLight(false);
3962 static void R_Shadow_FreeDeferred(void)
3964 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3965 r_shadow_prepassgeometryfbo = 0;
3967 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3968 r_shadow_prepasslightingdiffusespecularfbo = 0;
3970 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3971 r_shadow_prepasslightingdiffusefbo = 0;
3973 if (r_shadow_prepassgeometrydepthbuffer)
3974 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3975 r_shadow_prepassgeometrydepthbuffer = NULL;
3977 if (r_shadow_prepassgeometrynormalmaptexture)
3978 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3979 r_shadow_prepassgeometrynormalmaptexture = NULL;
3981 if (r_shadow_prepasslightingdiffusetexture)
3982 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3983 r_shadow_prepasslightingdiffusetexture = NULL;
3985 if (r_shadow_prepasslightingspeculartexture)
3986 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3987 r_shadow_prepasslightingspeculartexture = NULL;
3990 void R_Shadow_DrawPrepass(void)
3994 entity_render_t *ent;
3995 float clearcolor[4];
3997 R_Mesh_ResetTextureState();
3999 GL_ColorMask(1,1,1,1);
4000 GL_BlendFunc(GL_ONE, GL_ZERO);
4003 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4004 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4005 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4006 if (r_timereport_active)
4007 R_TimeReport("prepasscleargeom");
4009 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4010 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4011 if (r_timereport_active)
4012 R_TimeReport("prepassworld");
4014 for (i = 0;i < r_refdef.scene.numentities;i++)
4016 if (!r_refdef.viewcache.entityvisible[i])
4018 ent = r_refdef.scene.entities[i];
4019 if (ent->model && ent->model->DrawPrepass != NULL)
4020 ent->model->DrawPrepass(ent);
4023 if (r_timereport_active)
4024 R_TimeReport("prepassmodels");
4026 GL_DepthMask(false);
4027 GL_ColorMask(1,1,1,1);
4030 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4031 Vector4Set(clearcolor, 0, 0, 0, 0);
4032 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4033 if (r_timereport_active)
4034 R_TimeReport("prepassclearlit");
4036 R_Shadow_RenderMode_Begin();
4038 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4039 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4041 R_Shadow_RenderMode_End();
4043 if (r_timereport_active)
4044 R_TimeReport("prepasslights");
4047 #define MAX_SCENELIGHTS 65536
4048 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4050 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4052 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4054 r_shadow_scenemaxlights *= 2;
4055 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4056 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4058 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4062 void R_Shadow_DrawLightSprites(void);
4063 void R_Shadow_PrepareLights(void)
4072 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4073 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4074 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4076 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4077 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4078 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4079 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4080 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4081 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4082 r_shadow_shadowmapborder != shadowmapborder ||
4083 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4084 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4085 R_Shadow_FreeShadowMaps();
4087 r_shadow_usingshadowmaportho = false;
4089 switch (vid.renderpath)
4091 case RENDERPATH_GL32:
4093 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4095 r_shadow_usingdeferredprepass = false;
4096 if (r_shadow_prepass_width)
4097 R_Shadow_FreeDeferred();
4098 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4102 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4104 R_Shadow_FreeDeferred();
4106 r_shadow_usingdeferredprepass = true;
4107 r_shadow_prepass_width = vid.width;
4108 r_shadow_prepass_height = vid.height;
4109 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4110 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4111 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4112 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4114 // set up the geometry pass fbo (depth + normalmap)
4115 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4116 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4117 // render depth into a renderbuffer and other important properties into the normalmap texture
4119 // set up the lighting pass fbo (diffuse + specular)
4120 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4121 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4122 // render diffuse into one texture and specular into another,
4123 // with depth and normalmap bound as textures,
4124 // with depth bound as attachment as well
4126 // set up the lighting pass fbo (diffuse)
4127 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4128 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4129 // render diffuse into one texture,
4130 // with depth and normalmap bound as textures,
4131 // with depth bound as attachment as well
4135 case RENDERPATH_GLES2:
4136 r_shadow_usingdeferredprepass = false;
4140 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);
4142 r_shadow_scenenumlights = 0;
4143 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4144 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4145 for (lightindex = 0; lightindex < range; lightindex++)
4147 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4148 if (light && (light->flags & flag))
4150 R_Shadow_PrepareLight(&light->rtlight);
4151 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4154 if (r_refdef.scene.rtdlight)
4156 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4158 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4159 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4162 else if (gl_flashblend.integer)
4164 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4166 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4167 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4168 VectorScale(rtlight->color, f, rtlight->currentcolor);
4172 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4173 if (r_shadow_debuglight.integer >= 0)
4175 r_shadow_scenenumlights = 0;
4176 lightindex = r_shadow_debuglight.integer;
4177 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4180 R_Shadow_PrepareLight(&light->rtlight);
4181 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4185 // if we're doing shadowmaps we need to prepare the atlas layout now
4186 if (R_Shadow_ShadowMappingEnabled())
4190 // allocate shadowmaps in the atlas now
4191 // 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...
4192 for (lod = 0; lod < 16; lod++)
4194 int packing_success = 0;
4195 int packing_failure = 0;
4196 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4197 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4198 if (r_shadow_shadowmapatlas_modelshadows_size)
4199 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);
4200 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4202 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4203 int size = rtlight->shadowmapsidesize >> lod;
4205 if (!rtlight->castshadows)
4207 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4210 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4211 if (rtlight->cached_numshadowentities_noselfshadow)
4213 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4215 rtlight->shadowmapatlassidesize = size;
4220 // note down that we failed to pack this one, it will have to disable shadows
4221 rtlight->shadowmapatlassidesize = 0;
4225 // generally everything fits and we stop here on the first iteration
4226 if (packing_failure == 0)
4231 if (r_editlights.integer)
4232 R_Shadow_DrawLightSprites();
4235 void R_Shadow_DrawShadowMaps(void)
4237 R_Shadow_RenderMode_Begin();
4238 R_Shadow_RenderMode_ActiveLight(NULL);
4240 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4241 R_Shadow_ClearShadowMapTexture();
4243 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4244 if (r_shadow_shadowmapatlas_modelshadows_size)
4246 R_Shadow_DrawModelShadowMaps();
4247 // don't let sound skip if going slow
4248 if (r_refdef.scene.extraupdate)
4252 if (R_Shadow_ShadowMappingEnabled())
4255 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4256 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4259 R_Shadow_RenderMode_End();
4262 void R_Shadow_DrawLights(void)
4266 R_Shadow_RenderMode_Begin();
4268 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4269 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4271 R_Shadow_RenderMode_End();
4274 #define MAX_MODELSHADOWS 1024
4275 static int r_shadow_nummodelshadows;
4276 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4278 void R_Shadow_PrepareModelShadows(void)
4281 float scale, size, radius, dot1, dot2;
4282 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4283 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4284 entity_render_t *ent;
4286 r_shadow_nummodelshadows = 0;
4287 r_shadow_shadowmapatlas_modelshadows_size = 0;
4289 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4292 size = r_shadow_shadowmaptexturesize / 4;
4293 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4294 radius = 0.5f * size / scale;
4296 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4297 VectorCopy(prvmshadowdir, shadowdir);
4298 VectorNormalize(shadowdir);
4299 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4300 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4301 if (fabs(dot1) <= fabs(dot2))
4302 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4304 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4305 VectorNormalize(shadowforward);
4306 CrossProduct(shadowdir, shadowforward, shadowright);
4307 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4308 VectorCopy(prvmshadowfocus, shadowfocus);
4309 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4310 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4311 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4312 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4313 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4315 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4317 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4318 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4319 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4320 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4321 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4322 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4324 for (i = 0; i < r_refdef.scene.numentities; i++)
4326 ent = r_refdef.scene.entities[i];
4327 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4329 // cast shadows from anything of the map (submodels are optional)
4330 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4332 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4334 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4335 R_AnimCache_GetEntity(ent, false, false);
4339 if (r_shadow_nummodelshadows)
4341 r_shadow_shadowmapatlas_modelshadows_x = 0;
4342 r_shadow_shadowmapatlas_modelshadows_y = 0;
4343 r_shadow_shadowmapatlas_modelshadows_size = size;
4347 static void R_Shadow_DrawModelShadowMaps(void)
4350 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4351 entity_render_t *ent;
4352 vec3_t relativelightorigin;
4353 vec3_t relativelightdirection, relativeforward, relativeright;
4354 vec3_t relativeshadowmins, relativeshadowmaxs;
4355 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4356 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4358 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4359 r_viewport_t viewport;
4361 size = r_shadow_shadowmapatlas_modelshadows_size;
4362 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4363 radius = 0.5f / scale;
4364 nearclip = -r_shadows_throwdistance.value;
4365 farclip = r_shadows_throwdistance.value;
4366 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);
4368 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4369 r_shadow_modelshadowmap_parameters[0] = size;
4370 r_shadow_modelshadowmap_parameters[1] = size;
4371 r_shadow_modelshadowmap_parameters[2] = 1.0;
4372 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4373 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4374 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4375 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4376 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4377 r_shadow_usingshadowmaportho = true;
4379 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4380 VectorCopy(prvmshadowdir, shadowdir);
4381 VectorNormalize(shadowdir);
4382 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4383 VectorCopy(prvmshadowfocus, shadowfocus);
4384 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4385 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4386 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4387 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4388 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4389 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4390 if (fabs(dot1) <= fabs(dot2))
4391 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4393 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4394 VectorNormalize(shadowforward);
4395 VectorM(scale, shadowforward, &m[0]);
4396 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4398 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4399 CrossProduct(shadowdir, shadowforward, shadowright);
4400 VectorM(scale, shadowright, &m[4]);
4401 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4402 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4403 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4404 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4405 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4406 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);
4407 R_SetViewport(&viewport);
4409 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4411 // render into a slightly restricted region so that the borders of the
4412 // shadowmap area fade away, rather than streaking across everything
4413 // outside the usable area
4414 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4416 for (i = 0;i < r_shadow_nummodelshadows;i++)
4418 ent = r_shadow_modelshadows[i];
4419 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4420 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4421 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4422 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4423 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4424 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4425 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4426 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4427 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4428 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4429 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4430 RSurf_ActiveModelEntity(ent, false, false, false);
4431 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4432 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4438 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4440 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4442 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4443 Cvar_SetValueQuick(&r_test, 0);
4448 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4449 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4450 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4451 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4452 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4453 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4456 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4459 vec3_t centerorigin;
4463 // if it's too close, skip it
4464 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4466 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4469 if (usequery && r_numqueries + 2 <= r_maxqueries)
4471 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4472 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4473 // 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
4474 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4476 switch(vid.renderpath)
4478 case RENDERPATH_GL32:
4479 case RENDERPATH_GLES2:
4482 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4483 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4484 GL_DepthFunc(GL_ALWAYS);
4485 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4486 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4487 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4488 qglEndQuery(GL_SAMPLES_PASSED);
4489 GL_DepthFunc(GL_LEQUAL);
4490 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4491 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4492 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4493 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4494 qglEndQuery(GL_SAMPLES_PASSED);
4500 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4503 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4505 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4508 unsigned int occlude = 0;
4510 // now we have to check the query result
4511 if (rtlight->corona_queryindex_visiblepixels)
4513 switch(vid.renderpath)
4515 case RENDERPATH_GL32:
4516 case RENDERPATH_GLES2:
4518 // store the pixel counts into a uniform buffer for the shader to
4519 // use - we'll never know the results on the cpu without
4520 // synchronizing and we don't want that
4521 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4522 if (!r_shadow_occlusion_buf) {
4523 qglGenBuffers(1, &r_shadow_occlusion_buf);
4524 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4525 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4527 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4529 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4530 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4531 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4532 occlude = MATERIALFLAG_OCCLUDE;
4533 cscale *= rtlight->corona_visibility;
4543 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4546 VectorScale(rtlight->currentcolor, cscale, color);
4547 if (VectorLength(color) > (1.0f / 256.0f))
4550 qboolean negated = (color[0] + color[1] + color[2] < 0);
4553 VectorNegate(color, color);
4554 GL_BlendEquationSubtract(true);
4556 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4557 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);
4558 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4560 GL_BlendEquationSubtract(false);
4564 void R_Shadow_DrawCoronas(void)
4567 qboolean usequery = false;
4572 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4574 if (r_fb.water.renderingscene)
4576 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4577 R_EntityMatrix(&identitymatrix);
4579 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4581 // check occlusion of coronas, using occlusion queries or raytraces
4583 switch (vid.renderpath)
4585 case RENDERPATH_GL32:
4586 case RENDERPATH_GLES2:
4587 usequery = r_coronas_occlusionquery.integer;
4591 GL_ColorMask(0,0,0,0);
4592 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4593 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4596 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4597 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4599 qglGenQueries(r_maxqueries - i, r_queries + i);
4602 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4603 GL_BlendFunc(GL_ONE, GL_ZERO);
4604 GL_CullFace(GL_NONE);
4605 GL_DepthMask(false);
4606 GL_DepthRange(0, 1);
4607 GL_PolygonOffset(0, 0);
4609 R_Mesh_ResetTextureState();
4610 R_SetupShader_Generic_NoTexture(false, false);
4615 for (lightindex = 0;lightindex < range;lightindex++)
4617 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4620 rtlight = &light->rtlight;
4621 rtlight->corona_visibility = 0;
4622 rtlight->corona_queryindex_visiblepixels = 0;
4623 rtlight->corona_queryindex_allpixels = 0;
4624 if (!(rtlight->flags & flag))
4626 if (rtlight->corona <= 0)
4628 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4630 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4632 for (i = 0;i < r_refdef.scene.numlights;i++)
4634 rtlight = r_refdef.scene.lights[i];
4635 rtlight->corona_visibility = 0;
4636 rtlight->corona_queryindex_visiblepixels = 0;
4637 rtlight->corona_queryindex_allpixels = 0;
4638 if (!(rtlight->flags & flag))
4640 if (rtlight->corona <= 0)
4642 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4645 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4647 // now draw the coronas using the query data for intensity info
4648 for (lightindex = 0;lightindex < range;lightindex++)
4650 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4653 rtlight = &light->rtlight;
4654 if (rtlight->corona_visibility <= 0)
4656 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4658 for (i = 0;i < r_refdef.scene.numlights;i++)
4660 rtlight = r_refdef.scene.lights[i];
4661 if (rtlight->corona_visibility <= 0)
4663 if (gl_flashblend.integer)
4664 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4666 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4672 static dlight_t *R_Shadow_NewWorldLight(void)
4674 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4677 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)
4681 // 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
4683 // validate parameters
4687 // copy to light properties
4688 VectorCopy(origin, light->origin);
4689 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4690 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4691 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4693 light->color[0] = max(color[0], 0);
4694 light->color[1] = max(color[1], 0);
4695 light->color[2] = max(color[2], 0);
4697 light->color[0] = color[0];
4698 light->color[1] = color[1];
4699 light->color[2] = color[2];
4700 light->radius = max(radius, 0);
4701 light->style = style;
4702 light->shadow = shadowenable;
4703 light->corona = corona;
4704 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4705 light->coronasizescale = coronasizescale;
4706 light->ambientscale = ambientscale;
4707 light->diffusescale = diffusescale;
4708 light->specularscale = specularscale;
4709 light->flags = flags;
4711 // update renderable light data
4712 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4713 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);
4716 static void R_Shadow_FreeWorldLight(dlight_t *light)
4718 if (r_shadow_selectedlight == light)
4719 r_shadow_selectedlight = NULL;
4720 R_RTLight_Uncompile(&light->rtlight);
4721 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4724 void R_Shadow_ClearWorldLights(void)
4728 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4729 for (lightindex = 0;lightindex < range;lightindex++)
4731 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4733 R_Shadow_FreeWorldLight(light);
4735 r_shadow_selectedlight = NULL;
4738 static void R_Shadow_SelectLight(dlight_t *light)
4740 if (r_shadow_selectedlight)
4741 r_shadow_selectedlight->selected = false;
4742 r_shadow_selectedlight = light;
4743 if (r_shadow_selectedlight)
4744 r_shadow_selectedlight->selected = true;
4747 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4749 // this is never batched (there can be only one)
4751 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4752 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4753 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4756 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4761 skinframe_t *skinframe;
4764 // this is never batched (due to the ent parameter changing every time)
4765 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4766 const dlight_t *light = (dlight_t *)ent;
4769 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4772 VectorScale(light->color, intensity, spritecolor);
4773 if (VectorLength(spritecolor) < 0.1732f)
4774 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4775 if (VectorLength(spritecolor) > 1.0f)
4776 VectorNormalize(spritecolor);
4778 // draw light sprite
4779 if (light->cubemapname[0] && !light->shadow)
4780 skinframe = r_editlights_sprcubemapnoshadowlight;
4781 else if (light->cubemapname[0])
4782 skinframe = r_editlights_sprcubemaplight;
4783 else if (!light->shadow)
4784 skinframe = r_editlights_sprnoshadowlight;
4786 skinframe = r_editlights_sprlight;
4788 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);
4789 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4791 // draw selection sprite if light is selected
4792 if (light->selected)
4794 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4795 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4796 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4800 void R_Shadow_DrawLightSprites(void)
4804 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4805 for (lightindex = 0;lightindex < range;lightindex++)
4807 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4809 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4811 if (!r_editlights_lockcursor)
4812 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4815 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4820 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4821 if (lightindex >= range)
4823 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4826 rtlight = &light->rtlight;
4827 //if (!(rtlight->flags & flag))
4829 VectorCopy(rtlight->shadoworigin, origin);
4830 *radius = rtlight->radius;
4831 VectorCopy(rtlight->color, color);
4835 static void R_Shadow_SelectLightInView(void)
4837 float bestrating, rating, temp[3];
4841 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4845 if (r_editlights_lockcursor)
4847 for (lightindex = 0;lightindex < range;lightindex++)
4849 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4852 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4853 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4856 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4857 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)
4859 bestrating = rating;
4864 R_Shadow_SelectLight(best);
4867 void R_Shadow_LoadWorldLights(void)
4869 int n, a, style, shadow, flags;
4870 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4871 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4872 if (cl.worldmodel == NULL)
4874 Con_Print("No map loaded.\n");
4877 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4878 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4888 for (;COM_Parse(t, true) && strcmp(
4889 if (COM_Parse(t, true))
4891 if (com_token[0] == '!')
4894 origin[0] = atof(com_token+1);
4897 origin[0] = atof(com_token);
4902 while (*s && *s != '\n' && *s != '\r')
4908 // check for modifier flags
4915 #if _MSC_VER >= 1400
4916 #define sscanf sscanf_s
4918 cubemapname[sizeof(cubemapname)-1] = 0;
4919 #if MAX_QPATH != 128
4920 #error update this code if MAX_QPATH changes
4922 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
4923 #if _MSC_VER >= 1400
4924 , (unsigned int)sizeof(cubemapname)
4926 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4929 flags = LIGHTFLAG_REALTIMEMODE;
4937 coronasizescale = 0.25f;
4939 VectorClear(angles);
4942 if (a < 9 || !strcmp(cubemapname, "\"\""))
4944 // remove quotes on cubemapname
4945 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4948 namelen = strlen(cubemapname) - 2;
4949 memmove(cubemapname, cubemapname + 1, namelen);
4950 cubemapname[namelen] = '\0';
4954 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);
4957 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4965 Con_Printf("invalid rtlights file \"%s\"\n", name);
4966 Mem_Free(lightsstring);
4970 void R_Shadow_SaveWorldLights(void)
4974 size_t bufchars, bufmaxchars;
4976 char name[MAX_QPATH];
4977 char line[MAX_INPUTLINE];
4978 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4979 // I hate lines which are 3 times my screen size :( --blub
4982 if (cl.worldmodel == NULL)
4984 Con_Print("No map loaded.\n");
4987 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4988 bufchars = bufmaxchars = 0;
4990 for (lightindex = 0;lightindex < range;lightindex++)
4992 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4995 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4996 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);
4997 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4998 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]);
5000 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);
5001 if (bufchars + strlen(line) > bufmaxchars)
5003 bufmaxchars = bufchars + strlen(line) + 2048;
5005 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5009 memcpy(buf, oldbuf, bufchars);
5015 memcpy(buf + bufchars, line, strlen(line));
5016 bufchars += strlen(line);
5020 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5025 void R_Shadow_LoadLightsFile(void)
5028 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5029 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5030 if (cl.worldmodel == NULL)
5032 Con_Print("No map loaded.\n");
5035 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5036 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5044 while (*s && *s != '\n' && *s != '\r')
5050 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);
5054 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);
5057 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5058 radius = bound(15, radius, 4096);
5059 VectorScale(color, (2.0f / (8388608.0f)), color);
5060 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5068 Con_Printf("invalid lights file \"%s\"\n", name);
5069 Mem_Free(lightsstring);
5073 // tyrlite/hmap2 light types in the delay field
5074 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5076 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5088 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5089 char key[256], value[MAX_INPUTLINE];
5092 if (cl.worldmodel == NULL)
5094 Con_Print("No map loaded.\n");
5097 // try to load a .ent file first
5098 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5099 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5100 // and if that is not found, fall back to the bsp file entity string
5102 data = cl.worldmodel->brush.entities;
5105 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5107 type = LIGHTTYPE_MINUSX;
5108 origin[0] = origin[1] = origin[2] = 0;
5109 originhack[0] = originhack[1] = originhack[2] = 0;
5110 angles[0] = angles[1] = angles[2] = 0;
5111 color[0] = color[1] = color[2] = 1;
5112 light[0] = light[1] = light[2] = 1;light[3] = 300;
5113 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5123 if (!COM_ParseToken_Simple(&data, false, false, true))
5125 if (com_token[0] == '}')
5126 break; // end of entity
5127 if (com_token[0] == '_')
5128 strlcpy(key, com_token + 1, sizeof(key));
5130 strlcpy(key, com_token, sizeof(key));
5131 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5132 key[strlen(key)-1] = 0;
5133 if (!COM_ParseToken_Simple(&data, false, false, true))
5135 strlcpy(value, com_token, sizeof(value));
5137 // now that we have the key pair worked out...
5138 if (!strcmp("light", key))
5140 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5144 light[0] = vec[0] * (1.0f / 256.0f);
5145 light[1] = vec[0] * (1.0f / 256.0f);
5146 light[2] = vec[0] * (1.0f / 256.0f);
5152 light[0] = vec[0] * (1.0f / 255.0f);
5153 light[1] = vec[1] * (1.0f / 255.0f);
5154 light[2] = vec[2] * (1.0f / 255.0f);
5158 else if (!strcmp("delay", key))
5160 else if (!strcmp("origin", key))
5161 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5162 else if (!strcmp("angle", key))
5163 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5164 else if (!strcmp("angles", key))
5165 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5166 else if (!strcmp("color", key))
5167 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5168 else if (!strcmp("wait", key))
5169 fadescale = atof(value);
5170 else if (!strcmp("classname", key))
5172 if (!strncmp(value, "light", 5))
5175 if (!strcmp(value, "light_fluoro"))
5180 overridecolor[0] = 1;
5181 overridecolor[1] = 1;
5182 overridecolor[2] = 1;
5184 if (!strcmp(value, "light_fluorospark"))
5189 overridecolor[0] = 1;
5190 overridecolor[1] = 1;
5191 overridecolor[2] = 1;
5193 if (!strcmp(value, "light_globe"))
5198 overridecolor[0] = 1;
5199 overridecolor[1] = 0.8;
5200 overridecolor[2] = 0.4;
5202 if (!strcmp(value, "light_flame_large_yellow"))
5207 overridecolor[0] = 1;
5208 overridecolor[1] = 0.5;
5209 overridecolor[2] = 0.1;
5211 if (!strcmp(value, "light_flame_small_yellow"))
5216 overridecolor[0] = 1;
5217 overridecolor[1] = 0.5;
5218 overridecolor[2] = 0.1;
5220 if (!strcmp(value, "light_torch_small_white"))
5225 overridecolor[0] = 1;
5226 overridecolor[1] = 0.5;
5227 overridecolor[2] = 0.1;
5229 if (!strcmp(value, "light_torch_small_walltorch"))
5234 overridecolor[0] = 1;
5235 overridecolor[1] = 0.5;
5236 overridecolor[2] = 0.1;
5240 else if (!strcmp("style", key))
5241 style = atoi(value);
5242 else if (!strcmp("skin", key))
5243 skin = (int)atof(value);
5244 else if (!strcmp("pflags", key))
5245 pflags = (int)atof(value);
5246 //else if (!strcmp("effects", key))
5247 // effects = (int)atof(value);
5248 else if (cl.worldmodel->type == mod_brushq3)
5250 if (!strcmp("scale", key))
5251 lightscale = atof(value);
5252 if (!strcmp("fade", key))
5253 fadescale = atof(value);
5258 if (lightscale <= 0)
5262 if (color[0] == color[1] && color[0] == color[2])
5264 color[0] *= overridecolor[0];
5265 color[1] *= overridecolor[1];
5266 color[2] *= overridecolor[2];
5268 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5269 color[0] = color[0] * light[0];
5270 color[1] = color[1] * light[1];
5271 color[2] = color[2] * light[2];
5274 case LIGHTTYPE_MINUSX:
5276 case LIGHTTYPE_RECIPX:
5278 VectorScale(color, (1.0f / 16.0f), color);
5280 case LIGHTTYPE_RECIPXX:
5282 VectorScale(color, (1.0f / 16.0f), color);
5285 case LIGHTTYPE_NONE:
5289 case LIGHTTYPE_MINUSXX:
5292 VectorAdd(origin, originhack, origin);
5294 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);
5297 Mem_Free(entfiledata);
5301 static void R_Shadow_SetCursorLocationForView(void)
5304 vec3_t dest, endpos;
5306 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5307 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5308 if (trace.fraction < 1)
5310 dist = trace.fraction * r_editlights_cursordistance.value;
5311 push = r_editlights_cursorpushback.value;
5315 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5316 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5320 VectorClear( endpos );
5322 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5323 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5324 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5327 void R_Shadow_UpdateWorldLightSelection(void)
5329 if (r_editlights.integer)
5331 R_Shadow_SetCursorLocationForView();
5332 R_Shadow_SelectLightInView();
5335 R_Shadow_SelectLight(NULL);
5338 static void R_Shadow_EditLights_Clear_f(cmd_state_t *cmd)
5340 R_Shadow_ClearWorldLights();
5343 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd)
5347 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5348 R_Shadow_ClearWorldLights();
5349 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5351 R_Shadow_LoadWorldLights();
5352 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5353 R_Shadow_LoadLightsFile();
5355 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5357 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5358 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5362 static void R_Shadow_EditLights_Save_f(cmd_state_t *cmd)
5366 R_Shadow_SaveWorldLights();
5369 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(cmd_state_t *cmd)
5371 R_Shadow_ClearWorldLights();
5372 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5375 static void R_Shadow_EditLights_ImportLightsFile_f(cmd_state_t *cmd)
5377 R_Shadow_ClearWorldLights();
5378 R_Shadow_LoadLightsFile();
5381 static void R_Shadow_EditLights_Spawn_f(cmd_state_t *cmd)
5384 if (!r_editlights.integer)
5386 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5389 if (Cmd_Argc(cmd) != 1)
5391 Con_Print("r_editlights_spawn does not take parameters\n");
5394 color[0] = color[1] = color[2] = 1;
5395 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5398 static void R_Shadow_EditLights_Edit_f(cmd_state_t *cmd)
5400 vec3_t origin, angles, color;
5401 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5402 int style, shadows, flags, normalmode, realtimemode;
5403 char cubemapname[MAX_INPUTLINE];
5404 if (!r_editlights.integer)
5406 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5409 if (!r_shadow_selectedlight)
5411 Con_Print("No selected light.\n");
5414 VectorCopy(r_shadow_selectedlight->origin, origin);
5415 VectorCopy(r_shadow_selectedlight->angles, angles);
5416 VectorCopy(r_shadow_selectedlight->color, color);
5417 radius = r_shadow_selectedlight->radius;
5418 style = r_shadow_selectedlight->style;
5419 if (r_shadow_selectedlight->cubemapname)
5420 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5423 shadows = r_shadow_selectedlight->shadow;
5424 corona = r_shadow_selectedlight->corona;
5425 coronasizescale = r_shadow_selectedlight->coronasizescale;
5426 ambientscale = r_shadow_selectedlight->ambientscale;
5427 diffusescale = r_shadow_selectedlight->diffusescale;
5428 specularscale = r_shadow_selectedlight->specularscale;
5429 flags = r_shadow_selectedlight->flags;
5430 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5431 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5432 if (!strcmp(Cmd_Argv(cmd, 1), "origin"))
5434 if (Cmd_Argc(cmd) != 5)
5436 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5439 origin[0] = atof(Cmd_Argv(cmd, 2));
5440 origin[1] = atof(Cmd_Argv(cmd, 3));
5441 origin[2] = atof(Cmd_Argv(cmd, 4));
5443 else if (!strcmp(Cmd_Argv(cmd, 1), "originscale"))
5445 if (Cmd_Argc(cmd) != 5)
5447 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5450 origin[0] *= atof(Cmd_Argv(cmd, 2));
5451 origin[1] *= atof(Cmd_Argv(cmd, 3));
5452 origin[2] *= atof(Cmd_Argv(cmd, 4));
5454 else if (!strcmp(Cmd_Argv(cmd, 1), "originx"))
5456 if (Cmd_Argc(cmd) != 3)
5458 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5461 origin[0] = atof(Cmd_Argv(cmd, 2));
5463 else if (!strcmp(Cmd_Argv(cmd, 1), "originy"))
5465 if (Cmd_Argc(cmd) != 3)
5467 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5470 origin[1] = atof(Cmd_Argv(cmd, 2));
5472 else if (!strcmp(Cmd_Argv(cmd, 1), "originz"))
5474 if (Cmd_Argc(cmd) != 3)
5476 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5479 origin[2] = atof(Cmd_Argv(cmd, 2));
5481 else if (!strcmp(Cmd_Argv(cmd, 1), "move"))
5483 if (Cmd_Argc(cmd) != 5)
5485 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5488 origin[0] += atof(Cmd_Argv(cmd, 2));
5489 origin[1] += atof(Cmd_Argv(cmd, 3));
5490 origin[2] += atof(Cmd_Argv(cmd, 4));
5492 else if (!strcmp(Cmd_Argv(cmd, 1), "movex"))
5494 if (Cmd_Argc(cmd) != 3)
5496 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5499 origin[0] += atof(Cmd_Argv(cmd, 2));
5501 else if (!strcmp(Cmd_Argv(cmd, 1), "movey"))
5503 if (Cmd_Argc(cmd) != 3)
5505 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5508 origin[1] += atof(Cmd_Argv(cmd, 2));
5510 else if (!strcmp(Cmd_Argv(cmd, 1), "movez"))
5512 if (Cmd_Argc(cmd) != 3)
5514 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5517 origin[2] += atof(Cmd_Argv(cmd, 2));
5519 else if (!strcmp(Cmd_Argv(cmd, 1), "angles"))
5521 if (Cmd_Argc(cmd) != 5)
5523 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5526 angles[0] = atof(Cmd_Argv(cmd, 2));
5527 angles[1] = atof(Cmd_Argv(cmd, 3));
5528 angles[2] = atof(Cmd_Argv(cmd, 4));
5530 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesx"))
5532 if (Cmd_Argc(cmd) != 3)
5534 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5537 angles[0] = atof(Cmd_Argv(cmd, 2));
5539 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesy"))
5541 if (Cmd_Argc(cmd) != 3)
5543 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5546 angles[1] = atof(Cmd_Argv(cmd, 2));
5548 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesz"))
5550 if (Cmd_Argc(cmd) != 3)
5552 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5555 angles[2] = atof(Cmd_Argv(cmd, 2));
5557 else if (!strcmp(Cmd_Argv(cmd, 1), "color"))
5559 if (Cmd_Argc(cmd) != 5)
5561 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(cmd, 1));
5564 color[0] = atof(Cmd_Argv(cmd, 2));
5565 color[1] = atof(Cmd_Argv(cmd, 3));
5566 color[2] = atof(Cmd_Argv(cmd, 4));
5568 else if (!strcmp(Cmd_Argv(cmd, 1), "radius"))
5570 if (Cmd_Argc(cmd) != 3)
5572 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5575 radius = atof(Cmd_Argv(cmd, 2));
5577 else if (!strcmp(Cmd_Argv(cmd, 1), "colorscale"))
5579 if (Cmd_Argc(cmd) == 3)
5581 double scale = atof(Cmd_Argv(cmd, 2));
5588 if (Cmd_Argc(cmd) != 5)
5590 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(cmd, 1));
5593 color[0] *= atof(Cmd_Argv(cmd, 2));
5594 color[1] *= atof(Cmd_Argv(cmd, 3));
5595 color[2] *= atof(Cmd_Argv(cmd, 4));
5598 else if (!strcmp(Cmd_Argv(cmd, 1), "radiusscale") || !strcmp(Cmd_Argv(cmd, 1), "sizescale"))
5600 if (Cmd_Argc(cmd) != 3)
5602 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5605 radius *= atof(Cmd_Argv(cmd, 2));
5607 else if (!strcmp(Cmd_Argv(cmd, 1), "style"))
5609 if (Cmd_Argc(cmd) != 3)
5611 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5614 style = atoi(Cmd_Argv(cmd, 2));
5616 else if (!strcmp(Cmd_Argv(cmd, 1), "cubemap"))
5618 if (Cmd_Argc(cmd) > 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5623 if (Cmd_Argc(cmd) == 3)
5624 strlcpy(cubemapname, Cmd_Argv(cmd, 2), sizeof(cubemapname));
5628 else if (!strcmp(Cmd_Argv(cmd, 1), "shadows"))
5630 if (Cmd_Argc(cmd) != 3)
5632 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5635 shadows = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5637 else if (!strcmp(Cmd_Argv(cmd, 1), "corona"))
5639 if (Cmd_Argc(cmd) != 3)
5641 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5644 corona = atof(Cmd_Argv(cmd, 2));
5646 else if (!strcmp(Cmd_Argv(cmd, 1), "coronasize"))
5648 if (Cmd_Argc(cmd) != 3)
5650 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5653 coronasizescale = atof(Cmd_Argv(cmd, 2));
5655 else if (!strcmp(Cmd_Argv(cmd, 1), "ambient"))
5657 if (Cmd_Argc(cmd) != 3)
5659 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5662 ambientscale = atof(Cmd_Argv(cmd, 2));
5664 else if (!strcmp(Cmd_Argv(cmd, 1), "diffuse"))
5666 if (Cmd_Argc(cmd) != 3)
5668 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5671 diffusescale = atof(Cmd_Argv(cmd, 2));
5673 else if (!strcmp(Cmd_Argv(cmd, 1), "specular"))
5675 if (Cmd_Argc(cmd) != 3)
5677 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5680 specularscale = atof(Cmd_Argv(cmd, 2));
5682 else if (!strcmp(Cmd_Argv(cmd, 1), "normalmode"))
5684 if (Cmd_Argc(cmd) != 3)
5686 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5689 normalmode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5691 else if (!strcmp(Cmd_Argv(cmd, 1), "realtimemode"))
5693 if (Cmd_Argc(cmd) != 3)
5695 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5698 realtimemode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5702 Con_Print("usage: r_editlights_edit [property] [value]\n");
5703 Con_Print("Selected light's properties:\n");
5704 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5705 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5706 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5707 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5708 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5709 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5710 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5711 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5712 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5713 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5714 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5715 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5716 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5717 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5720 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5721 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5724 static void R_Shadow_EditLights_EditAll_f(cmd_state_t *cmd)
5727 dlight_t *light, *oldselected;
5730 if (!r_editlights.integer)
5732 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5736 oldselected = r_shadow_selectedlight;
5737 // EditLights doesn't seem to have a "remove" command or something so:
5738 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5739 for (lightindex = 0;lightindex < range;lightindex++)
5741 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5744 R_Shadow_SelectLight(light);
5745 R_Shadow_EditLights_Edit_f(&cmd_client);
5747 // return to old selected (to not mess editing once selection is locked)
5748 R_Shadow_SelectLight(oldselected);
5751 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5753 int lightnumber, lightcount;
5754 size_t lightindex, range;
5759 if (!r_editlights.integer)
5762 // update cvars so QC can query them
5763 if (r_shadow_selectedlight)
5765 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5766 Cvar_SetQuick(&r_editlights_current_origin, temp);
5767 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5768 Cvar_SetQuick(&r_editlights_current_angles, temp);
5769 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5770 Cvar_SetQuick(&r_editlights_current_color, temp);
5771 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5772 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5773 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5774 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5775 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5776 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5777 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5778 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5779 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5780 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5781 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5784 // draw properties on screen
5785 if (!r_editlights_drawproperties.integer)
5787 x = vid_conwidth.value - 320;
5789 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5792 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5793 for (lightindex = 0;lightindex < range;lightindex++)
5795 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5798 if (light == r_shadow_selectedlight)
5799 lightnumber = (int)lightindex;
5802 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;
5803 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;
5805 if (r_shadow_selectedlight == NULL)
5807 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;
5808 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;
5809 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;
5810 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;
5811 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;
5812 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;
5813 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;
5814 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;
5815 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;
5816 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;
5817 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;
5818 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;
5819 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;
5820 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;
5821 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;
5823 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;
5824 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;
5825 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;
5826 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;
5827 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;
5828 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;
5829 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;
5830 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;
5831 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;
5832 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;
5835 static void R_Shadow_EditLights_ToggleShadow_f(cmd_state_t *cmd)
5837 if (!r_editlights.integer)
5839 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5842 if (!r_shadow_selectedlight)
5844 Con_Print("No selected light.\n");
5847 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);
5850 static void R_Shadow_EditLights_ToggleCorona_f(cmd_state_t *cmd)
5852 if (!r_editlights.integer)
5854 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5857 if (!r_shadow_selectedlight)
5859 Con_Print("No selected light.\n");
5862 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);
5865 static void R_Shadow_EditLights_Remove_f(cmd_state_t *cmd)
5867 if (!r_editlights.integer)
5869 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5872 if (!r_shadow_selectedlight)
5874 Con_Print("No selected light.\n");
5877 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5878 r_shadow_selectedlight = NULL;
5881 static void R_Shadow_EditLights_Help_f(cmd_state_t *cmd)
5884 "Documentation on r_editlights system:\n"
5886 "r_editlights : enable/disable editing mode\n"
5887 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5888 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5889 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5890 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5891 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5893 "r_editlights_help : this help\n"
5894 "r_editlights_clear : remove all lights\n"
5895 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5896 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5897 "r_editlights_save : save to .rtlights file\n"
5898 "r_editlights_spawn : create a light with default settings\n"
5899 "r_editlights_edit command : edit selected light - more documentation below\n"
5900 "r_editlights_remove : remove selected light\n"
5901 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5902 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5903 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5905 "origin x y z : set light location\n"
5906 "originx x: set x component of light location\n"
5907 "originy y: set y component of light location\n"
5908 "originz z: set z component of light location\n"
5909 "move x y z : adjust light location\n"
5910 "movex x: adjust x component of light location\n"
5911 "movey y: adjust y component of light location\n"
5912 "movez z: adjust z component of light location\n"
5913 "angles x y z : set light angles\n"
5914 "anglesx x: set x component of light angles\n"
5915 "anglesy y: set y component of light angles\n"
5916 "anglesz z: set z component of light angles\n"
5917 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5918 "radius radius : set radius (size) of light\n"
5919 "colorscale grey : multiply color of light (1 does nothing)\n"
5920 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5921 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5922 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5923 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5924 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5925 "cubemap basename : set filter cubemap of light\n"
5926 "shadows 1/0 : turn on/off shadows\n"
5927 "corona n : set corona intensity\n"
5928 "coronasize n : set corona size (0-1)\n"
5929 "ambient n : set ambient intensity (0-1)\n"
5930 "diffuse n : set diffuse intensity (0-1)\n"
5931 "specular n : set specular intensity (0-1)\n"
5932 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5933 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5934 "<nothing> : print light properties to console\n"
5938 static void R_Shadow_EditLights_CopyInfo_f(cmd_state_t *cmd)
5940 if (!r_editlights.integer)
5942 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5945 if (!r_shadow_selectedlight)
5947 Con_Print("No selected light.\n");
5950 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5951 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5952 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5953 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5954 if (r_shadow_selectedlight->cubemapname)
5955 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5957 r_shadow_bufferlight.cubemapname[0] = 0;
5958 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5959 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5960 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5961 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5962 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5963 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5964 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5967 static void R_Shadow_EditLights_PasteInfo_f(cmd_state_t *cmd)
5969 if (!r_editlights.integer)
5971 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5974 if (!r_shadow_selectedlight)
5976 Con_Print("No selected light.\n");
5979 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);
5982 static void R_Shadow_EditLights_Lock_f(cmd_state_t *cmd)
5984 if (!r_editlights.integer)
5986 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5989 if (r_editlights_lockcursor)
5991 r_editlights_lockcursor = false;
5994 if (!r_shadow_selectedlight)
5996 Con_Print("No selected light to lock on.\n");
5999 r_editlights_lockcursor = true;
6002 static void R_Shadow_EditLights_Init(void)
6004 Cvar_RegisterVariable(&r_editlights);
6005 Cvar_RegisterVariable(&r_editlights_cursordistance);
6006 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6007 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6008 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6009 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6010 Cvar_RegisterVariable(&r_editlights_drawproperties);
6011 Cvar_RegisterVariable(&r_editlights_current_origin);
6012 Cvar_RegisterVariable(&r_editlights_current_angles);
6013 Cvar_RegisterVariable(&r_editlights_current_color);
6014 Cvar_RegisterVariable(&r_editlights_current_radius);
6015 Cvar_RegisterVariable(&r_editlights_current_corona);
6016 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6017 Cvar_RegisterVariable(&r_editlights_current_style);
6018 Cvar_RegisterVariable(&r_editlights_current_shadows);
6019 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6020 Cvar_RegisterVariable(&r_editlights_current_ambient);
6021 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6022 Cvar_RegisterVariable(&r_editlights_current_specular);
6023 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6024 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6025 Cmd_AddCommand(&cmd_client, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6026 Cmd_AddCommand(&cmd_client, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6027 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)");
6028 Cmd_AddCommand(&cmd_client, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6029 Cmd_AddCommand(&cmd_client, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6030 Cmd_AddCommand(&cmd_client, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6031 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)");
6032 Cmd_AddCommand(&cmd_client, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6033 Cmd_AddCommand(&cmd_client, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6034 Cmd_AddCommand(&cmd_client, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6035 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)");
6036 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)");
6037 Cmd_AddCommand(&cmd_client, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6038 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)");
6039 Cmd_AddCommand(&cmd_client, "r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6045 =============================================================================
6049 =============================================================================
6052 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6054 int i, numlights, flag, q;
6057 float relativepoint[3];
6062 float sa[3], sx[3], sy[3], sz[3], sd[3];
6065 // use first order spherical harmonics to combine directional lights
6066 for (q = 0; q < 3; q++)
6067 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6069 if (flags & LP_LIGHTMAP)
6071 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6073 float tempambient[3];
6074 for (q = 0; q < 3; q++)
6075 tempambient[q] = color[q] = relativepoint[q] = 0;
6076 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6077 // calculate a weighted average light direction as well
6078 intensity = VectorLength(color);
6079 for (q = 0; q < 3; q++)
6081 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6082 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6083 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6084 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6085 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6090 // unlit map - fullbright but scaled by lightmapintensity
6091 for (q = 0; q < 3; q++)
6092 sa[q] += lightmapintensity;
6096 if (flags & LP_RTWORLD)
6098 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6099 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6100 for (i = 0; i < numlights; i++)
6102 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6105 light = &dlight->rtlight;
6106 if (!(light->flags & flag))
6109 lightradius2 = light->radius * light->radius;
6110 VectorSubtract(light->shadoworigin, p, relativepoint);
6111 dist2 = VectorLength2(relativepoint);
6112 if (dist2 >= lightradius2)
6114 dist = sqrt(dist2) / light->radius;
6115 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6116 if (intensity <= 0.0f)
6118 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)
6120 for (q = 0; q < 3; q++)
6121 color[q] = light->currentcolor[q] * intensity;
6122 intensity = VectorLength(color);
6123 VectorNormalize(relativepoint);
6124 for (q = 0; q < 3; q++)
6126 sa[q] += 0.5f * color[q];
6127 sx[q] += relativepoint[0] * color[q];
6128 sy[q] += relativepoint[1] * color[q];
6129 sz[q] += relativepoint[2] * color[q];
6130 sd[q] += intensity * relativepoint[q];
6133 // FIXME: sample bouncegrid too!
6136 if (flags & LP_DYNLIGHT)
6139 for (i = 0;i < r_refdef.scene.numlights;i++)
6141 light = r_refdef.scene.lights[i];
6143 lightradius2 = light->radius * light->radius;
6144 VectorSubtract(light->shadoworigin, p, relativepoint);
6145 dist2 = VectorLength2(relativepoint);
6146 if (dist2 >= lightradius2)
6148 dist = sqrt(dist2) / light->radius;
6149 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6150 if (intensity <= 0.0f)
6152 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)
6154 for (q = 0; q < 3; q++)
6155 color[q] = light->currentcolor[q] * intensity;
6156 intensity = VectorLength(color);
6157 VectorNormalize(relativepoint);
6158 for (q = 0; q < 3; q++)
6160 sa[q] += 0.5f * color[q];
6161 sx[q] += relativepoint[0] * color[q];
6162 sy[q] += relativepoint[1] * color[q];
6163 sz[q] += relativepoint[2] * color[q];
6164 sd[q] += intensity * relativepoint[q];
6169 // calculate the weighted-average light direction (bentnormal)
6170 for (q = 0; q < 3; q++)
6171 lightdir[q] = sd[q];
6172 VectorNormalize(lightdir);
6173 for (q = 0; q < 3; q++)
6175 // extract the diffuse color along the chosen direction and scale it
6176 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6177 // subtract some of diffuse from ambient
6178 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;