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;
1539 float clearcolor[4];
1541 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1543 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1545 R_Mesh_ResetTextureState();
1546 R_Shadow_RenderMode_Reset();
1547 if (r_shadow_shadowmap2ddepthbuffer)
1548 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1550 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1551 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1552 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1557 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1559 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1561 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1562 R_SetViewport(&viewport);
1563 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1564 flipped = (side & 1) ^ (side >> 2);
1565 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1566 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1568 Vector4Set(clearcolor, 1,1,1,1);
1569 if (r_shadow_shadowmap2ddepthbuffer)
1570 GL_ColorMask(1,1,1,1);
1572 GL_ColorMask(0,0,0,0);
1573 switch(vid.renderpath)
1575 case RENDERPATH_GL32:
1576 case RENDERPATH_GLES2:
1577 GL_CullFace(r_refdef.view.cullface_back);
1581 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1582 r_shadow_shadowmapside = side;
1585 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1587 R_Mesh_ResetTextureState();
1590 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1591 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1592 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1593 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1596 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1597 R_Shadow_RenderMode_Reset();
1598 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1600 GL_DepthFunc(GL_EQUAL);
1601 // do global setup needed for the chosen lighting mode
1602 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1603 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1604 r_shadow_usingshadowmap2d = shadowmapping;
1605 r_shadow_rendermode = r_shadow_lightingrendermode;
1608 static const unsigned short bboxelements[36] =
1618 static const float bboxpoints[8][3] =
1630 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1633 float vertex3f[8*3];
1634 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1635 // do global setup needed for the chosen lighting mode
1636 R_Shadow_RenderMode_Reset();
1637 r_shadow_rendermode = r_shadow_lightingrendermode;
1638 R_EntityMatrix(&identitymatrix);
1639 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1640 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1641 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1643 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1645 r_shadow_usingshadowmap2d = shadowmapping;
1647 // render the lighting
1648 R_SetupShader_DeferredLight(rsurface.rtlight);
1649 for (i = 0;i < 8;i++)
1650 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1651 GL_ColorMask(1,1,1,1);
1652 GL_DepthMask(false);
1653 GL_DepthRange(0, 1);
1654 GL_PolygonOffset(0, 0);
1656 GL_DepthFunc(GL_GREATER);
1657 GL_CullFace(r_refdef.view.cullface_back);
1658 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1659 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1662 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1664 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1671 // see if there are really any lights to render...
1672 if (enable && r_shadow_bouncegrid_static.integer)
1675 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1676 for (lightindex = 0;lightindex < range;lightindex++)
1678 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1679 if (!light || !(light->flags & flag))
1681 rtlight = &light->rtlight;
1682 // when static, we skip styled lights because they tend to change...
1683 if (rtlight->style > 0)
1685 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1686 if (!VectorLength2(lightcolor))
1696 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1698 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1699 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1700 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1701 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1703 // prevent any garbage in alignment padded areas as we'll be using memcmp
1704 memset(settings, 0, sizeof(*settings));
1706 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1707 settings->staticmode = s;
1708 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1709 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1710 settings->lightpathsize = bound(0.0f, r_shadow_bouncegrid_lightpathsize.value, 1024.0f);
1711 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1712 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1713 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1714 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1715 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1716 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1717 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1718 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) / 65536.0f;
1719 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1720 settings->energyperphoton = 4096.0f / quality;
1721 settings->spacing[0] = spacing;
1722 settings->spacing[1] = spacing;
1723 settings->spacing[2] = spacing;
1724 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1725 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1726 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1727 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1728 settings->subsamples = bound(1, r_shadow_bouncegrid_subsamples.integer, 4);
1730 // bound the values for sanity
1731 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1732 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1733 settings->maxbounce = bound(0, settings->maxbounce, 16);
1734 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1735 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1736 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1739 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1750 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1752 // get the spacing values
1753 spacing[0] = settings->spacing[0];
1754 spacing[1] = settings->spacing[1];
1755 spacing[2] = settings->spacing[2];
1756 ispacing[0] = 1.0f / spacing[0];
1757 ispacing[1] = 1.0f / spacing[1];
1758 ispacing[2] = 1.0f / spacing[2];
1760 // calculate texture size enclosing entire world bounds at the spacing
1761 if (r_refdef.scene.worldmodel)
1765 qboolean bounds_set = false;
1769 // calculate bounds enclosing world lights as they should be noticably tighter
1770 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1771 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1772 for (lightindex = 0;lightindex < range;lightindex++)
1774 const vec_t *rtlmins, *rtlmaxs;
1776 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1780 rtlight = &light->rtlight;
1781 rtlmins = rtlight->cullmins;
1782 rtlmaxs = rtlight->cullmaxs;
1786 VectorCopy(rtlmins, mins);
1787 VectorCopy(rtlmaxs, maxs);
1792 mins[0] = min(mins[0], rtlmins[0]);
1793 mins[1] = min(mins[1], rtlmins[1]);
1794 mins[2] = min(mins[2], rtlmins[2]);
1795 maxs[0] = max(maxs[0], rtlmaxs[0]);
1796 maxs[1] = max(maxs[1], rtlmaxs[1]);
1797 maxs[2] = max(maxs[2], rtlmaxs[2]);
1801 // limit to no larger than the world bounds
1802 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1803 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1804 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1805 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1806 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1807 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1809 VectorMA(mins, -2.0f, spacing, mins);
1810 VectorMA(maxs, 2.0f, spacing, maxs);
1814 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1815 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1817 VectorSubtract(maxs, mins, size);
1818 // now we can calculate the resolution we want
1819 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1820 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1821 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1822 // figure out the exact texture size (honoring power of 2 if required)
1823 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1824 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1825 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1826 size[0] = spacing[0] * resolution[0];
1827 size[1] = spacing[1] * resolution[1];
1828 size[2] = spacing[2] * resolution[2];
1830 // if dynamic we may or may not want to use the world bounds
1831 // if the dynamic size is smaller than the world bounds, use it instead
1832 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]))
1834 // we know the resolution we want
1835 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1836 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1837 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1838 // now we can calculate the texture size
1839 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1840 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1841 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1842 size[0] = spacing[0] * resolution[0];
1843 size[1] = spacing[1] * resolution[1];
1844 size[2] = spacing[2] * resolution[2];
1845 // center the rendering on the view
1846 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1847 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1848 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1851 // recalculate the maxs in case the resolution was not satisfactory
1852 VectorAdd(mins, size, maxs);
1854 // check if this changed the texture size
1855 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);
1856 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1857 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1858 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1859 VectorCopy(size, r_shadow_bouncegrid_state.size);
1860 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1861 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1862 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1864 // reallocate pixels for this update if needed...
1865 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1866 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1867 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1868 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1869 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1871 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1873 r_shadow_bouncegrid_state.highpixels = NULL;
1875 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1876 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1877 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1878 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1879 if (r_shadow_bouncegrid_state.photons) { Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL; }
1880 if (r_shadow_bouncegrid_state.photons_tasks) { Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL; }
1881 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
1883 r_shadow_bouncegrid_state.numpixels = numpixels;
1886 // update the bouncegrid matrix to put it in the world properly
1887 memset(m, 0, sizeof(m));
1888 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1889 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1890 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1891 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1892 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1893 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1895 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1898 static float R_Shadow_BounceGrid_RefractiveIndexAtPoint(vec3_t point)
1900 // check material at shadoworigin to see what the initial refractive index should be
1901 int hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
1902 int skipsupercontentsmask = 0;
1903 int skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
1904 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);
1905 if (trace.starttexture && (trace.starttexture->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)))
1906 return trace.starttexture->refractive_index;
1907 else if (trace.startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
1908 return 1.333f; // water
1910 return 1.0003f; // air
1913 // enumerate world rtlights and sum the overall amount of light in the world,
1914 // from that we can calculate a scaling factor to fairly distribute photons
1915 // to all the lights
1917 // this modifies rtlight->photoncolor and rtlight->photons
1918 static void R_Shadow_BounceGrid_AssignPhotons_Task(taskqueue_task_t *t)
1920 // get the range of light numbers we'll be looping over:
1921 // range = static lights
1922 // range1 = dynamic lights (optional)
1923 // range2 = range + range1
1924 unsigned int range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1925 unsigned int range1 = r_shadow_bouncegrid_state.settings.staticmode ? 0 : r_refdef.scene.numlights;
1926 unsigned int range2 = range + range1;
1927 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
1929 float normalphotonscaling;
1930 float photonscaling;
1931 float photonintensity;
1932 float photoncount = 0.0f;
1933 float lightintensity;
1939 unsigned int lightindex;
1944 float bounceminimumintensity2;
1945 float startrefractiveindex;
1947 randomseed_t randomseed;
1948 vec3_t baseshotcolor;
1950 normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1951 for (lightindex = 0;lightindex < range2;lightindex++)
1953 if (lightindex < range)
1955 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1958 rtlight = &light->rtlight;
1959 VectorClear(rtlight->bouncegrid_photoncolor);
1960 rtlight->bouncegrid_photons = 0;
1961 rtlight->bouncegrid_hits = 0;
1962 rtlight->bouncegrid_traces = 0;
1963 rtlight->bouncegrid_effectiveradius = 0;
1964 if (!(light->flags & flag))
1966 if (r_shadow_bouncegrid_state.settings.staticmode)
1968 // when static, we skip styled lights because they tend to change...
1969 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
1972 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
1977 rtlight = r_refdef.scene.lights[lightindex - range];
1978 VectorClear(rtlight->bouncegrid_photoncolor);
1979 rtlight->bouncegrid_photons = 0;
1980 rtlight->bouncegrid_hits = 0;
1981 rtlight->bouncegrid_traces = 0;
1982 rtlight->bouncegrid_effectiveradius = 0;
1984 // draw only visible lights (major speedup)
1985 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
1986 cullmins[0] = rtlight->shadoworigin[0] - radius;
1987 cullmins[1] = rtlight->shadoworigin[1] - radius;
1988 cullmins[2] = rtlight->shadoworigin[2] - radius;
1989 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
1990 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
1991 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
1992 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
1993 if (!r_shadow_bouncegrid_state.settings.staticmode)
1995 // skip if the expanded light box does not touch any visible leafs
1996 if (r_refdef.scene.worldmodel
1997 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
1998 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2000 // skip if the expanded light box is not visible to traceline
2001 // note that PrepareLight already did this check but for a smaller box, so we
2002 // end up casting more traces per frame per light when using bouncegrid, which
2003 // is probably fine (and they use the same timer)
2004 if (r_shadow_culllights_trace.integer)
2006 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))
2007 rtlight->trace_timer = realtime;
2008 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2011 // skip if expanded light box is offscreen
2012 if (R_CullBox(cullmins, cullmaxs))
2014 // skip if overall light intensity is zero
2015 if (w * VectorLength2(rtlight->color) == 0.0f)
2018 // a light that does not emit any light before style is applied, can be
2019 // skipped entirely (it may just be a corona)
2020 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2022 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2023 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2024 // skip lights that will emit no photons
2025 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2027 // shoot particles from this light
2028 // use a calculation for the number of particles that will not
2029 // vary with lightstyle, otherwise we get randomized particle
2030 // distribution, the seeded random is only consistent for a
2031 // consistent number of particles on this light...
2032 s = rtlight->radius;
2033 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2034 if (lightindex >= range)
2035 lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2036 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2037 photoncount += rtlight->bouncegrid_photons;
2038 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2039 // if the lightstyle happens to be off right now, we can skip actually
2040 // firing the photons, but we did have to count them in the total.
2041 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2042 // rtlight->bouncegrid_photons = 0;
2044 // the user provided an energyperphoton value which we try to use
2045 // if that results in too many photons to shoot this frame, then we cap it
2046 // which causes photons to appear/disappear from frame to frame, so we don't
2047 // like doing that in the typical case
2048 photonscaling = 1.0f;
2049 photonintensity = 1.0f;
2050 if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2052 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2053 photonintensity = 1.0f / photonscaling;
2056 // modify the lights to reflect our computed scaling
2057 for (lightindex = 0; lightindex < range2; lightindex++)
2059 if (lightindex < range)
2061 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2064 rtlight = &light->rtlight;
2067 rtlight = r_refdef.scene.lights[lightindex - range];
2068 rtlight->bouncegrid_photons *= photonscaling;
2069 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2072 // compute a seed for the unstable random modes
2073 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2074 seed = realtime * 1000.0;
2076 for (lightindex = 0; lightindex < range2; lightindex++)
2078 if (lightindex < range)
2080 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2083 rtlight = &light->rtlight;
2086 rtlight = r_refdef.scene.lights[lightindex - range];
2087 // note that this code used to keep track of residual photons and
2088 // distribute them evenly to achieve exactly a desired photon count,
2089 // but that caused unwanted flickering in dynamic mode
2090 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2091 // skip if we won't be shooting any photons
2092 if (!shootparticles)
2094 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2095 //s = settings.particleintensity / shootparticles;
2096 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2097 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2098 if (VectorLength2(baseshotcolor) <= 0.0f)
2100 r_refdef.stats[r_stat_bouncegrid_lights]++;
2101 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2102 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2103 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2105 // check material at shadoworigin to see what the initial refractive index should be
2106 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2108 // for seeded random we start the RNG with the position of the light
2109 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2117 u.f[0] = rtlight->shadoworigin[0];
2118 u.f[1] = rtlight->shadoworigin[1];
2119 u.f[2] = rtlight->shadoworigin[2];
2121 switch (r_shadow_bouncegrid_state.settings.rng_type)
2125 // we have to shift the seed provided by the user because the result must be odd
2126 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2129 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2134 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2136 r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2137 VectorCopy(baseshotcolor, p->color);
2138 VectorCopy(rtlight->shadoworigin, p->start);
2139 switch (r_shadow_bouncegrid_state.settings.rng_type)
2143 // figure out a random direction for the initial photon to go
2144 VectorLehmerRandom(&randomseed, p->end);
2147 // figure out a random direction for the initial photon to go
2148 VectorCheeseRandom(seed, p->end);
2152 // we want a uniform distribution spherically, not merely within the sphere
2153 if (r_shadow_bouncegrid_state.settings.normalizevectors)
2154 VectorNormalize(p->end);
2156 VectorMA(p->start, radius, p->end, p->end);
2157 p->bounceminimumintensity2 = bounceminimumintensity2;
2158 p->startrefractiveindex = startrefractiveindex;
2166 static void R_Shadow_BounceGrid_Slice(int zi)
2168 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2169 int xi, yi; // pixel increments
2170 float color[32] = { 0 };
2171 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2172 float iradius = 1.0f / radius;
2173 int slicemins[3], slicemaxs[3];
2175 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2176 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2178 int samples = r_shadow_bouncegrid_state.settings.subsamples;
2179 float isamples = 1.0f / samples;
2180 float samplescolorscale = isamples * isamples * isamples;
2182 // we use these a lot, so get a local copy
2183 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2185 for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2187 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2189 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2191 r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2192 float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2194 VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2195 VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2197 pathmins[2] = min(pathstart[2], pathend[2]);
2198 slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2199 pathmaxs[2] = max(pathstart[2], pathend[2]);
2200 slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2202 // skip if the path doesn't touch this slice
2203 if (zi < slicemins[2] || zi >= slicemaxs[2])
2206 pathmins[0] = min(pathstart[0], pathend[0]);
2207 slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2208 slicemins[0] = max(slicemins[0], 1);
2209 pathmaxs[0] = max(pathstart[0], pathend[0]);
2210 slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2211 slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2213 pathmins[1] = min(pathstart[1], pathend[1]);
2214 slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2215 slicemins[1] = max(slicemins[1], 1);
2216 pathmaxs[1] = max(pathstart[1], pathend[1]);
2217 slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2218 slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2220 // skip if the path is out of bounds on X or Y
2221 if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2224 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2225 // accumulate average shotcolor
2226 VectorSubtract(pathend, pathstart, pathdelta);
2227 pathlength2 = VectorLength2(pathdelta);
2228 pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2229 VectorScale(pathdelta, pathilength, pathdir);
2230 // the color is scaled by the number of subsamples
2231 color[0] = path->color[0] * samplescolorscale;
2232 color[1] = path->color[1] * samplescolorscale;
2233 color[2] = path->color[2] * samplescolorscale;
2237 // store bentnormal in case the shader has a use for it,
2238 // bentnormal is an intensity-weighted average of the directions,
2239 // and will be normalized on conversion to texture pixels.
2240 float intensity = VectorLength(color);
2241 color[4] = pathdir[0] * intensity;
2242 color[5] = pathdir[1] * intensity;
2243 color[6] = pathdir[2] * intensity;
2244 color[7] = intensity;
2245 // for each color component (R, G, B) calculate the amount that a
2246 // direction contributes
2247 color[8] = color[0] * max(0.0f, pathdir[0]);
2248 color[9] = color[0] * max(0.0f, pathdir[1]);
2249 color[10] = color[0] * max(0.0f, pathdir[2]);
2251 color[12] = color[1] * max(0.0f, pathdir[0]);
2252 color[13] = color[1] * max(0.0f, pathdir[1]);
2253 color[14] = color[1] * max(0.0f, pathdir[2]);
2255 color[16] = color[2] * max(0.0f, pathdir[0]);
2256 color[17] = color[2] * max(0.0f, pathdir[1]);
2257 color[18] = color[2] * max(0.0f, pathdir[2]);
2259 // and do the same for negative directions
2260 color[20] = color[0] * max(0.0f, -pathdir[0]);
2261 color[21] = color[0] * max(0.0f, -pathdir[1]);
2262 color[22] = color[0] * max(0.0f, -pathdir[2]);
2264 color[24] = color[1] * max(0.0f, -pathdir[0]);
2265 color[25] = color[1] * max(0.0f, -pathdir[1]);
2266 color[26] = color[1] * max(0.0f, -pathdir[2]);
2268 color[28] = color[2] * max(0.0f, -pathdir[0]);
2269 color[29] = color[2] * max(0.0f, -pathdir[1]);
2270 color[30] = color[2] * max(0.0f, -pathdir[2]);
2274 for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2276 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2278 float sample[3], diff[3], nearest[3], along, distance2;
2279 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2281 // loop over the subsamples
2282 for (zs = 0; zs < samples; zs++)
2284 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2285 for (ys = 0; ys < samples; ys++)
2287 sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2288 for (xs = 0; xs < samples; xs++)
2290 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2292 // measure distance from subsample to line segment and see if it is within radius
2293 along = DotProduct(sample, pathdir) * pathilength;
2295 VectorCopy(pathstart, nearest);
2296 else if (along >= 1)
2297 VectorCopy(pathend, nearest);
2299 VectorLerp(pathstart, along, pathend, nearest);
2300 VectorSubtract(sample, nearest, diff);
2301 VectorScale(diff, iradius, diff);
2302 distance2 = VectorLength2(diff);
2303 if (distance2 < 1.0f)
2305 // contribute some color to this pixel, across all bands
2306 float w = 1.0f - sqrt(distance2);
2311 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2312 p[pixelsperband * 4 + 3] += color[7] * w;
2314 for (band = 0; band < pixelbands; band++)
2316 // add to the pixel color (RGB only - see above)
2317 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2318 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2319 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2331 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2333 R_Shadow_BounceGrid_Slice((int)t->i[0]);
2337 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2340 // we need to wait for the texture clear to finish before we start adding light to it
2341 if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2346 slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2347 for (i = 0; i < slices; i++)
2348 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2349 TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2350 TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2351 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2355 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2357 const float *inpixel;
2359 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2362 unsigned int x, y, z;
2363 unsigned int resolution[3];
2364 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2365 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2367 for (z = 1;z < resolution[2]-1;z++)
2369 for (y = 1;y < resolution[1]-1;y++)
2372 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2373 inpixel = inpixels + 4*index;
2374 outpixel = outpixels + 4*index;
2375 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2377 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2378 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2379 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2380 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2387 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2390 unsigned int resolution[3];
2391 if (r_shadow_bouncegrid_state.settings.blur)
2393 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2395 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2396 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2397 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2398 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2401 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2403 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2405 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2407 // toggle the state, highpixels now points to pixels[3] result
2408 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2409 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2414 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2416 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2417 unsigned char *pixelsbgra8 = NULL;
2418 unsigned char *pixelbgra8;
2419 unsigned short *pixelsrgba16f = NULL;
2420 unsigned short *pixelrgba16f;
2421 float *pixelsrgba32f = NULL;
2422 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2425 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2426 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2427 unsigned int pixelband;
2428 unsigned int x, y, z;
2429 unsigned int index, bandindex;
2430 unsigned int resolution[3];
2432 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2434 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2436 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2437 r_shadow_bouncegrid_state.texture = NULL;
2440 // if bentnormals exist, we need to normalize and bias them for the shader
2444 for (z = 0;z < resolution[2]-1;z++)
2446 for (y = 0;y < resolution[1]-1;y++)
2449 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2450 highpixel = highpixels + 4*index;
2451 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2453 // only convert pixels that were hit by photons
2454 if (highpixel[3] != 0.0f)
2455 VectorNormalize(highpixel);
2456 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2457 highpixel[pixelsperband * 4 + 3] = 1.0f;
2463 // start by clearing the pixels array - we won't be writing to all of it
2465 // then process only the pixels that have at least some color, skipping
2466 // the higher bands for speed on pixels that are black
2467 switch (floatcolors)
2470 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2471 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2472 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2473 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2476 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2478 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2480 for (z = 1;z < resolution[2]-1;z++)
2482 for (y = 1;y < resolution[1]-1;y++)
2486 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2487 highpixel = highpixels + 4*index;
2488 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2490 // only convert pixels that were hit by photons
2491 if (VectorLength2(highpixel))
2493 // normalize the bentnormal now
2496 VectorNormalize(highpixel + pixelsperband * 4);
2497 highpixel[pixelsperband * 4 + 3] = 1.0f;
2499 // process all of the pixelbands for this pixel
2500 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2502 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2503 bandpixel = highpixels + 4*bandindex;
2504 c[0] = (int)(bandpixel[0]*256.0f);
2505 c[1] = (int)(bandpixel[1]*256.0f);
2506 c[2] = (int)(bandpixel[2]*256.0f);
2507 c[3] = (int)(bandpixel[3]*256.0f);
2508 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2509 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2510 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2511 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2518 if (!r_shadow_bouncegrid_state.createtexture)
2519 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2521 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);
2524 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2525 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2526 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2527 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2528 for (z = 1;z < resolution[2]-1;z++)
2530 for (y = 1;y < resolution[1]-1;y++)
2534 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2535 highpixel = highpixels + 4*index;
2536 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2538 // only convert pixels that were hit by photons
2539 if (VectorLength2(highpixel))
2541 // process all of the pixelbands for this pixel
2542 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2544 // time to have fun with IEEE 754 bit hacking...
2547 unsigned int raw[4];
2549 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2550 bandpixel = highpixels + 4*bandindex;
2551 VectorCopy4(bandpixel, u.f);
2552 VectorCopy4(u.raw, c);
2553 // this math supports negative numbers, snaps denormals to zero
2554 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2555 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2556 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2557 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2558 // this math does not support negative
2559 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2560 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2561 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2562 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2569 if (!r_shadow_bouncegrid_state.createtexture)
2570 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2572 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);
2575 // our native format happens to match, so this is easy.
2576 pixelsrgba32f = highpixels;
2578 if (!r_shadow_bouncegrid_state.createtexture)
2579 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2581 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);
2585 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2588 void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2590 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2594 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)
2596 int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2598 vec3_t surfacenormal;
2599 vec3_t reflectstart, reflectend, reflectcolor;
2600 vec3_t refractstart, refractend, refractcolor;
2602 float reflectamount = 1.0f;
2604 // figure out what we want to interact with
2605 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2606 skipsupercontentsmask = 0;
2607 skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2608 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2609 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2610 if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2612 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2613 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2614 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);
2618 // dynamic mode fires many rays and most will match the cache from the previous frame
2619 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);
2621 VectorCopy(cliptrace.endpos, shothit);
2622 if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2624 qboolean notculled = true;
2625 // cull paths that fail R_CullBox in dynamic mode
2626 if (!r_shadow_bouncegrid_state.settings.staticmode
2627 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2629 vec3_t cullmins, cullmaxs;
2630 cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2631 cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2632 cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2633 cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2634 cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2635 cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2636 if (R_CullBox(cullmins, cullmaxs))
2641 r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2642 VectorCopy(shotstart, path->start);
2643 VectorCopy(shothit, path->end);
2644 VectorCopy(shotcolor, path->color);
2647 if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2649 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2650 // also clamp the resulting color to never add energy, even if the user requests extreme values
2651 VectorCopy(cliptrace.plane.normal, surfacenormal);
2652 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2653 VectorClear(refractcolor);
2654 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2655 if (cliptrace.hittexture)
2657 if (cliptrace.hittexture->currentskinframe)
2658 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2659 if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2661 reflectamount *= cliptrace.hittexture->currentalpha;
2662 if (cliptrace.hittexture->currentskinframe)
2663 reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2665 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2669 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2670 VectorSubtract(shotstart, shotend, lightdir);
2671 VectorNormalize(lightdir);
2672 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2673 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2674 reflectamount *= Fresnel;
2675 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2677 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2678 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2679 // make sure we do not gain energy even if surface colors are out of bounds
2680 reflectcolor[0] = min(reflectcolor[0], 1.0f);
2681 reflectcolor[1] = min(reflectcolor[1], 1.0f);
2682 reflectcolor[2] = min(reflectcolor[2], 1.0f);
2683 refractcolor[0] = min(refractcolor[0], 1.0f);
2684 refractcolor[1] = min(refractcolor[1], 1.0f);
2685 refractcolor[2] = min(refractcolor[2], 1.0f);
2687 // reflected and refracted shots
2688 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2689 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2690 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2691 VectorMultiply(refractcolor, shotcolor, refractcolor);
2693 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2695 // reflect the remaining portion of the line across plane normal
2696 VectorSubtract(shotend, shothit, reflectend);
2697 VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2698 // calculate the new line start and end
2699 VectorCopy(shothit, reflectstart);
2700 VectorAdd(reflectstart, reflectend, reflectend);
2701 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2704 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2706 // Check what refractive index is on the other side
2707 float refractiveindex;
2708 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2709 refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2710 // reflect the remaining portion of the line across plane normal
2711 VectorSubtract(shotend, shothit, refractend);
2712 s = refractiveindex / previousrefractiveindex;
2713 VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2714 // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2715 // calculate the new line start and end
2716 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2717 VectorAdd(refractstart, refractend, refractend);
2718 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2723 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2725 r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2726 R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2730 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2733 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2734 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2735 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);
2736 if (r_shadow_bouncegrid_threaded.integer)
2738 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2739 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2743 // when not threaded we still have to report task status
2744 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2745 r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2746 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2751 void R_Shadow_UpdateBounceGridTexture(void)
2753 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2754 r_shadow_bouncegrid_settings_t settings;
2755 qboolean enable = false;
2756 qboolean settingschanged;
2758 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2760 R_Shadow_BounceGrid_GenerateSettings(&settings);
2762 // changing intensity does not require an update
2763 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2765 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2767 // when settings change, we free everything as it is just simpler that way.
2768 if (settingschanged || !enable)
2770 // not enabled, make sure we free anything we don't need anymore.
2771 if (r_shadow_bouncegrid_state.texture)
2773 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2774 r_shadow_bouncegrid_state.texture = NULL;
2776 r_shadow_bouncegrid_state.highpixels = NULL;
2777 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2778 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2779 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2780 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2781 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2782 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2783 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2784 r_shadow_bouncegrid_state.numpixels = 0;
2785 r_shadow_bouncegrid_state.numphotons = 0;
2786 r_shadow_bouncegrid_state.directional = false;
2792 // if all the settings seem identical to the previous update, return
2793 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2796 // store the new settings
2797 r_shadow_bouncegrid_state.settings = settings;
2799 R_Shadow_BounceGrid_UpdateSpacing();
2801 // allocate the highpixels array we'll be accumulating light into
2802 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2803 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2804 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2805 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2806 r_shadow_bouncegrid_state.highpixels_index = 0;
2807 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2809 // set up the tracking of photon data
2810 if (r_shadow_bouncegrid_state.photons == NULL)
2811 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));
2812 if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2813 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2814 r_shadow_bouncegrid_state.numphotons = 0;
2816 // set up the tracking of slice tasks
2817 if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2818 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2820 memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2821 memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2822 memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2823 memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2824 memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2825 memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2826 memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2827 memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2828 memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2830 // clear the texture
2831 TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2832 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2834 // calculate weighting factors for distributing photons among the lights
2835 TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2836 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2838 // enqueue tasks to trace the photons from lights
2839 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2840 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2842 // accumulate the light paths into texture
2843 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);
2844 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2846 // apply a mild blur filter to the texture
2847 TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2848 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2850 TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2851 R_TimeReport("bouncegrid_gen");
2853 // convert the pixels to lower precision and upload the texture
2854 // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2855 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2856 R_TimeReport("bouncegrid_tex");
2858 // after we compute the static lighting we don't need to keep the highpixels array around
2859 if (settings.staticmode)
2861 r_shadow_bouncegrid_state.highpixels = NULL;
2862 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2863 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2864 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2865 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2866 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2867 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2868 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2872 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2874 R_Shadow_RenderMode_Reset();
2875 GL_BlendFunc(GL_ONE, GL_ONE);
2876 GL_DepthRange(0, 1);
2877 GL_DepthTest(r_showlighting.integer < 2);
2878 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2880 GL_DepthFunc(GL_EQUAL);
2881 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2884 void R_Shadow_RenderMode_End(void)
2886 R_Shadow_RenderMode_Reset();
2887 R_Shadow_RenderMode_ActiveLight(NULL);
2889 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2890 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2893 int bboxedges[12][2] =
2912 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2914 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2916 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2917 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2918 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2919 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2922 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2923 return true; // invisible
2924 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2925 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2926 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2927 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2928 r_refdef.stats[r_stat_lights_scissored]++;
2932 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2934 // used to display how many times a surface is lit for level design purposes
2935 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2936 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2940 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])
2942 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2943 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2947 extern cvar_t gl_lightmaps;
2948 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2951 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2952 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2953 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2954 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2955 if (!r_shadow_usenormalmap.integer)
2957 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2958 VectorClear(diffusecolor);
2959 VectorClear(specularcolor);
2961 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2962 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2963 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2964 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2966 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2969 VectorNegate(ambientcolor, ambientcolor);
2970 VectorNegate(diffusecolor, diffusecolor);
2971 VectorNegate(specularcolor, specularcolor);
2972 GL_BlendEquationSubtract(true);
2974 RSurf_SetupDepthAndCulling();
2975 switch (r_shadow_rendermode)
2977 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2978 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2979 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2981 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2982 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2985 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2989 GL_BlendEquationSubtract(false);
2992 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)
2994 matrix4x4_t tempmatrix = *matrix;
2995 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2997 // if this light has been compiled before, free the associated data
2998 R_RTLight_Uncompile(rtlight);
3000 // clear it completely to avoid any lingering data
3001 memset(rtlight, 0, sizeof(*rtlight));
3003 // copy the properties
3004 rtlight->matrix_lighttoworld = tempmatrix;
3005 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3006 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3007 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3008 VectorCopy(color, rtlight->color);
3009 rtlight->cubemapname[0] = 0;
3010 if (cubemapname && cubemapname[0])
3011 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3012 rtlight->shadow = shadow;
3013 rtlight->corona = corona;
3014 rtlight->style = style;
3015 rtlight->isstatic = isstatic;
3016 rtlight->coronasizescale = coronasizescale;
3017 rtlight->ambientscale = ambientscale;
3018 rtlight->diffusescale = diffusescale;
3019 rtlight->specularscale = specularscale;
3020 rtlight->flags = flags;
3022 // compute derived data
3023 //rtlight->cullradius = rtlight->radius;
3024 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3025 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3026 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3027 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3028 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3029 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3030 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3033 // compiles rtlight geometry
3034 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3035 void R_RTLight_Compile(rtlight_t *rtlight)
3038 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3039 int lighttris, shadowtris;
3040 entity_render_t *ent = r_refdef.scene.worldentity;
3041 dp_model_t *model = r_refdef.scene.worldmodel;
3042 unsigned char *data;
3044 // compile the light
3045 rtlight->compiled = true;
3046 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3047 rtlight->static_numleafs = 0;
3048 rtlight->static_numleafpvsbytes = 0;
3049 rtlight->static_leaflist = NULL;
3050 rtlight->static_leafpvs = NULL;
3051 rtlight->static_numsurfaces = 0;
3052 rtlight->static_surfacelist = NULL;
3053 rtlight->static_shadowmap_receivers = 0x3F;
3054 rtlight->static_shadowmap_casters = 0x3F;
3055 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3056 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3057 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3058 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3059 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3060 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3062 if (model && model->GetLightInfo)
3064 // this variable must be set for the CompileShadowMap code
3065 r_shadow_compilingrtlight = rtlight;
3066 R_FrameData_SetMark();
3067 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);
3068 R_FrameData_ReturnToMark();
3069 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3070 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3071 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3072 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3073 rtlight->static_numsurfaces = numsurfaces;
3074 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3075 rtlight->static_numleafs = numleafs;
3076 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3077 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3078 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3079 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3080 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3081 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3082 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3083 if (rtlight->static_numsurfaces)
3084 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3085 if (rtlight->static_numleafs)
3086 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3087 if (rtlight->static_numleafpvsbytes)
3088 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3089 if (rtlight->static_numshadowtrispvsbytes)
3090 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3091 if (rtlight->static_numlighttrispvsbytes)
3092 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3093 R_FrameData_SetMark();
3094 if (model->CompileShadowMap && rtlight->shadow)
3095 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3096 R_FrameData_ReturnToMark();
3097 // now we're done compiling the rtlight
3098 r_shadow_compilingrtlight = NULL;
3102 // use smallest available cullradius - box radius or light radius
3103 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3104 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3107 if (rtlight->static_numlighttrispvsbytes)
3108 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3109 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3113 if (rtlight->static_numshadowtrispvsbytes)
3114 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3115 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3118 if (developer_extra.integer)
3119 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);
3122 void R_RTLight_Uncompile(rtlight_t *rtlight)
3124 if (rtlight->compiled)
3126 if (rtlight->static_meshchain_shadow_shadowmap)
3127 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3128 rtlight->static_meshchain_shadow_shadowmap = NULL;
3129 // these allocations are grouped
3130 if (rtlight->static_surfacelist)
3131 Mem_Free(rtlight->static_surfacelist);
3132 rtlight->static_numleafs = 0;
3133 rtlight->static_numleafpvsbytes = 0;
3134 rtlight->static_leaflist = NULL;
3135 rtlight->static_leafpvs = NULL;
3136 rtlight->static_numsurfaces = 0;
3137 rtlight->static_surfacelist = NULL;
3138 rtlight->static_numshadowtrispvsbytes = 0;
3139 rtlight->static_shadowtrispvs = NULL;
3140 rtlight->static_numlighttrispvsbytes = 0;
3141 rtlight->static_lighttrispvs = NULL;
3142 rtlight->compiled = false;
3146 void R_Shadow_UncompileWorldLights(void)
3150 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3151 for (lightindex = 0;lightindex < range;lightindex++)
3153 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3156 R_RTLight_Uncompile(&light->rtlight);
3160 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3164 // reset the count of frustum planes
3165 // see rtlight->cached_frustumplanes definition for how much this array
3167 rtlight->cached_numfrustumplanes = 0;
3169 if (r_trippy.integer)
3172 // haven't implemented a culling path for ortho rendering
3173 if (!r_refdef.view.useperspective)
3175 // check if the light is on screen and copy the 4 planes if it is
3176 for (i = 0;i < 4;i++)
3177 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3180 for (i = 0;i < 4;i++)
3181 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3186 // generate a deformed frustum that includes the light origin, this is
3187 // used to cull shadow casting surfaces that can not possibly cast a
3188 // shadow onto the visible light-receiving surfaces, which can be a
3191 // if the light origin is onscreen the result will be 4 planes exactly
3192 // if the light origin is offscreen on only one axis the result will
3193 // be exactly 5 planes (split-side case)
3194 // if the light origin is offscreen on two axes the result will be
3195 // exactly 4 planes (stretched corner case)
3196 for (i = 0;i < 4;i++)
3198 // quickly reject standard frustum planes that put the light
3199 // origin outside the frustum
3200 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3203 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3205 // if all the standard frustum planes were accepted, the light is onscreen
3206 // otherwise we need to generate some more planes below...
3207 if (rtlight->cached_numfrustumplanes < 4)
3209 // at least one of the stock frustum planes failed, so we need to
3210 // create one or two custom planes to enclose the light origin
3211 for (i = 0;i < 4;i++)
3213 // create a plane using the view origin and light origin, and a
3214 // single point from the frustum corner set
3215 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3216 VectorNormalize(plane.normal);
3217 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3218 // see if this plane is backwards and flip it if so
3219 for (j = 0;j < 4;j++)
3220 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3224 VectorNegate(plane.normal, plane.normal);
3226 // flipped plane, test again to see if it is now valid
3227 for (j = 0;j < 4;j++)
3228 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3230 // if the plane is still not valid, then it is dividing the
3231 // frustum and has to be rejected
3235 // we have created a valid plane, compute extra info
3236 PlaneClassify(&plane);
3238 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3240 // if we've found 5 frustum planes then we have constructed a
3241 // proper split-side case and do not need to keep searching for
3242 // planes to enclose the light origin
3243 if (rtlight->cached_numfrustumplanes == 5)
3251 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3253 plane = rtlight->cached_frustumplanes[i];
3254 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));
3259 // now add the light-space box planes if the light box is rotated, as any
3260 // caster outside the oriented light box is irrelevant (even if it passed
3261 // the worldspace light box, which is axial)
3262 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3264 for (i = 0;i < 6;i++)
3268 v[i >> 1] = (i & 1) ? -1 : 1;
3269 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3270 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3271 plane.dist = VectorNormalizeLength(plane.normal);
3272 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3273 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3279 // add the world-space reduced box planes
3280 for (i = 0;i < 6;i++)
3282 VectorClear(plane.normal);
3283 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3284 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3285 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3294 // reduce all plane distances to tightly fit the rtlight cull box, which
3296 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3297 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3298 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3299 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3300 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3301 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3302 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3303 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3304 oldnum = rtlight->cached_numfrustumplanes;
3305 rtlight->cached_numfrustumplanes = 0;
3306 for (j = 0;j < oldnum;j++)
3308 // find the nearest point on the box to this plane
3309 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3310 for (i = 1;i < 8;i++)
3312 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3313 if (bestdist > dist)
3316 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);
3317 // if the nearest point is near or behind the plane, we want this
3318 // plane, otherwise the plane is useless as it won't cull anything
3319 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3321 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3322 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3329 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3331 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3333 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3335 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3336 if (mesh->sidetotals[r_shadow_shadowmapside])
3339 GL_CullFace(GL_NONE);
3340 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3341 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3342 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);
3346 else if (r_refdef.scene.worldentity->model)
3347 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);
3349 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3352 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3354 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3355 vec_t relativeshadowradius;
3356 RSurf_ActiveModelEntity(ent, false, false, false);
3357 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3358 // we need to re-init the shader for each entity because the matrix changed
3359 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3360 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3361 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3362 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3363 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3364 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3365 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3366 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3367 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3370 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3372 // set up properties for rendering light onto this entity
3373 RSurf_ActiveModelEntity(ent, true, true, false);
3374 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3375 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3376 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3377 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3380 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3382 if (!r_refdef.scene.worldmodel->DrawLight)
3385 // set up properties for rendering light onto this entity
3386 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3387 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3388 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3389 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3390 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3392 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3394 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3397 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3399 dp_model_t *model = ent->model;
3400 if (!model->DrawLight)
3403 R_Shadow_SetupEntityLight(ent);
3405 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3407 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3410 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3414 int numleafs, numsurfaces;
3415 int *leaflist, *surfacelist;
3416 unsigned char *leafpvs;
3417 unsigned char *shadowtrispvs;
3418 unsigned char *lighttrispvs;
3419 //unsigned char *surfacesides;
3420 int numlightentities;
3421 int numlightentities_noselfshadow;
3422 int numshadowentities;
3423 int numshadowentities_noselfshadow;
3424 // FIXME: bounds check lightentities and shadowentities, etc.
3425 static entity_render_t *lightentities[MAX_EDICTS];
3426 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3427 static entity_render_t *shadowentities[MAX_EDICTS];
3428 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3430 qboolean castshadows;
3432 rtlight->draw = false;
3433 rtlight->cached_numlightentities = 0;
3434 rtlight->cached_numlightentities_noselfshadow = 0;
3435 rtlight->cached_numshadowentities = 0;
3436 rtlight->cached_numshadowentities_noselfshadow = 0;
3437 rtlight->cached_numsurfaces = 0;
3438 rtlight->cached_lightentities = NULL;
3439 rtlight->cached_lightentities_noselfshadow = NULL;
3440 rtlight->cached_shadowentities = NULL;
3441 rtlight->cached_shadowentities_noselfshadow = NULL;
3442 rtlight->cached_shadowtrispvs = NULL;
3443 rtlight->cached_lighttrispvs = NULL;
3444 rtlight->cached_surfacelist = NULL;
3445 rtlight->shadowmapsidesize = 0;
3447 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3448 // skip lights that are basically invisible (color 0 0 0)
3449 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3451 // loading is done before visibility checks because loading should happen
3452 // all at once at the start of a level, not when it stalls gameplay.
3453 // (especially important to benchmarks)
3455 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3457 if (rtlight->compiled)
3458 R_RTLight_Uncompile(rtlight);
3459 R_RTLight_Compile(rtlight);
3463 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3465 // look up the light style value at this time
3466 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3467 VectorScale(rtlight->color, f, rtlight->currentcolor);
3469 if (rtlight->selected)
3471 f = 2 + sin(realtime * M_PI * 4.0);
3472 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3476 // skip if lightstyle is currently off
3477 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3480 // skip processing on corona-only lights
3484 // skip if the light box is not touching any visible leafs
3485 if (r_shadow_culllights_pvs.integer
3486 && r_refdef.scene.worldmodel
3487 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3488 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3491 // skip if the light box is not visible to traceline
3492 if (r_shadow_culllights_trace.integer)
3494 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))
3495 rtlight->trace_timer = realtime;
3496 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3500 // skip if the light box is off screen
3501 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3504 // in the typical case this will be quickly replaced by GetLightInfo
3505 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3506 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3508 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3510 // 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
3511 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3514 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3516 // compiled light, world available and can receive realtime lighting
3517 // retrieve leaf information
3518 numleafs = rtlight->static_numleafs;
3519 leaflist = rtlight->static_leaflist;
3520 leafpvs = rtlight->static_leafpvs;
3521 numsurfaces = rtlight->static_numsurfaces;
3522 surfacelist = rtlight->static_surfacelist;
3523 //surfacesides = NULL;
3524 shadowtrispvs = rtlight->static_shadowtrispvs;
3525 lighttrispvs = rtlight->static_lighttrispvs;
3527 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3529 // dynamic light, world available and can receive realtime lighting
3530 // calculate lit surfaces and leafs
3531 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);
3532 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3533 leaflist = r_shadow_buffer_leaflist;
3534 leafpvs = r_shadow_buffer_leafpvs;
3535 surfacelist = r_shadow_buffer_surfacelist;
3536 //surfacesides = r_shadow_buffer_surfacesides;
3537 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3538 lighttrispvs = r_shadow_buffer_lighttrispvs;
3539 // if the reduced leaf bounds are offscreen, skip it
3540 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3551 //surfacesides = NULL;
3552 shadowtrispvs = NULL;
3553 lighttrispvs = NULL;
3555 // check if light is illuminating any visible leafs
3558 for (i = 0; i < numleafs; i++)
3559 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3565 // make a list of lit entities and shadow casting entities
3566 numlightentities = 0;
3567 numlightentities_noselfshadow = 0;
3568 numshadowentities = 0;
3569 numshadowentities_noselfshadow = 0;
3571 // add dynamic entities that are lit by the light
3572 for (i = 0; i < r_refdef.scene.numentities; i++)
3575 entity_render_t *ent = r_refdef.scene.entities[i];
3577 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3579 // skip the object entirely if it is not within the valid
3580 // shadow-casting region (which includes the lit region)
3581 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3583 if (!(model = ent->model))
3585 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3587 // this entity wants to receive light, is visible, and is
3588 // inside the light box
3589 // TODO: check if the surfaces in the model can receive light
3590 // so now check if it's in a leaf seen by the light
3591 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))
3593 if (ent->flags & RENDER_NOSELFSHADOW)
3594 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3596 lightentities[numlightentities++] = ent;
3597 // since it is lit, it probably also casts a shadow...
3598 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3599 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3600 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3602 // note: exterior models without the RENDER_NOSELFSHADOW
3603 // flag still create a RENDER_NOSELFSHADOW shadow but
3604 // are lit normally, this means that they are
3605 // self-shadowing but do not shadow other
3606 // RENDER_NOSELFSHADOW entities such as the gun
3607 // (very weird, but keeps the player shadow off the gun)
3608 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3609 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3611 shadowentities[numshadowentities++] = ent;
3614 else if (ent->flags & RENDER_SHADOW)
3616 // this entity is not receiving light, but may still need to
3618 // TODO: check if the surfaces in the model can cast shadow
3619 // now check if it is in a leaf seen by the light
3620 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))
3622 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3623 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3624 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3626 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3627 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3629 shadowentities[numshadowentities++] = ent;
3634 // return if there's nothing at all to light
3635 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3638 // count this light in the r_speeds
3639 r_refdef.stats[r_stat_lights]++;
3641 // flag it as worth drawing later
3642 rtlight->draw = true;
3644 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3645 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3647 numshadowentities = numshadowentities_noselfshadow = 0;
3648 rtlight->castshadows = castshadows;
3650 // cache all the animated entities that cast a shadow but are not visible
3651 for (i = 0; i < numshadowentities; i++)
3652 R_AnimCache_GetEntity(shadowentities[i], false, false);
3653 for (i = 0; i < numshadowentities_noselfshadow; i++)
3654 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3656 // 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)
3657 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3659 for (i = 0; i < numshadowentities_noselfshadow; i++)
3660 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3661 numshadowentities_noselfshadow = 0;
3664 // we can convert noselfshadow to regular if there are no casters of that type
3665 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3667 for (i = 0; i < numlightentities_noselfshadow; i++)
3668 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3669 numlightentities_noselfshadow = 0;
3672 // allocate some temporary memory for rendering this light later in the frame
3673 // reusable buffers need to be copied, static data can be used as-is
3674 rtlight->cached_numlightentities = numlightentities;
3675 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3676 rtlight->cached_numshadowentities = numshadowentities;
3677 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3678 rtlight->cached_numsurfaces = numsurfaces;
3679 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3680 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3681 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3682 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3683 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3685 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3686 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3687 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3688 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3689 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3693 // compiled light data
3694 rtlight->cached_shadowtrispvs = shadowtrispvs;
3695 rtlight->cached_lighttrispvs = lighttrispvs;
3696 rtlight->cached_surfacelist = surfacelist;
3699 if (R_Shadow_ShadowMappingEnabled())
3701 // figure out the shadowmapping parameters for this light
3702 vec3_t nearestpoint;
3705 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3706 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3707 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3708 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3709 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3710 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3711 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3712 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3713 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3717 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3721 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3722 int numlightentities;
3723 int numlightentities_noselfshadow;
3724 int numshadowentities;
3725 int numshadowentities_noselfshadow;
3726 entity_render_t **lightentities;
3727 entity_render_t **lightentities_noselfshadow;
3728 entity_render_t **shadowentities;
3729 entity_render_t **shadowentities_noselfshadow;
3731 static unsigned char entitysides[MAX_EDICTS];
3732 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3738 matrix4x4_t radiustolight;
3740 // check if we cached this light this frame (meaning it is worth drawing)
3741 if (!rtlight->draw || !rtlight->castshadows)
3744 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3745 if (rtlight->shadowmapatlassidesize == 0)
3747 rtlight->castshadows = false;
3751 // set up a scissor rectangle for this light
3752 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3755 // don't let sound skip if going slow
3756 if (r_refdef.scene.extraupdate)
3759 numlightentities = rtlight->cached_numlightentities;
3760 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3761 numshadowentities = rtlight->cached_numshadowentities;
3762 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3763 numsurfaces = rtlight->cached_numsurfaces;
3764 lightentities = rtlight->cached_lightentities;
3765 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3766 shadowentities = rtlight->cached_shadowentities;
3767 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3768 shadowtrispvs = rtlight->cached_shadowtrispvs;
3769 lighttrispvs = rtlight->cached_lighttrispvs;
3770 surfacelist = rtlight->cached_surfacelist;
3772 // make this the active rtlight for rendering purposes
3773 R_Shadow_RenderMode_ActiveLight(rtlight);
3775 radiustolight = rtlight->matrix_worldtolight;
3776 Matrix4x4_Abs(&radiustolight);
3778 size = rtlight->shadowmapatlassidesize;
3779 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3781 surfacesides = NULL;
3786 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3788 castermask = rtlight->static_shadowmap_casters;
3789 receivermask = rtlight->static_shadowmap_receivers;
3793 surfacesides = r_shadow_buffer_surfacesides;
3794 for (i = 0; i < numsurfaces; i++)
3796 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3797 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3798 castermask |= surfacesides[i];
3799 receivermask |= surfacesides[i];
3804 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3805 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3806 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3807 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3809 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3813 for (i = 0; i < numshadowentities; i++)
3814 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3815 for (i = 0; i < numshadowentities_noselfshadow; i++)
3816 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3819 // there is no need to render shadows for sides that have no receivers...
3820 castermask &= receivermask;
3822 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3824 // render shadow casters into shadowmaps for this light
3825 for (side = 0; side < 6; side++)
3827 int bit = 1 << side;
3828 if (castermask & bit)
3830 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3832 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3833 for (i = 0; i < numshadowentities; i++)
3834 if (entitysides[i] & bit)
3835 R_Shadow_DrawEntityShadow(shadowentities[i]);
3836 for (i = 0; i < numshadowentities_noselfshadow; i++)
3837 if (entitysides_noselfshadow[i] & bit)
3838 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3841 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3842 if (numshadowentities_noselfshadow)
3844 for (side = 0; side < 6; side++)
3846 int bit = 1 << side;
3847 if (castermask & bit)
3849 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3851 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3852 for (i = 0; i < numshadowentities; i++)
3853 if (entitysides[i] & bit)
3854 R_Shadow_DrawEntityShadow(shadowentities[i]);
3860 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3864 unsigned char *shadowtrispvs, *lighttrispvs;
3865 int numlightentities;
3866 int numlightentities_noselfshadow;
3867 int numshadowentities;
3868 int numshadowentities_noselfshadow;
3869 entity_render_t **lightentities;
3870 entity_render_t **lightentities_noselfshadow;
3871 entity_render_t **shadowentities;
3872 entity_render_t **shadowentities_noselfshadow;
3874 qboolean castshadows;
3876 // check if we cached this light this frame (meaning it is worth drawing)
3880 // set up a scissor rectangle for this light
3881 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3884 // don't let sound skip if going slow
3885 if (r_refdef.scene.extraupdate)
3888 numlightentities = rtlight->cached_numlightentities;
3889 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3890 numshadowentities = rtlight->cached_numshadowentities;
3891 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3892 numsurfaces = rtlight->cached_numsurfaces;
3893 lightentities = rtlight->cached_lightentities;
3894 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3895 shadowentities = rtlight->cached_shadowentities;
3896 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3897 shadowtrispvs = rtlight->cached_shadowtrispvs;
3898 lighttrispvs = rtlight->cached_lighttrispvs;
3899 surfacelist = rtlight->cached_surfacelist;
3900 castshadows = rtlight->castshadows;
3902 // make this the active rtlight for rendering purposes
3903 R_Shadow_RenderMode_ActiveLight(rtlight);
3905 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3907 // optionally draw the illuminated areas
3908 // for performance analysis by level designers
3909 R_Shadow_RenderMode_VisibleLighting(false);
3911 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3912 for (i = 0;i < numlightentities;i++)
3913 R_Shadow_DrawEntityLight(lightentities[i]);
3914 for (i = 0;i < numlightentities_noselfshadow;i++)
3915 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3918 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3922 float shadowmapoffsetnoselfshadow = 0;
3923 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3924 Matrix4x4_Abs(&radiustolight);
3926 size = rtlight->shadowmapatlassidesize;
3927 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3929 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3931 if (rtlight->cached_numshadowentities_noselfshadow)
3932 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3934 // render lighting using the depth texture as shadowmap
3935 // draw lighting in the unmasked areas
3936 if (numsurfaces + numlightentities)
3938 R_Shadow_RenderMode_Lighting(false, true, false);
3939 // draw lighting in the unmasked areas
3941 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3942 for (i = 0; i < numlightentities; i++)
3943 R_Shadow_DrawEntityLight(lightentities[i]);
3945 // offset to the noselfshadow part of the atlas and draw those too
3946 if (numlightentities_noselfshadow)
3948 R_Shadow_RenderMode_Lighting(false, true, true);
3949 for (i = 0; i < numlightentities_noselfshadow; i++)
3950 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3953 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3954 if (r_shadow_usingdeferredprepass)
3955 R_Shadow_RenderMode_DrawDeferredLight(true);
3959 // draw lighting in the unmasked areas
3960 R_Shadow_RenderMode_Lighting(false, false, false);
3962 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3963 for (i = 0;i < numlightentities;i++)
3964 R_Shadow_DrawEntityLight(lightentities[i]);
3965 for (i = 0;i < numlightentities_noselfshadow;i++)
3966 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3968 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3969 if (r_shadow_usingdeferredprepass)
3970 R_Shadow_RenderMode_DrawDeferredLight(false);
3974 static void R_Shadow_FreeDeferred(void)
3976 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3977 r_shadow_prepassgeometryfbo = 0;
3979 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3980 r_shadow_prepasslightingdiffusespecularfbo = 0;
3982 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3983 r_shadow_prepasslightingdiffusefbo = 0;
3985 if (r_shadow_prepassgeometrydepthbuffer)
3986 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3987 r_shadow_prepassgeometrydepthbuffer = NULL;
3989 if (r_shadow_prepassgeometrynormalmaptexture)
3990 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3991 r_shadow_prepassgeometrynormalmaptexture = NULL;
3993 if (r_shadow_prepasslightingdiffusetexture)
3994 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3995 r_shadow_prepasslightingdiffusetexture = NULL;
3997 if (r_shadow_prepasslightingspeculartexture)
3998 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3999 r_shadow_prepasslightingspeculartexture = NULL;
4002 void R_Shadow_DrawPrepass(void)
4006 entity_render_t *ent;
4007 float clearcolor[4];
4009 R_Mesh_ResetTextureState();
4011 GL_ColorMask(1,1,1,1);
4012 GL_BlendFunc(GL_ONE, GL_ZERO);
4015 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4016 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4017 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4018 if (r_timereport_active)
4019 R_TimeReport("prepasscleargeom");
4021 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4022 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4023 if (r_timereport_active)
4024 R_TimeReport("prepassworld");
4026 for (i = 0;i < r_refdef.scene.numentities;i++)
4028 if (!r_refdef.viewcache.entityvisible[i])
4030 ent = r_refdef.scene.entities[i];
4031 if (ent->model && ent->model->DrawPrepass != NULL)
4032 ent->model->DrawPrepass(ent);
4035 if (r_timereport_active)
4036 R_TimeReport("prepassmodels");
4038 GL_DepthMask(false);
4039 GL_ColorMask(1,1,1,1);
4042 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4043 Vector4Set(clearcolor, 0, 0, 0, 0);
4044 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4045 if (r_timereport_active)
4046 R_TimeReport("prepassclearlit");
4048 R_Shadow_RenderMode_Begin();
4050 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4051 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4053 R_Shadow_RenderMode_End();
4055 if (r_timereport_active)
4056 R_TimeReport("prepasslights");
4059 #define MAX_SCENELIGHTS 65536
4060 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4062 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4064 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4066 r_shadow_scenemaxlights *= 2;
4067 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4068 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4070 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4074 void R_Shadow_DrawLightSprites(void);
4075 void R_Shadow_PrepareLights(void)
4084 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4085 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4086 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4088 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4089 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4090 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4091 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4092 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4093 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4094 r_shadow_shadowmapborder != shadowmapborder ||
4095 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4096 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4097 R_Shadow_FreeShadowMaps();
4099 r_shadow_usingshadowmaportho = false;
4101 switch (vid.renderpath)
4103 case RENDERPATH_GL32:
4105 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4107 r_shadow_usingdeferredprepass = false;
4108 if (r_shadow_prepass_width)
4109 R_Shadow_FreeDeferred();
4110 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4114 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4116 R_Shadow_FreeDeferred();
4118 r_shadow_usingdeferredprepass = true;
4119 r_shadow_prepass_width = vid.width;
4120 r_shadow_prepass_height = vid.height;
4121 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4122 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);
4123 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);
4124 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);
4126 // set up the geometry pass fbo (depth + normalmap)
4127 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4128 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4129 // render depth into a renderbuffer and other important properties into the normalmap texture
4131 // set up the lighting pass fbo (diffuse + specular)
4132 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4133 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4134 // render diffuse into one texture and specular into another,
4135 // with depth and normalmap bound as textures,
4136 // with depth bound as attachment as well
4138 // set up the lighting pass fbo (diffuse)
4139 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4140 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4141 // render diffuse into one texture,
4142 // with depth and normalmap bound as textures,
4143 // with depth bound as attachment as well
4147 case RENDERPATH_GLES2:
4148 r_shadow_usingdeferredprepass = false;
4152 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);
4154 r_shadow_scenenumlights = 0;
4155 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4156 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4157 for (lightindex = 0; lightindex < range; lightindex++)
4159 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4160 if (light && (light->flags & flag))
4162 R_Shadow_PrepareLight(&light->rtlight);
4163 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4166 if (r_refdef.scene.rtdlight)
4168 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4170 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4171 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4174 else if (gl_flashblend.integer)
4176 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4178 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4179 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4180 VectorScale(rtlight->color, f, rtlight->currentcolor);
4184 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4185 if (r_shadow_debuglight.integer >= 0)
4187 r_shadow_scenenumlights = 0;
4188 lightindex = r_shadow_debuglight.integer;
4189 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4192 R_Shadow_PrepareLight(&light->rtlight);
4193 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4197 // if we're doing shadowmaps we need to prepare the atlas layout now
4198 if (R_Shadow_ShadowMappingEnabled())
4202 // allocate shadowmaps in the atlas now
4203 // 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...
4204 for (lod = 0; lod < 16; lod++)
4206 int packing_success = 0;
4207 int packing_failure = 0;
4208 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4209 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4210 if (r_shadow_shadowmapatlas_modelshadows_size)
4211 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);
4212 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4214 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4215 int size = rtlight->shadowmapsidesize >> lod;
4217 if (!rtlight->castshadows)
4219 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4222 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4223 if (rtlight->cached_numshadowentities_noselfshadow)
4225 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4227 rtlight->shadowmapatlassidesize = size;
4232 // note down that we failed to pack this one, it will have to disable shadows
4233 rtlight->shadowmapatlassidesize = 0;
4237 // generally everything fits and we stop here on the first iteration
4238 if (packing_failure == 0)
4243 if (r_editlights.integer)
4244 R_Shadow_DrawLightSprites();
4247 void R_Shadow_DrawShadowMaps(void)
4249 R_Shadow_RenderMode_Begin();
4250 R_Shadow_RenderMode_ActiveLight(NULL);
4252 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4253 R_Shadow_ClearShadowMapTexture();
4255 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4256 if (r_shadow_shadowmapatlas_modelshadows_size)
4258 R_Shadow_DrawModelShadowMaps();
4259 // don't let sound skip if going slow
4260 if (r_refdef.scene.extraupdate)
4264 if (R_Shadow_ShadowMappingEnabled())
4267 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4268 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4271 R_Shadow_RenderMode_End();
4274 void R_Shadow_DrawLights(void)
4278 R_Shadow_RenderMode_Begin();
4280 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4281 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4283 R_Shadow_RenderMode_End();
4286 #define MAX_MODELSHADOWS 1024
4287 static int r_shadow_nummodelshadows;
4288 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4290 void R_Shadow_PrepareModelShadows(void)
4293 float scale, size, radius, dot1, dot2;
4294 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4295 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4296 entity_render_t *ent;
4298 r_shadow_nummodelshadows = 0;
4299 r_shadow_shadowmapatlas_modelshadows_size = 0;
4301 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4304 size = r_shadow_shadowmaptexturesize / 4;
4305 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4306 radius = 0.5f * size / scale;
4308 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4309 VectorCopy(prvmshadowdir, shadowdir);
4310 VectorNormalize(shadowdir);
4311 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4312 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4313 if (fabs(dot1) <= fabs(dot2))
4314 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4316 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4317 VectorNormalize(shadowforward);
4318 CrossProduct(shadowdir, shadowforward, shadowright);
4319 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4320 VectorCopy(prvmshadowfocus, shadowfocus);
4321 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4322 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4323 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4324 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4325 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4327 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4329 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4330 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4331 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4332 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4333 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4334 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4336 for (i = 0; i < r_refdef.scene.numentities; i++)
4338 ent = r_refdef.scene.entities[i];
4339 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4341 // cast shadows from anything of the map (submodels are optional)
4342 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4344 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4346 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4347 R_AnimCache_GetEntity(ent, false, false);
4351 if (r_shadow_nummodelshadows)
4353 r_shadow_shadowmapatlas_modelshadows_x = 0;
4354 r_shadow_shadowmapatlas_modelshadows_y = 0;
4355 r_shadow_shadowmapatlas_modelshadows_size = size;
4359 static void R_Shadow_DrawModelShadowMaps(void)
4362 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4363 entity_render_t *ent;
4364 vec3_t relativelightorigin;
4365 vec3_t relativelightdirection, relativeforward, relativeright;
4366 vec3_t relativeshadowmins, relativeshadowmaxs;
4367 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4368 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4370 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4371 r_viewport_t viewport;
4373 size = r_shadow_shadowmapatlas_modelshadows_size;
4374 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4375 radius = 0.5f / scale;
4376 nearclip = -r_shadows_throwdistance.value;
4377 farclip = r_shadows_throwdistance.value;
4378 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);
4380 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4381 r_shadow_modelshadowmap_parameters[0] = size;
4382 r_shadow_modelshadowmap_parameters[1] = size;
4383 r_shadow_modelshadowmap_parameters[2] = 1.0;
4384 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4385 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4386 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4387 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4388 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4389 r_shadow_usingshadowmaportho = true;
4391 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4392 VectorCopy(prvmshadowdir, shadowdir);
4393 VectorNormalize(shadowdir);
4394 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4395 VectorCopy(prvmshadowfocus, shadowfocus);
4396 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4397 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4398 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4399 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4400 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4401 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4402 if (fabs(dot1) <= fabs(dot2))
4403 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4405 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4406 VectorNormalize(shadowforward);
4407 VectorM(scale, shadowforward, &m[0]);
4408 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4410 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4411 CrossProduct(shadowdir, shadowforward, shadowright);
4412 VectorM(scale, shadowright, &m[4]);
4413 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4414 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4415 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4416 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4417 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4418 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);
4419 R_SetViewport(&viewport);
4421 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4423 // render into a slightly restricted region so that the borders of the
4424 // shadowmap area fade away, rather than streaking across everything
4425 // outside the usable area
4426 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4428 for (i = 0;i < r_shadow_nummodelshadows;i++)
4430 ent = r_shadow_modelshadows[i];
4431 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4432 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4433 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4434 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4435 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4436 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4437 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4438 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4439 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4440 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4441 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4442 RSurf_ActiveModelEntity(ent, false, false, false);
4443 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4444 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4450 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4452 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4454 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4455 Cvar_SetValueQuick(&r_test, 0);
4460 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4461 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4462 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4463 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4464 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4465 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4468 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4471 vec3_t centerorigin;
4475 // if it's too close, skip it
4476 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4478 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4481 if (usequery && r_numqueries + 2 <= r_maxqueries)
4483 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4484 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4485 // 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
4486 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4488 switch(vid.renderpath)
4490 case RENDERPATH_GL32:
4491 case RENDERPATH_GLES2:
4494 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4495 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4496 GL_DepthFunc(GL_ALWAYS);
4497 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4498 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4499 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4500 qglEndQuery(GL_SAMPLES_PASSED);
4501 GL_DepthFunc(GL_LEQUAL);
4502 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4503 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4504 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4505 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4506 qglEndQuery(GL_SAMPLES_PASSED);
4512 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4515 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4517 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4520 unsigned int occlude = 0;
4522 // now we have to check the query result
4523 if (rtlight->corona_queryindex_visiblepixels)
4525 switch(vid.renderpath)
4527 case RENDERPATH_GL32:
4528 case RENDERPATH_GLES2:
4530 // store the pixel counts into a uniform buffer for the shader to
4531 // use - we'll never know the results on the cpu without
4532 // synchronizing and we don't want that
4533 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4534 if (!r_shadow_occlusion_buf) {
4535 qglGenBuffers(1, &r_shadow_occlusion_buf);
4536 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4537 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4539 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4541 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4542 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4543 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4544 occlude = MATERIALFLAG_OCCLUDE;
4545 cscale *= rtlight->corona_visibility;
4555 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4558 VectorScale(rtlight->currentcolor, cscale, color);
4559 if (VectorLength(color) > (1.0f / 256.0f))
4562 qboolean negated = (color[0] + color[1] + color[2] < 0);
4565 VectorNegate(color, color);
4566 GL_BlendEquationSubtract(true);
4568 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4569 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);
4570 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4572 GL_BlendEquationSubtract(false);
4576 void R_Shadow_DrawCoronas(void)
4579 qboolean usequery = false;
4584 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4586 if (r_fb.water.renderingscene)
4588 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4589 R_EntityMatrix(&identitymatrix);
4591 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4593 // check occlusion of coronas, using occlusion queries or raytraces
4595 switch (vid.renderpath)
4597 case RENDERPATH_GL32:
4598 case RENDERPATH_GLES2:
4599 usequery = r_coronas_occlusionquery.integer;
4603 GL_ColorMask(0,0,0,0);
4604 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4605 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4608 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4609 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4611 qglGenQueries(r_maxqueries - i, r_queries + i);
4614 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4615 GL_BlendFunc(GL_ONE, GL_ZERO);
4616 GL_CullFace(GL_NONE);
4617 GL_DepthMask(false);
4618 GL_DepthRange(0, 1);
4619 GL_PolygonOffset(0, 0);
4621 R_Mesh_ResetTextureState();
4622 R_SetupShader_Generic_NoTexture(false, false);
4627 for (lightindex = 0;lightindex < range;lightindex++)
4629 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4632 rtlight = &light->rtlight;
4633 rtlight->corona_visibility = 0;
4634 rtlight->corona_queryindex_visiblepixels = 0;
4635 rtlight->corona_queryindex_allpixels = 0;
4636 if (!(rtlight->flags & flag))
4638 if (rtlight->corona <= 0)
4640 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4642 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4644 for (i = 0;i < r_refdef.scene.numlights;i++)
4646 rtlight = r_refdef.scene.lights[i];
4647 rtlight->corona_visibility = 0;
4648 rtlight->corona_queryindex_visiblepixels = 0;
4649 rtlight->corona_queryindex_allpixels = 0;
4650 if (!(rtlight->flags & flag))
4652 if (rtlight->corona <= 0)
4654 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4657 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4659 // now draw the coronas using the query data for intensity info
4660 for (lightindex = 0;lightindex < range;lightindex++)
4662 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4665 rtlight = &light->rtlight;
4666 if (rtlight->corona_visibility <= 0)
4668 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4670 for (i = 0;i < r_refdef.scene.numlights;i++)
4672 rtlight = r_refdef.scene.lights[i];
4673 if (rtlight->corona_visibility <= 0)
4675 if (gl_flashblend.integer)
4676 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4678 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4684 static dlight_t *R_Shadow_NewWorldLight(void)
4686 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4689 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)
4693 // 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
4695 // validate parameters
4699 // copy to light properties
4700 VectorCopy(origin, light->origin);
4701 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4702 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4703 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4705 light->color[0] = max(color[0], 0);
4706 light->color[1] = max(color[1], 0);
4707 light->color[2] = max(color[2], 0);
4709 light->color[0] = color[0];
4710 light->color[1] = color[1];
4711 light->color[2] = color[2];
4712 light->radius = max(radius, 0);
4713 light->style = style;
4714 light->shadow = shadowenable;
4715 light->corona = corona;
4716 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4717 light->coronasizescale = coronasizescale;
4718 light->ambientscale = ambientscale;
4719 light->diffusescale = diffusescale;
4720 light->specularscale = specularscale;
4721 light->flags = flags;
4723 // update renderable light data
4724 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4725 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);
4728 static void R_Shadow_FreeWorldLight(dlight_t *light)
4730 if (r_shadow_selectedlight == light)
4731 r_shadow_selectedlight = NULL;
4732 R_RTLight_Uncompile(&light->rtlight);
4733 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4736 void R_Shadow_ClearWorldLights(void)
4740 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4741 for (lightindex = 0;lightindex < range;lightindex++)
4743 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4745 R_Shadow_FreeWorldLight(light);
4747 r_shadow_selectedlight = NULL;
4750 static void R_Shadow_SelectLight(dlight_t *light)
4752 if (r_shadow_selectedlight)
4753 r_shadow_selectedlight->selected = false;
4754 r_shadow_selectedlight = light;
4755 if (r_shadow_selectedlight)
4756 r_shadow_selectedlight->selected = true;
4759 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4761 // this is never batched (there can be only one)
4763 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4764 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4765 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4768 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4773 skinframe_t *skinframe;
4776 // this is never batched (due to the ent parameter changing every time)
4777 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4778 const dlight_t *light = (dlight_t *)ent;
4781 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4784 VectorScale(light->color, intensity, spritecolor);
4785 if (VectorLength(spritecolor) < 0.1732f)
4786 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4787 if (VectorLength(spritecolor) > 1.0f)
4788 VectorNormalize(spritecolor);
4790 // draw light sprite
4791 if (light->cubemapname[0] && !light->shadow)
4792 skinframe = r_editlights_sprcubemapnoshadowlight;
4793 else if (light->cubemapname[0])
4794 skinframe = r_editlights_sprcubemaplight;
4795 else if (!light->shadow)
4796 skinframe = r_editlights_sprnoshadowlight;
4798 skinframe = r_editlights_sprlight;
4800 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);
4801 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4803 // draw selection sprite if light is selected
4804 if (light->selected)
4806 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4807 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4808 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4812 void R_Shadow_DrawLightSprites(void)
4816 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4817 for (lightindex = 0;lightindex < range;lightindex++)
4819 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4821 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4823 if (!r_editlights_lockcursor)
4824 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4827 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4832 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4833 if (lightindex >= range)
4835 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4838 rtlight = &light->rtlight;
4839 //if (!(rtlight->flags & flag))
4841 VectorCopy(rtlight->shadoworigin, origin);
4842 *radius = rtlight->radius;
4843 VectorCopy(rtlight->color, color);
4847 static void R_Shadow_SelectLightInView(void)
4849 float bestrating, rating, temp[3];
4853 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4857 if (r_editlights_lockcursor)
4859 for (lightindex = 0;lightindex < range;lightindex++)
4861 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4864 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4865 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4868 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4869 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)
4871 bestrating = rating;
4876 R_Shadow_SelectLight(best);
4879 void R_Shadow_LoadWorldLights(void)
4881 int n, a, style, shadow, flags;
4882 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4883 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4884 if (cl.worldmodel == NULL)
4886 Con_Print("No map loaded.\n");
4889 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4890 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4900 for (;COM_Parse(t, true) && strcmp(
4901 if (COM_Parse(t, true))
4903 if (com_token[0] == '!')
4906 origin[0] = atof(com_token+1);
4909 origin[0] = atof(com_token);
4914 while (*s && *s != '\n' && *s != '\r')
4920 // check for modifier flags
4927 #if _MSC_VER >= 1400
4928 #define sscanf sscanf_s
4930 cubemapname[sizeof(cubemapname)-1] = 0;
4931 #if MAX_QPATH != 128
4932 #error update this code if MAX_QPATH changes
4934 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
4935 #if _MSC_VER >= 1400
4936 , (unsigned int)sizeof(cubemapname)
4938 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4941 flags = LIGHTFLAG_REALTIMEMODE;
4949 coronasizescale = 0.25f;
4951 VectorClear(angles);
4954 if (a < 9 || !strcmp(cubemapname, "\"\""))
4956 // remove quotes on cubemapname
4957 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4960 namelen = strlen(cubemapname) - 2;
4961 memmove(cubemapname, cubemapname + 1, namelen);
4962 cubemapname[namelen] = '\0';
4966 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);
4969 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4977 Con_Printf("invalid rtlights file \"%s\"\n", name);
4978 Mem_Free(lightsstring);
4982 void R_Shadow_SaveWorldLights(void)
4986 size_t bufchars, bufmaxchars;
4988 char name[MAX_QPATH];
4989 char line[MAX_INPUTLINE];
4990 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4991 // I hate lines which are 3 times my screen size :( --blub
4994 if (cl.worldmodel == NULL)
4996 Con_Print("No map loaded.\n");
4999 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5000 bufchars = bufmaxchars = 0;
5002 for (lightindex = 0;lightindex < range;lightindex++)
5004 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5007 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5008 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);
5009 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5010 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]);
5012 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);
5013 if (bufchars + strlen(line) > bufmaxchars)
5015 bufmaxchars = bufchars + strlen(line) + 2048;
5017 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5021 memcpy(buf, oldbuf, bufchars);
5027 memcpy(buf + bufchars, line, strlen(line));
5028 bufchars += strlen(line);
5032 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5037 void R_Shadow_LoadLightsFile(void)
5040 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5041 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5042 if (cl.worldmodel == NULL)
5044 Con_Print("No map loaded.\n");
5047 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5048 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5056 while (*s && *s != '\n' && *s != '\r')
5062 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);
5066 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);
5069 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5070 radius = bound(15, radius, 4096);
5071 VectorScale(color, (2.0f / (8388608.0f)), color);
5072 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5080 Con_Printf("invalid lights file \"%s\"\n", name);
5081 Mem_Free(lightsstring);
5085 // tyrlite/hmap2 light types in the delay field
5086 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5088 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5100 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5101 char key[256], value[MAX_INPUTLINE];
5104 if (cl.worldmodel == NULL)
5106 Con_Print("No map loaded.\n");
5109 // try to load a .ent file first
5110 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5111 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5112 // and if that is not found, fall back to the bsp file entity string
5114 data = cl.worldmodel->brush.entities;
5117 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5119 type = LIGHTTYPE_MINUSX;
5120 origin[0] = origin[1] = origin[2] = 0;
5121 originhack[0] = originhack[1] = originhack[2] = 0;
5122 angles[0] = angles[1] = angles[2] = 0;
5123 color[0] = color[1] = color[2] = 1;
5124 light[0] = light[1] = light[2] = 1;light[3] = 300;
5125 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5135 if (!COM_ParseToken_Simple(&data, false, false, true))
5137 if (com_token[0] == '}')
5138 break; // end of entity
5139 if (com_token[0] == '_')
5140 strlcpy(key, com_token + 1, sizeof(key));
5142 strlcpy(key, com_token, sizeof(key));
5143 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5144 key[strlen(key)-1] = 0;
5145 if (!COM_ParseToken_Simple(&data, false, false, true))
5147 strlcpy(value, com_token, sizeof(value));
5149 // now that we have the key pair worked out...
5150 if (!strcmp("light", key))
5152 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5156 light[0] = vec[0] * (1.0f / 256.0f);
5157 light[1] = vec[0] * (1.0f / 256.0f);
5158 light[2] = vec[0] * (1.0f / 256.0f);
5164 light[0] = vec[0] * (1.0f / 255.0f);
5165 light[1] = vec[1] * (1.0f / 255.0f);
5166 light[2] = vec[2] * (1.0f / 255.0f);
5170 else if (!strcmp("delay", key))
5172 else if (!strcmp("origin", key))
5173 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5174 else if (!strcmp("angle", key))
5175 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5176 else if (!strcmp("angles", key))
5177 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5178 else if (!strcmp("color", key))
5179 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5180 else if (!strcmp("wait", key))
5181 fadescale = atof(value);
5182 else if (!strcmp("classname", key))
5184 if (!strncmp(value, "light", 5))
5187 if (!strcmp(value, "light_fluoro"))
5192 overridecolor[0] = 1;
5193 overridecolor[1] = 1;
5194 overridecolor[2] = 1;
5196 if (!strcmp(value, "light_fluorospark"))
5201 overridecolor[0] = 1;
5202 overridecolor[1] = 1;
5203 overridecolor[2] = 1;
5205 if (!strcmp(value, "light_globe"))
5210 overridecolor[0] = 1;
5211 overridecolor[1] = 0.8;
5212 overridecolor[2] = 0.4;
5214 if (!strcmp(value, "light_flame_large_yellow"))
5219 overridecolor[0] = 1;
5220 overridecolor[1] = 0.5;
5221 overridecolor[2] = 0.1;
5223 if (!strcmp(value, "light_flame_small_yellow"))
5228 overridecolor[0] = 1;
5229 overridecolor[1] = 0.5;
5230 overridecolor[2] = 0.1;
5232 if (!strcmp(value, "light_torch_small_white"))
5237 overridecolor[0] = 1;
5238 overridecolor[1] = 0.5;
5239 overridecolor[2] = 0.1;
5241 if (!strcmp(value, "light_torch_small_walltorch"))
5246 overridecolor[0] = 1;
5247 overridecolor[1] = 0.5;
5248 overridecolor[2] = 0.1;
5252 else if (!strcmp("style", key))
5253 style = atoi(value);
5254 else if (!strcmp("skin", key))
5255 skin = (int)atof(value);
5256 else if (!strcmp("pflags", key))
5257 pflags = (int)atof(value);
5258 //else if (!strcmp("effects", key))
5259 // effects = (int)atof(value);
5260 else if (cl.worldmodel->type == mod_brushq3)
5262 if (!strcmp("scale", key))
5263 lightscale = atof(value);
5264 if (!strcmp("fade", key))
5265 fadescale = atof(value);
5270 if (lightscale <= 0)
5274 if (color[0] == color[1] && color[0] == color[2])
5276 color[0] *= overridecolor[0];
5277 color[1] *= overridecolor[1];
5278 color[2] *= overridecolor[2];
5280 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5281 color[0] = color[0] * light[0];
5282 color[1] = color[1] * light[1];
5283 color[2] = color[2] * light[2];
5286 case LIGHTTYPE_MINUSX:
5288 case LIGHTTYPE_RECIPX:
5290 VectorScale(color, (1.0f / 16.0f), color);
5292 case LIGHTTYPE_RECIPXX:
5294 VectorScale(color, (1.0f / 16.0f), color);
5297 case LIGHTTYPE_NONE:
5301 case LIGHTTYPE_MINUSXX:
5304 VectorAdd(origin, originhack, origin);
5306 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);
5309 Mem_Free(entfiledata);
5313 static void R_Shadow_SetCursorLocationForView(void)
5316 vec3_t dest, endpos;
5318 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5319 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5320 if (trace.fraction < 1)
5322 dist = trace.fraction * r_editlights_cursordistance.value;
5323 push = r_editlights_cursorpushback.value;
5327 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5328 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5332 VectorClear( endpos );
5334 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5335 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5336 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5339 void R_Shadow_UpdateWorldLightSelection(void)
5341 if (r_editlights.integer)
5343 R_Shadow_SetCursorLocationForView();
5344 R_Shadow_SelectLightInView();
5347 R_Shadow_SelectLight(NULL);
5350 static void R_Shadow_EditLights_Clear_f(cmd_state_t *cmd)
5352 R_Shadow_ClearWorldLights();
5355 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd)
5359 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5360 R_Shadow_ClearWorldLights();
5361 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5363 R_Shadow_LoadWorldLights();
5364 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5365 R_Shadow_LoadLightsFile();
5367 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5369 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5370 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5374 static void R_Shadow_EditLights_Save_f(cmd_state_t *cmd)
5378 R_Shadow_SaveWorldLights();
5381 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(cmd_state_t *cmd)
5383 R_Shadow_ClearWorldLights();
5384 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5387 static void R_Shadow_EditLights_ImportLightsFile_f(cmd_state_t *cmd)
5389 R_Shadow_ClearWorldLights();
5390 R_Shadow_LoadLightsFile();
5393 static void R_Shadow_EditLights_Spawn_f(cmd_state_t *cmd)
5396 if (!r_editlights.integer)
5398 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5401 if (Cmd_Argc(cmd) != 1)
5403 Con_Print("r_editlights_spawn does not take parameters\n");
5406 color[0] = color[1] = color[2] = 1;
5407 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5410 static void R_Shadow_EditLights_Edit_f(cmd_state_t *cmd)
5412 vec3_t origin, angles, color;
5413 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5414 int style, shadows, flags, normalmode, realtimemode;
5415 char cubemapname[MAX_INPUTLINE];
5416 if (!r_editlights.integer)
5418 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5421 if (!r_shadow_selectedlight)
5423 Con_Print("No selected light.\n");
5426 VectorCopy(r_shadow_selectedlight->origin, origin);
5427 VectorCopy(r_shadow_selectedlight->angles, angles);
5428 VectorCopy(r_shadow_selectedlight->color, color);
5429 radius = r_shadow_selectedlight->radius;
5430 style = r_shadow_selectedlight->style;
5431 if (r_shadow_selectedlight->cubemapname)
5432 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5435 shadows = r_shadow_selectedlight->shadow;
5436 corona = r_shadow_selectedlight->corona;
5437 coronasizescale = r_shadow_selectedlight->coronasizescale;
5438 ambientscale = r_shadow_selectedlight->ambientscale;
5439 diffusescale = r_shadow_selectedlight->diffusescale;
5440 specularscale = r_shadow_selectedlight->specularscale;
5441 flags = r_shadow_selectedlight->flags;
5442 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5443 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5444 if (!strcmp(Cmd_Argv(cmd, 1), "origin"))
5446 if (Cmd_Argc(cmd) != 5)
5448 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5451 origin[0] = atof(Cmd_Argv(cmd, 2));
5452 origin[1] = atof(Cmd_Argv(cmd, 3));
5453 origin[2] = atof(Cmd_Argv(cmd, 4));
5455 else if (!strcmp(Cmd_Argv(cmd, 1), "originscale"))
5457 if (Cmd_Argc(cmd) != 5)
5459 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5462 origin[0] *= atof(Cmd_Argv(cmd, 2));
5463 origin[1] *= atof(Cmd_Argv(cmd, 3));
5464 origin[2] *= atof(Cmd_Argv(cmd, 4));
5466 else if (!strcmp(Cmd_Argv(cmd, 1), "originx"))
5468 if (Cmd_Argc(cmd) != 3)
5470 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5473 origin[0] = atof(Cmd_Argv(cmd, 2));
5475 else if (!strcmp(Cmd_Argv(cmd, 1), "originy"))
5477 if (Cmd_Argc(cmd) != 3)
5479 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5482 origin[1] = atof(Cmd_Argv(cmd, 2));
5484 else if (!strcmp(Cmd_Argv(cmd, 1), "originz"))
5486 if (Cmd_Argc(cmd) != 3)
5488 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5491 origin[2] = atof(Cmd_Argv(cmd, 2));
5493 else if (!strcmp(Cmd_Argv(cmd, 1), "move"))
5495 if (Cmd_Argc(cmd) != 5)
5497 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5500 origin[0] += atof(Cmd_Argv(cmd, 2));
5501 origin[1] += atof(Cmd_Argv(cmd, 3));
5502 origin[2] += atof(Cmd_Argv(cmd, 4));
5504 else if (!strcmp(Cmd_Argv(cmd, 1), "movex"))
5506 if (Cmd_Argc(cmd) != 3)
5508 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5511 origin[0] += atof(Cmd_Argv(cmd, 2));
5513 else if (!strcmp(Cmd_Argv(cmd, 1), "movey"))
5515 if (Cmd_Argc(cmd) != 3)
5517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5520 origin[1] += atof(Cmd_Argv(cmd, 2));
5522 else if (!strcmp(Cmd_Argv(cmd, 1), "movez"))
5524 if (Cmd_Argc(cmd) != 3)
5526 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5529 origin[2] += atof(Cmd_Argv(cmd, 2));
5531 else if (!strcmp(Cmd_Argv(cmd, 1), "angles"))
5533 if (Cmd_Argc(cmd) != 5)
5535 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5538 angles[0] = atof(Cmd_Argv(cmd, 2));
5539 angles[1] = atof(Cmd_Argv(cmd, 3));
5540 angles[2] = atof(Cmd_Argv(cmd, 4));
5542 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesx"))
5544 if (Cmd_Argc(cmd) != 3)
5546 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5549 angles[0] = atof(Cmd_Argv(cmd, 2));
5551 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesy"))
5553 if (Cmd_Argc(cmd) != 3)
5555 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5558 angles[1] = atof(Cmd_Argv(cmd, 2));
5560 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesz"))
5562 if (Cmd_Argc(cmd) != 3)
5564 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5567 angles[2] = atof(Cmd_Argv(cmd, 2));
5569 else if (!strcmp(Cmd_Argv(cmd, 1), "color"))
5571 if (Cmd_Argc(cmd) != 5)
5573 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(cmd, 1));
5576 color[0] = atof(Cmd_Argv(cmd, 2));
5577 color[1] = atof(Cmd_Argv(cmd, 3));
5578 color[2] = atof(Cmd_Argv(cmd, 4));
5580 else if (!strcmp(Cmd_Argv(cmd, 1), "radius"))
5582 if (Cmd_Argc(cmd) != 3)
5584 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5587 radius = atof(Cmd_Argv(cmd, 2));
5589 else if (!strcmp(Cmd_Argv(cmd, 1), "colorscale"))
5591 if (Cmd_Argc(cmd) == 3)
5593 double scale = atof(Cmd_Argv(cmd, 2));
5600 if (Cmd_Argc(cmd) != 5)
5602 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(cmd, 1));
5605 color[0] *= atof(Cmd_Argv(cmd, 2));
5606 color[1] *= atof(Cmd_Argv(cmd, 3));
5607 color[2] *= atof(Cmd_Argv(cmd, 4));
5610 else if (!strcmp(Cmd_Argv(cmd, 1), "radiusscale") || !strcmp(Cmd_Argv(cmd, 1), "sizescale"))
5612 if (Cmd_Argc(cmd) != 3)
5614 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5617 radius *= atof(Cmd_Argv(cmd, 2));
5619 else if (!strcmp(Cmd_Argv(cmd, 1), "style"))
5621 if (Cmd_Argc(cmd) != 3)
5623 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5626 style = atoi(Cmd_Argv(cmd, 2));
5628 else if (!strcmp(Cmd_Argv(cmd, 1), "cubemap"))
5630 if (Cmd_Argc(cmd) > 3)
5632 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5635 if (Cmd_Argc(cmd) == 3)
5636 strlcpy(cubemapname, Cmd_Argv(cmd, 2), sizeof(cubemapname));
5640 else if (!strcmp(Cmd_Argv(cmd, 1), "shadows"))
5642 if (Cmd_Argc(cmd) != 3)
5644 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5647 shadows = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5649 else if (!strcmp(Cmd_Argv(cmd, 1), "corona"))
5651 if (Cmd_Argc(cmd) != 3)
5653 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5656 corona = atof(Cmd_Argv(cmd, 2));
5658 else if (!strcmp(Cmd_Argv(cmd, 1), "coronasize"))
5660 if (Cmd_Argc(cmd) != 3)
5662 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5665 coronasizescale = atof(Cmd_Argv(cmd, 2));
5667 else if (!strcmp(Cmd_Argv(cmd, 1), "ambient"))
5669 if (Cmd_Argc(cmd) != 3)
5671 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5674 ambientscale = atof(Cmd_Argv(cmd, 2));
5676 else if (!strcmp(Cmd_Argv(cmd, 1), "diffuse"))
5678 if (Cmd_Argc(cmd) != 3)
5680 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5683 diffusescale = atof(Cmd_Argv(cmd, 2));
5685 else if (!strcmp(Cmd_Argv(cmd, 1), "specular"))
5687 if (Cmd_Argc(cmd) != 3)
5689 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5692 specularscale = atof(Cmd_Argv(cmd, 2));
5694 else if (!strcmp(Cmd_Argv(cmd, 1), "normalmode"))
5696 if (Cmd_Argc(cmd) != 3)
5698 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5701 normalmode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5703 else if (!strcmp(Cmd_Argv(cmd, 1), "realtimemode"))
5705 if (Cmd_Argc(cmd) != 3)
5707 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5710 realtimemode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5714 Con_Print("usage: r_editlights_edit [property] [value]\n");
5715 Con_Print("Selected light's properties:\n");
5716 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5717 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5718 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5719 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5720 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5721 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5722 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5723 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5724 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5725 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5726 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5727 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5728 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5729 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5732 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5733 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5736 static void R_Shadow_EditLights_EditAll_f(cmd_state_t *cmd)
5739 dlight_t *light, *oldselected;
5742 if (!r_editlights.integer)
5744 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5748 oldselected = r_shadow_selectedlight;
5749 // EditLights doesn't seem to have a "remove" command or something so:
5750 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5751 for (lightindex = 0;lightindex < range;lightindex++)
5753 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5756 R_Shadow_SelectLight(light);
5757 R_Shadow_EditLights_Edit_f(&cmd_client);
5759 // return to old selected (to not mess editing once selection is locked)
5760 R_Shadow_SelectLight(oldselected);
5763 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5765 int lightnumber, lightcount;
5766 size_t lightindex, range;
5771 if (!r_editlights.integer)
5774 // update cvars so QC can query them
5775 if (r_shadow_selectedlight)
5777 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5778 Cvar_SetQuick(&r_editlights_current_origin, temp);
5779 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5780 Cvar_SetQuick(&r_editlights_current_angles, temp);
5781 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5782 Cvar_SetQuick(&r_editlights_current_color, temp);
5783 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5784 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5785 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5786 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5787 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5788 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5789 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5790 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5791 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5792 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5793 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5796 // draw properties on screen
5797 if (!r_editlights_drawproperties.integer)
5799 x = vid_conwidth.value - 320;
5801 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5804 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5805 for (lightindex = 0;lightindex < range;lightindex++)
5807 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5810 if (light == r_shadow_selectedlight)
5811 lightnumber = (int)lightindex;
5814 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;
5815 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;
5817 if (r_shadow_selectedlight == NULL)
5819 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;
5820 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;
5821 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;
5822 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;
5823 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;
5824 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;
5825 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;
5826 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;
5827 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;
5828 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;
5829 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;
5830 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;
5831 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;
5832 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;
5833 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;
5835 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;
5836 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;
5837 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;
5838 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;
5839 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;
5840 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;
5841 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;
5842 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;
5843 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;
5844 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;
5847 static void R_Shadow_EditLights_ToggleShadow_f(cmd_state_t *cmd)
5849 if (!r_editlights.integer)
5851 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5854 if (!r_shadow_selectedlight)
5856 Con_Print("No selected light.\n");
5859 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);
5862 static void R_Shadow_EditLights_ToggleCorona_f(cmd_state_t *cmd)
5864 if (!r_editlights.integer)
5866 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5869 if (!r_shadow_selectedlight)
5871 Con_Print("No selected light.\n");
5874 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);
5877 static void R_Shadow_EditLights_Remove_f(cmd_state_t *cmd)
5879 if (!r_editlights.integer)
5881 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5884 if (!r_shadow_selectedlight)
5886 Con_Print("No selected light.\n");
5889 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5890 r_shadow_selectedlight = NULL;
5893 static void R_Shadow_EditLights_Help_f(cmd_state_t *cmd)
5896 "Documentation on r_editlights system:\n"
5898 "r_editlights : enable/disable editing mode\n"
5899 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5900 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5901 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5902 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5903 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5905 "r_editlights_help : this help\n"
5906 "r_editlights_clear : remove all lights\n"
5907 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5908 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5909 "r_editlights_save : save to .rtlights file\n"
5910 "r_editlights_spawn : create a light with default settings\n"
5911 "r_editlights_edit command : edit selected light - more documentation below\n"
5912 "r_editlights_remove : remove selected light\n"
5913 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5914 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5915 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5917 "origin x y z : set light location\n"
5918 "originx x: set x component of light location\n"
5919 "originy y: set y component of light location\n"
5920 "originz z: set z component of light location\n"
5921 "move x y z : adjust light location\n"
5922 "movex x: adjust x component of light location\n"
5923 "movey y: adjust y component of light location\n"
5924 "movez z: adjust z component of light location\n"
5925 "angles x y z : set light angles\n"
5926 "anglesx x: set x component of light angles\n"
5927 "anglesy y: set y component of light angles\n"
5928 "anglesz z: set z component of light angles\n"
5929 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5930 "radius radius : set radius (size) of light\n"
5931 "colorscale grey : multiply color of light (1 does nothing)\n"
5932 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5933 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5934 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5935 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5936 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5937 "cubemap basename : set filter cubemap of light\n"
5938 "shadows 1/0 : turn on/off shadows\n"
5939 "corona n : set corona intensity\n"
5940 "coronasize n : set corona size (0-1)\n"
5941 "ambient n : set ambient intensity (0-1)\n"
5942 "diffuse n : set diffuse intensity (0-1)\n"
5943 "specular n : set specular intensity (0-1)\n"
5944 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5945 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5946 "<nothing> : print light properties to console\n"
5950 static void R_Shadow_EditLights_CopyInfo_f(cmd_state_t *cmd)
5952 if (!r_editlights.integer)
5954 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5957 if (!r_shadow_selectedlight)
5959 Con_Print("No selected light.\n");
5962 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5963 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5964 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5965 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5966 if (r_shadow_selectedlight->cubemapname)
5967 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5969 r_shadow_bufferlight.cubemapname[0] = 0;
5970 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5971 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5972 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5973 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5974 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5975 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5976 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5979 static void R_Shadow_EditLights_PasteInfo_f(cmd_state_t *cmd)
5981 if (!r_editlights.integer)
5983 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5986 if (!r_shadow_selectedlight)
5988 Con_Print("No selected light.\n");
5991 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);
5994 static void R_Shadow_EditLights_Lock_f(cmd_state_t *cmd)
5996 if (!r_editlights.integer)
5998 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6001 if (r_editlights_lockcursor)
6003 r_editlights_lockcursor = false;
6006 if (!r_shadow_selectedlight)
6008 Con_Print("No selected light to lock on.\n");
6011 r_editlights_lockcursor = true;
6014 static void R_Shadow_EditLights_Init(void)
6016 Cvar_RegisterVariable(&r_editlights);
6017 Cvar_RegisterVariable(&r_editlights_cursordistance);
6018 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6019 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6020 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6021 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6022 Cvar_RegisterVariable(&r_editlights_drawproperties);
6023 Cvar_RegisterVariable(&r_editlights_current_origin);
6024 Cvar_RegisterVariable(&r_editlights_current_angles);
6025 Cvar_RegisterVariable(&r_editlights_current_color);
6026 Cvar_RegisterVariable(&r_editlights_current_radius);
6027 Cvar_RegisterVariable(&r_editlights_current_corona);
6028 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6029 Cvar_RegisterVariable(&r_editlights_current_style);
6030 Cvar_RegisterVariable(&r_editlights_current_shadows);
6031 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6032 Cvar_RegisterVariable(&r_editlights_current_ambient);
6033 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6034 Cvar_RegisterVariable(&r_editlights_current_specular);
6035 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6036 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6037 Cmd_AddCommand(&cmd_client, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6038 Cmd_AddCommand(&cmd_client, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6039 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)");
6040 Cmd_AddCommand(&cmd_client, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6041 Cmd_AddCommand(&cmd_client, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6042 Cmd_AddCommand(&cmd_client, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6043 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)");
6044 Cmd_AddCommand(&cmd_client, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6045 Cmd_AddCommand(&cmd_client, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6046 Cmd_AddCommand(&cmd_client, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6047 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)");
6048 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)");
6049 Cmd_AddCommand(&cmd_client, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6050 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)");
6051 Cmd_AddCommand(&cmd_client, "r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6057 =============================================================================
6061 =============================================================================
6064 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6066 int i, numlights, flag, q;
6069 float relativepoint[3];
6074 float sa[3], sx[3], sy[3], sz[3], sd[3];
6077 // use first order spherical harmonics to combine directional lights
6078 for (q = 0; q < 3; q++)
6079 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6081 if (flags & LP_LIGHTMAP)
6083 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6085 float tempambient[3];
6086 for (q = 0; q < 3; q++)
6087 tempambient[q] = color[q] = relativepoint[q] = 0;
6088 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6089 // calculate a weighted average light direction as well
6090 intensity = VectorLength(color);
6091 for (q = 0; q < 3; q++)
6093 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6094 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6095 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6096 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6097 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6102 // unlit map - fullbright but scaled by lightmapintensity
6103 for (q = 0; q < 3; q++)
6104 sa[q] += lightmapintensity;
6108 if (flags & LP_RTWORLD)
6110 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6111 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6112 for (i = 0; i < numlights; i++)
6114 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6117 light = &dlight->rtlight;
6118 if (!(light->flags & flag))
6121 lightradius2 = light->radius * light->radius;
6122 VectorSubtract(light->shadoworigin, p, relativepoint);
6123 dist2 = VectorLength2(relativepoint);
6124 if (dist2 >= lightradius2)
6126 dist = sqrt(dist2) / light->radius;
6127 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6128 if (intensity <= 0.0f)
6130 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)
6132 for (q = 0; q < 3; q++)
6133 color[q] = light->currentcolor[q] * intensity;
6134 intensity = VectorLength(color);
6135 VectorNormalize(relativepoint);
6136 for (q = 0; q < 3; q++)
6138 sa[q] += 0.5f * color[q];
6139 sx[q] += relativepoint[0] * color[q];
6140 sy[q] += relativepoint[1] * color[q];
6141 sz[q] += relativepoint[2] * color[q];
6142 sd[q] += intensity * relativepoint[q];
6145 // FIXME: sample bouncegrid too!
6148 if (flags & LP_DYNLIGHT)
6151 for (i = 0;i < r_refdef.scene.numlights;i++)
6153 light = r_refdef.scene.lights[i];
6155 lightradius2 = light->radius * light->radius;
6156 VectorSubtract(light->shadoworigin, p, relativepoint);
6157 dist2 = VectorLength2(relativepoint);
6158 if (dist2 >= lightradius2)
6160 dist = sqrt(dist2) / light->radius;
6161 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6162 if (intensity <= 0.0f)
6164 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)
6166 for (q = 0; q < 3; q++)
6167 color[q] = light->currentcolor[q] * intensity;
6168 intensity = VectorLength(color);
6169 VectorNormalize(relativepoint);
6170 for (q = 0; q < 3; q++)
6172 sa[q] += 0.5f * color[q];
6173 sx[q] += relativepoint[0] * color[q];
6174 sy[q] += relativepoint[1] * color[q];
6175 sz[q] += relativepoint[2] * color[q];
6176 sd[q] += intensity * relativepoint[q];
6181 // calculate the weighted-average light direction (bentnormal)
6182 for (q = 0; q < 3; q++)
6183 lightdir[q] = sd[q];
6184 VectorNormalize(lightdir);
6185 for (q = 0; q < 3; q++)
6187 // extract the diffuse color along the chosen direction and scale it
6188 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6189 // subtract some of diffuse from ambient
6190 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;