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->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1728 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1729 settings->subsamples = bound(1, r_shadow_bouncegrid_subsamples.integer, 4);
1731 // bound the values for sanity
1732 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1733 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1734 settings->maxbounce = bound(0, settings->maxbounce, 16);
1735 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1736 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1737 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1740 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1751 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1753 // get the spacing values
1754 spacing[0] = settings->spacing[0];
1755 spacing[1] = settings->spacing[1];
1756 spacing[2] = settings->spacing[2];
1757 ispacing[0] = 1.0f / spacing[0];
1758 ispacing[1] = 1.0f / spacing[1];
1759 ispacing[2] = 1.0f / spacing[2];
1761 // calculate texture size enclosing entire world bounds at the spacing
1762 if (r_refdef.scene.worldmodel)
1766 qboolean bounds_set = false;
1770 // calculate bounds enclosing world lights as they should be noticably tighter
1771 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1772 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1773 for (lightindex = 0;lightindex < range;lightindex++)
1775 const vec_t *rtlmins, *rtlmaxs;
1777 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1781 rtlight = &light->rtlight;
1782 rtlmins = rtlight->cullmins;
1783 rtlmaxs = rtlight->cullmaxs;
1787 VectorCopy(rtlmins, mins);
1788 VectorCopy(rtlmaxs, maxs);
1793 mins[0] = min(mins[0], rtlmins[0]);
1794 mins[1] = min(mins[1], rtlmins[1]);
1795 mins[2] = min(mins[2], rtlmins[2]);
1796 maxs[0] = max(maxs[0], rtlmaxs[0]);
1797 maxs[1] = max(maxs[1], rtlmaxs[1]);
1798 maxs[2] = max(maxs[2], rtlmaxs[2]);
1802 // limit to no larger than the world bounds
1803 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1804 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1805 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1806 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1807 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1808 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1810 VectorMA(mins, -2.0f, spacing, mins);
1811 VectorMA(maxs, 2.0f, spacing, maxs);
1815 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1816 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1818 VectorSubtract(maxs, mins, size);
1819 // now we can calculate the resolution we want
1820 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1821 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1822 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1823 // figure out the exact texture size (honoring power of 2 if required)
1824 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1825 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1826 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1827 size[0] = spacing[0] * resolution[0];
1828 size[1] = spacing[1] * resolution[1];
1829 size[2] = spacing[2] * resolution[2];
1831 // if dynamic we may or may not want to use the world bounds
1832 // if the dynamic size is smaller than the world bounds, use it instead
1833 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]))
1835 // we know the resolution we want
1836 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1837 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1838 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1839 // now we can calculate the texture size
1840 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1841 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1842 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1843 size[0] = spacing[0] * resolution[0];
1844 size[1] = spacing[1] * resolution[1];
1845 size[2] = spacing[2] * resolution[2];
1846 // center the rendering on the view
1847 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1848 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1849 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1852 // recalculate the maxs in case the resolution was not satisfactory
1853 VectorAdd(mins, size, maxs);
1855 // check if this changed the texture size
1856 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);
1857 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1858 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1859 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1860 VectorCopy(size, r_shadow_bouncegrid_state.size);
1861 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1862 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1863 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1865 // reallocate pixels for this update if needed...
1866 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1867 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1868 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1869 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1870 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1872 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1874 r_shadow_bouncegrid_state.highpixels = NULL;
1876 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1877 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1878 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1879 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1880 if (r_shadow_bouncegrid_state.photons) { Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL; }
1881 if (r_shadow_bouncegrid_state.photons_tasks) { Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL; }
1882 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
1884 r_shadow_bouncegrid_state.numpixels = numpixels;
1887 // update the bouncegrid matrix to put it in the world properly
1888 memset(m, 0, sizeof(m));
1889 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1890 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1891 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1892 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1893 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1894 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1896 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1899 static float R_Shadow_BounceGrid_RefractiveIndexAtPoint(vec3_t point)
1901 // check material at shadoworigin to see what the initial refractive index should be
1902 int hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
1903 int skipsupercontentsmask = 0;
1904 int skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
1905 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);
1906 if (trace.starttexture && (trace.starttexture->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)))
1907 return trace.starttexture->refractive_index;
1908 else if (trace.startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
1909 return 1.333f; // water
1911 return 1.0003f; // air
1914 // enumerate world rtlights and sum the overall amount of light in the world,
1915 // from that we can calculate a scaling factor to fairly distribute photons
1916 // to all the lights
1918 // this modifies rtlight->photoncolor and rtlight->photons
1919 static void R_Shadow_BounceGrid_AssignPhotons_Task(taskqueue_task_t *t)
1921 // get the range of light numbers we'll be looping over:
1922 // range = static lights
1923 // range1 = dynamic lights (optional)
1924 // range2 = range + range1
1925 unsigned int range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1926 unsigned int range1 = r_shadow_bouncegrid_state.settings.staticmode ? 0 : r_refdef.scene.numlights;
1927 unsigned int range2 = range + range1;
1928 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
1930 float normalphotonscaling;
1931 float photonscaling;
1932 float photonintensity;
1933 float photoncount = 0.0f;
1934 float lightintensity;
1940 unsigned int lightindex;
1945 float bounceminimumintensity2;
1946 float startrefractiveindex;
1948 randomseed_t randomseed;
1949 vec3_t baseshotcolor;
1953 normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1954 for (lightindex = 0;lightindex < range2;lightindex++)
1956 if (lightindex < range)
1958 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1961 rtlight = &light->rtlight;
1962 VectorClear(rtlight->bouncegrid_photoncolor);
1963 rtlight->bouncegrid_photons = 0;
1964 rtlight->bouncegrid_hits = 0;
1965 rtlight->bouncegrid_traces = 0;
1966 rtlight->bouncegrid_effectiveradius = 0;
1967 if (!(light->flags & flag))
1969 if (r_shadow_bouncegrid_state.settings.staticmode)
1971 // when static, we skip styled lights because they tend to change...
1972 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
1975 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
1980 rtlight = r_refdef.scene.lights[lightindex - range];
1981 VectorClear(rtlight->bouncegrid_photoncolor);
1982 rtlight->bouncegrid_photons = 0;
1983 rtlight->bouncegrid_hits = 0;
1984 rtlight->bouncegrid_traces = 0;
1985 rtlight->bouncegrid_effectiveradius = 0;
1987 // draw only visible lights (major speedup)
1988 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
1989 cullmins[0] = rtlight->shadoworigin[0] - radius;
1990 cullmins[1] = rtlight->shadoworigin[1] - radius;
1991 cullmins[2] = rtlight->shadoworigin[2] - radius;
1992 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
1993 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
1994 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
1995 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
1996 if (!r_shadow_bouncegrid_state.settings.staticmode)
1998 // skip if the expanded light box does not touch any visible leafs
1999 if (r_refdef.scene.worldmodel
2000 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2001 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2003 // skip if the expanded light box is not visible to traceline
2004 // note that PrepareLight already did this check but for a smaller box, so we
2005 // end up casting more traces per frame per light when using bouncegrid, which
2006 // is probably fine (and they use the same timer)
2007 if (r_shadow_culllights_trace.integer)
2009 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))
2010 rtlight->trace_timer = realtime;
2011 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2014 // skip if expanded light box is offscreen
2015 if (R_CullBox(cullmins, cullmaxs))
2017 // skip if overall light intensity is zero
2018 if (w * VectorLength2(rtlight->color) == 0.0f)
2021 // a light that does not emit any light before style is applied, can be
2022 // skipped entirely (it may just be a corona)
2023 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2025 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2026 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2027 // skip lights that will emit no photons
2028 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2030 // shoot particles from this light
2031 // use a calculation for the number of particles that will not
2032 // vary with lightstyle, otherwise we get randomized particle
2033 // distribution, the seeded random is only consistent for a
2034 // consistent number of particles on this light...
2035 s = rtlight->radius;
2036 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2037 if (lightindex >= range)
2038 lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2039 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2040 photoncount += rtlight->bouncegrid_photons;
2041 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2042 // if the lightstyle happens to be off right now, we can skip actually
2043 // firing the photons, but we did have to count them in the total.
2044 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2045 // rtlight->bouncegrid_photons = 0;
2047 // the user provided an energyperphoton value which we try to use
2048 // if that results in too many photons to shoot this frame, then we cap it
2049 // which causes photons to appear/disappear from frame to frame, so we don't
2050 // like doing that in the typical case
2051 photonscaling = 1.0f;
2052 photonintensity = 1.0f;
2053 if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2055 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2056 photonintensity = 1.0f / photonscaling;
2059 // modify the lights to reflect our computed scaling
2060 for (lightindex = 0; lightindex < range2; lightindex++)
2062 if (lightindex < range)
2064 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2067 rtlight = &light->rtlight;
2070 rtlight = r_refdef.scene.lights[lightindex - range];
2071 rtlight->bouncegrid_photons *= photonscaling;
2072 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2075 // compute a seed for the unstable random modes
2076 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2077 seed = realtime * 1000.0;
2079 for (lightindex = 0; lightindex < range2; lightindex++)
2081 if (lightindex < range)
2083 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2086 rtlight = &light->rtlight;
2089 rtlight = r_refdef.scene.lights[lightindex - range];
2090 // note that this code used to keep track of residual photons and
2091 // distribute them evenly to achieve exactly a desired photon count,
2092 // but that caused unwanted flickering in dynamic mode
2093 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2094 // skip if we won't be shooting any photons
2095 if (!shootparticles)
2097 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2098 //s = settings.particleintensity / shootparticles;
2099 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2100 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2101 if (VectorLength2(baseshotcolor) <= 0.0f)
2103 r_refdef.stats[r_stat_bouncegrid_lights]++;
2104 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2105 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2106 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2108 // check material at shadoworigin to see what the initial refractive index should be
2109 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2111 // for seeded random we start the RNG with the position of the light
2112 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2120 u.f[0] = rtlight->shadoworigin[0];
2121 u.f[1] = rtlight->shadoworigin[1];
2122 u.f[2] = rtlight->shadoworigin[2];
2124 switch (r_shadow_bouncegrid_state.settings.rng_type)
2128 // we have to shift the seed provided by the user because the result must be odd
2129 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2132 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2137 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2139 r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2140 VectorCopy(baseshotcolor, p->color);
2141 VectorCopy(rtlight->shadoworigin, p->start);
2142 switch (r_shadow_bouncegrid_state.settings.rng_type)
2146 // figure out a random direction for the initial photon to go
2147 VectorLehmerRandom(&randomseed, p->end);
2150 // figure out a random direction for the initial photon to go
2151 VectorCheeseRandom(seed, p->end);
2155 // we want a uniform distribution spherically, not merely within the sphere
2156 if (r_shadow_bouncegrid_state.settings.normalizevectors)
2157 VectorNormalize(p->end);
2159 VectorMA(p->start, radius, p->end, p->end);
2160 p->bounceminimumintensity2 = bounceminimumintensity2;
2161 p->startrefractiveindex = startrefractiveindex;
2169 static void R_Shadow_BounceGrid_Slice(int zi)
2171 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2172 int xi, yi; // pixel increments
2173 float color[32] = { 0 };
2174 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2175 float iradius = 1.0f / radius;
2176 int slicemins[3], slicemaxs[3];
2178 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2179 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2181 int samples = r_shadow_bouncegrid_state.settings.subsamples;
2182 float isamples = 1.0f / samples;
2183 float samplescolorscale = isamples * isamples * isamples;
2185 // we use these a lot, so get a local copy
2186 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2188 for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2190 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2192 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2194 r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2195 float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2197 VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2198 VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2200 pathmins[2] = min(pathstart[2], pathend[2]);
2201 slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2202 pathmaxs[2] = max(pathstart[2], pathend[2]);
2203 slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2205 // skip if the path doesn't touch this slice
2206 if (zi < slicemins[2] || zi >= slicemaxs[2])
2209 pathmins[0] = min(pathstart[0], pathend[0]);
2210 slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2211 slicemins[0] = max(slicemins[0], 1);
2212 pathmaxs[0] = max(pathstart[0], pathend[0]);
2213 slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2214 slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2216 pathmins[1] = min(pathstart[1], pathend[1]);
2217 slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2218 slicemins[1] = max(slicemins[1], 1);
2219 pathmaxs[1] = max(pathstart[1], pathend[1]);
2220 slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2221 slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2223 // skip if the path is out of bounds on X or Y
2224 if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2227 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2228 // accumulate average shotcolor
2229 VectorSubtract(pathend, pathstart, pathdelta);
2230 pathlength2 = VectorLength2(pathdelta);
2231 pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2232 VectorScale(pathdelta, pathilength, pathdir);
2233 // the color is scaled by the number of subsamples
2234 color[0] = path->color[0] * samplescolorscale;
2235 color[1] = path->color[1] * samplescolorscale;
2236 color[2] = path->color[2] * samplescolorscale;
2240 // store bentnormal in case the shader has a use for it,
2241 // bentnormal is an intensity-weighted average of the directions,
2242 // and will be normalized on conversion to texture pixels.
2243 float intensity = VectorLength(color);
2244 color[4] = pathdir[0] * intensity;
2245 color[5] = pathdir[1] * intensity;
2246 color[6] = pathdir[2] * intensity;
2247 color[7] = intensity;
2248 // for each color component (R, G, B) calculate the amount that a
2249 // direction contributes
2250 color[8] = color[0] * max(0.0f, pathdir[0]);
2251 color[9] = color[0] * max(0.0f, pathdir[1]);
2252 color[10] = color[0] * max(0.0f, pathdir[2]);
2254 color[12] = color[1] * max(0.0f, pathdir[0]);
2255 color[13] = color[1] * max(0.0f, pathdir[1]);
2256 color[14] = color[1] * max(0.0f, pathdir[2]);
2258 color[16] = color[2] * max(0.0f, pathdir[0]);
2259 color[17] = color[2] * max(0.0f, pathdir[1]);
2260 color[18] = color[2] * max(0.0f, pathdir[2]);
2262 // and do the same for negative directions
2263 color[20] = color[0] * max(0.0f, -pathdir[0]);
2264 color[21] = color[0] * max(0.0f, -pathdir[1]);
2265 color[22] = color[0] * max(0.0f, -pathdir[2]);
2267 color[24] = color[1] * max(0.0f, -pathdir[0]);
2268 color[25] = color[1] * max(0.0f, -pathdir[1]);
2269 color[26] = color[1] * max(0.0f, -pathdir[2]);
2271 color[28] = color[2] * max(0.0f, -pathdir[0]);
2272 color[29] = color[2] * max(0.0f, -pathdir[1]);
2273 color[30] = color[2] * max(0.0f, -pathdir[2]);
2277 for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2279 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2281 float sample[3], diff[3], nearest[3], along, distance2;
2282 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2284 // loop over the subsamples
2285 for (zs = 0; zs < samples; zs++)
2287 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2288 for (ys = 0; ys < samples; ys++)
2290 sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2291 for (xs = 0; xs < samples; xs++)
2293 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2295 // measure distance from subsample to line segment and see if it is within radius
2296 along = DotProduct(sample, pathdir) * pathilength;
2298 VectorCopy(pathstart, nearest);
2299 else if (along >= 1)
2300 VectorCopy(pathend, nearest);
2302 VectorLerp(pathstart, along, pathend, nearest);
2303 VectorSubtract(sample, nearest, diff);
2304 VectorScale(diff, iradius, diff);
2305 distance2 = VectorLength2(diff);
2306 if (distance2 < 1.0f)
2308 // contribute some color to this pixel, across all bands
2309 float w = 1.0f - sqrt(distance2);
2314 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2315 p[pixelsperband * 4 + 3] += color[7] * w;
2317 for (band = 0; band < pixelbands; band++)
2319 // add to the pixel color (RGB only - see above)
2320 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2321 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2322 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2334 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2337 R_Shadow_BounceGrid_Slice((int)t->i[0]);
2341 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2344 // we need to wait for the texture clear to finish before we start adding light to it
2345 if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2351 slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2352 for (i = 0; i < slices; i++)
2353 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2354 TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2355 TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2356 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2360 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2362 const float *inpixel;
2364 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2367 unsigned int x, y, z;
2368 unsigned int resolution[3];
2369 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2370 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2372 for (z = 1;z < resolution[2]-1;z++)
2374 for (y = 1;y < resolution[1]-1;y++)
2377 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2378 inpixel = inpixels + 4*index;
2379 outpixel = outpixels + 4*index;
2380 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2382 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2383 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2384 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2385 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2392 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2395 unsigned int resolution[3];
2397 if (r_shadow_bouncegrid_state.settings.blur)
2399 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2401 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2402 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2403 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2404 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2407 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2409 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2411 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2413 // toggle the state, highpixels now points to pixels[3] result
2414 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2415 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2420 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2422 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2423 unsigned char *pixelsbgra8 = NULL;
2424 unsigned char *pixelbgra8;
2425 unsigned short *pixelsrgba16f = NULL;
2426 unsigned short *pixelrgba16f;
2427 float *pixelsrgba32f = NULL;
2428 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2431 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2432 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2433 unsigned int pixelband;
2434 unsigned int x, y, z;
2435 unsigned int index, bandindex;
2436 unsigned int resolution[3];
2438 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2440 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2442 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2443 r_shadow_bouncegrid_state.texture = NULL;
2446 // if bentnormals exist, we need to normalize and bias them for the shader
2450 for (z = 0;z < resolution[2]-1;z++)
2452 for (y = 0;y < resolution[1]-1;y++)
2455 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2456 highpixel = highpixels + 4*index;
2457 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2459 // only convert pixels that were hit by photons
2460 if (highpixel[3] != 0.0f)
2461 VectorNormalize(highpixel);
2462 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2463 highpixel[pixelsperband * 4 + 3] = 1.0f;
2469 // start by clearing the pixels array - we won't be writing to all of it
2471 // then process only the pixels that have at least some color, skipping
2472 // the higher bands for speed on pixels that are black
2473 switch (floatcolors)
2476 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2477 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2478 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2479 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2482 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2484 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2486 for (z = 1;z < resolution[2]-1;z++)
2488 for (y = 1;y < resolution[1]-1;y++)
2492 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2493 highpixel = highpixels + 4*index;
2494 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2496 // only convert pixels that were hit by photons
2497 if (VectorLength2(highpixel))
2499 // normalize the bentnormal now
2502 VectorNormalize(highpixel + pixelsperband * 4);
2503 highpixel[pixelsperband * 4 + 3] = 1.0f;
2505 // process all of the pixelbands for this pixel
2506 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2508 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2509 bandpixel = highpixels + 4*bandindex;
2510 c[0] = (int)(bandpixel[0]*256.0f);
2511 c[1] = (int)(bandpixel[1]*256.0f);
2512 c[2] = (int)(bandpixel[2]*256.0f);
2513 c[3] = (int)(bandpixel[3]*256.0f);
2514 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2515 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2516 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2517 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2524 if (!r_shadow_bouncegrid_state.createtexture)
2525 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2527 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);
2530 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2531 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2532 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2533 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2534 for (z = 1;z < resolution[2]-1;z++)
2536 for (y = 1;y < resolution[1]-1;y++)
2540 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2541 highpixel = highpixels + 4*index;
2542 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2544 // only convert pixels that were hit by photons
2545 if (VectorLength2(highpixel))
2547 // process all of the pixelbands for this pixel
2548 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2550 // time to have fun with IEEE 754 bit hacking...
2553 unsigned int raw[4];
2555 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2556 bandpixel = highpixels + 4*bandindex;
2557 VectorCopy4(bandpixel, u.f);
2558 VectorCopy4(u.raw, c);
2559 // this math supports negative numbers, snaps denormals to zero
2560 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2561 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2562 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2563 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2564 // this math does not support negative
2565 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2566 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2567 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2568 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2575 if (!r_shadow_bouncegrid_state.createtexture)
2576 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2578 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);
2581 // our native format happens to match, so this is easy.
2582 pixelsrgba32f = highpixels;
2584 if (!r_shadow_bouncegrid_state.createtexture)
2585 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2587 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);
2591 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2594 void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2597 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2601 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)
2603 int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2605 vec3_t surfacenormal;
2606 vec3_t reflectstart, reflectend, reflectcolor;
2607 vec3_t refractstart, refractend, refractcolor;
2609 float reflectamount = 1.0f;
2611 // figure out what we want to interact with
2612 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2613 skipsupercontentsmask = 0;
2614 skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2615 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2616 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2617 if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2619 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2620 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2621 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);
2625 // dynamic mode fires many rays and most will match the cache from the previous frame
2626 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);
2628 VectorCopy(cliptrace.endpos, shothit);
2629 if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2631 qboolean notculled = true;
2632 // cull paths that fail R_CullBox in dynamic mode
2633 if (!r_shadow_bouncegrid_state.settings.staticmode
2634 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2636 vec3_t cullmins, cullmaxs;
2637 cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2638 cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2639 cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2640 cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2641 cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2642 cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2643 if (R_CullBox(cullmins, cullmaxs))
2648 r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2649 VectorCopy(shotstart, path->start);
2650 VectorCopy(shothit, path->end);
2651 VectorCopy(shotcolor, path->color);
2654 if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2656 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2657 // also clamp the resulting color to never add energy, even if the user requests extreme values
2658 VectorCopy(cliptrace.plane.normal, surfacenormal);
2659 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2660 VectorClear(refractcolor);
2661 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2662 if (cliptrace.hittexture)
2664 if (cliptrace.hittexture->currentskinframe)
2665 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2666 if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2668 reflectamount *= cliptrace.hittexture->currentalpha;
2669 if (cliptrace.hittexture->currentskinframe)
2670 reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2672 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2676 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2677 VectorSubtract(shotstart, shotend, lightdir);
2678 VectorNormalize(lightdir);
2679 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2680 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2681 reflectamount *= Fresnel;
2682 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2684 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2685 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2686 // make sure we do not gain energy even if surface colors are out of bounds
2687 reflectcolor[0] = min(reflectcolor[0], 1.0f);
2688 reflectcolor[1] = min(reflectcolor[1], 1.0f);
2689 reflectcolor[2] = min(reflectcolor[2], 1.0f);
2690 refractcolor[0] = min(refractcolor[0], 1.0f);
2691 refractcolor[1] = min(refractcolor[1], 1.0f);
2692 refractcolor[2] = min(refractcolor[2], 1.0f);
2694 // reflected and refracted shots
2695 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2696 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2697 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2698 VectorMultiply(refractcolor, shotcolor, refractcolor);
2700 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2702 // reflect the remaining portion of the line across plane normal
2703 VectorSubtract(shotend, shothit, reflectend);
2704 VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2705 // calculate the new line start and end
2706 VectorCopy(shothit, reflectstart);
2707 VectorAdd(reflectstart, reflectend, reflectend);
2708 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2711 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2713 // Check what refractive index is on the other side
2714 float refractiveindex;
2715 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2716 refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2717 // reflect the remaining portion of the line across plane normal
2718 VectorSubtract(shotend, shothit, refractend);
2719 s = refractiveindex / previousrefractiveindex;
2720 VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2721 // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2722 // calculate the new line start and end
2723 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2724 VectorAdd(refractstart, refractend, refractend);
2725 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2730 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2732 r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2734 R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2738 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2742 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2743 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2744 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);
2745 if (r_shadow_bouncegrid_threaded.integer)
2747 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2748 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2752 // when not threaded we still have to report task status
2753 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2754 r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2755 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2760 void R_Shadow_UpdateBounceGridTexture(void)
2762 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2763 r_shadow_bouncegrid_settings_t settings;
2764 qboolean enable = false;
2765 qboolean settingschanged;
2767 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2769 R_Shadow_BounceGrid_GenerateSettings(&settings);
2771 // changing intensity does not require an update
2772 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2774 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2776 // when settings change, we free everything as it is just simpler that way.
2777 if (settingschanged || !enable)
2779 // not enabled, make sure we free anything we don't need anymore.
2780 if (r_shadow_bouncegrid_state.texture)
2782 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2783 r_shadow_bouncegrid_state.texture = NULL;
2785 r_shadow_bouncegrid_state.highpixels = NULL;
2786 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2787 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2788 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2789 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2790 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2791 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2792 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2793 r_shadow_bouncegrid_state.numpixels = 0;
2794 r_shadow_bouncegrid_state.numphotons = 0;
2795 r_shadow_bouncegrid_state.directional = false;
2801 // if all the settings seem identical to the previous update, return
2802 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2805 // store the new settings
2806 r_shadow_bouncegrid_state.settings = settings;
2808 R_Shadow_BounceGrid_UpdateSpacing();
2810 // allocate the highpixels array we'll be accumulating light into
2811 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2812 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2813 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2814 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2815 r_shadow_bouncegrid_state.highpixels_index = 0;
2816 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2818 // set up the tracking of photon data
2819 if (r_shadow_bouncegrid_state.photons == NULL)
2820 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));
2821 if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2822 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2823 r_shadow_bouncegrid_state.numphotons = 0;
2825 // set up the tracking of slice tasks
2826 if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2827 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2829 memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2830 memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2831 memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2832 memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2833 memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2834 memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2835 memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2836 memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2837 memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2839 // clear the texture
2840 TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2841 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2843 // calculate weighting factors for distributing photons among the lights
2844 TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2845 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2847 // enqueue tasks to trace the photons from lights
2848 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2849 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2851 // accumulate the light paths into texture
2852 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);
2853 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2855 // apply a mild blur filter to the texture
2856 TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2857 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2859 TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2860 R_TimeReport("bouncegrid_gen");
2862 // convert the pixels to lower precision and upload the texture
2863 // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2864 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2865 R_TimeReport("bouncegrid_tex");
2867 // after we compute the static lighting we don't need to keep the highpixels array around
2868 if (settings.staticmode)
2870 r_shadow_bouncegrid_state.highpixels = NULL;
2871 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2872 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2873 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2874 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2875 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2876 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2877 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2881 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2883 R_Shadow_RenderMode_Reset();
2884 GL_BlendFunc(GL_ONE, GL_ONE);
2885 GL_DepthRange(0, 1);
2886 GL_DepthTest(r_showlighting.integer < 2);
2887 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2889 GL_DepthFunc(GL_EQUAL);
2890 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2893 void R_Shadow_RenderMode_End(void)
2895 R_Shadow_RenderMode_Reset();
2896 R_Shadow_RenderMode_ActiveLight(NULL);
2898 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2899 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2902 int bboxedges[12][2] =
2921 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2923 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2925 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2926 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2927 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2928 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2931 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2932 return true; // invisible
2933 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2934 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2935 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2936 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2937 r_refdef.stats[r_stat_lights_scissored]++;
2941 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2943 // used to display how many times a surface is lit for level design purposes
2944 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2945 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2949 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])
2951 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2952 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2956 extern cvar_t gl_lightmaps;
2957 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2960 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2961 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2962 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2963 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2964 if (!r_shadow_usenormalmap.integer)
2966 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2967 VectorClear(diffusecolor);
2968 VectorClear(specularcolor);
2970 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2971 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2972 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2973 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2975 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2978 VectorNegate(ambientcolor, ambientcolor);
2979 VectorNegate(diffusecolor, diffusecolor);
2980 VectorNegate(specularcolor, specularcolor);
2981 GL_BlendEquationSubtract(true);
2983 RSurf_SetupDepthAndCulling();
2984 switch (r_shadow_rendermode)
2986 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2987 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2988 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2990 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2991 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2994 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2998 GL_BlendEquationSubtract(false);
3001 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)
3003 matrix4x4_t tempmatrix = *matrix;
3004 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3006 // if this light has been compiled before, free the associated data
3007 R_RTLight_Uncompile(rtlight);
3009 // clear it completely to avoid any lingering data
3010 memset(rtlight, 0, sizeof(*rtlight));
3012 // copy the properties
3013 rtlight->matrix_lighttoworld = tempmatrix;
3014 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3015 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3016 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3017 VectorCopy(color, rtlight->color);
3018 rtlight->cubemapname[0] = 0;
3019 if (cubemapname && cubemapname[0])
3020 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3021 rtlight->shadow = shadow;
3022 rtlight->corona = corona;
3023 rtlight->style = style;
3024 rtlight->isstatic = isstatic;
3025 rtlight->coronasizescale = coronasizescale;
3026 rtlight->ambientscale = ambientscale;
3027 rtlight->diffusescale = diffusescale;
3028 rtlight->specularscale = specularscale;
3029 rtlight->flags = flags;
3031 // compute derived data
3032 //rtlight->cullradius = rtlight->radius;
3033 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3034 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3035 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3036 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3037 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3038 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3039 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3042 // compiles rtlight geometry
3043 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3044 void R_RTLight_Compile(rtlight_t *rtlight)
3047 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3048 int lighttris, shadowtris;
3049 entity_render_t *ent = r_refdef.scene.worldentity;
3050 dp_model_t *model = r_refdef.scene.worldmodel;
3051 unsigned char *data;
3053 // compile the light
3054 rtlight->compiled = true;
3055 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3056 rtlight->static_numleafs = 0;
3057 rtlight->static_numleafpvsbytes = 0;
3058 rtlight->static_leaflist = NULL;
3059 rtlight->static_leafpvs = NULL;
3060 rtlight->static_numsurfaces = 0;
3061 rtlight->static_surfacelist = NULL;
3062 rtlight->static_shadowmap_receivers = 0x3F;
3063 rtlight->static_shadowmap_casters = 0x3F;
3064 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3065 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3066 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3067 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3068 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3069 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3071 if (model && model->GetLightInfo)
3073 // this variable must be set for the CompileShadowMap code
3074 r_shadow_compilingrtlight = rtlight;
3075 R_FrameData_SetMark();
3076 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);
3077 R_FrameData_ReturnToMark();
3078 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3079 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3080 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3081 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3082 rtlight->static_numsurfaces = numsurfaces;
3083 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3084 rtlight->static_numleafs = numleafs;
3085 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3086 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3087 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3088 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3089 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3090 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3091 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3092 if (rtlight->static_numsurfaces)
3093 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3094 if (rtlight->static_numleafs)
3095 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3096 if (rtlight->static_numleafpvsbytes)
3097 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3098 if (rtlight->static_numshadowtrispvsbytes)
3099 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3100 if (rtlight->static_numlighttrispvsbytes)
3101 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3102 R_FrameData_SetMark();
3103 if (model->CompileShadowMap && rtlight->shadow)
3104 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3105 R_FrameData_ReturnToMark();
3106 // now we're done compiling the rtlight
3107 r_shadow_compilingrtlight = NULL;
3111 // use smallest available cullradius - box radius or light radius
3112 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3113 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3116 if (rtlight->static_numlighttrispvsbytes)
3117 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3118 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3122 if (rtlight->static_numshadowtrispvsbytes)
3123 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3124 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3127 if (developer_extra.integer)
3128 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);
3131 void R_RTLight_Uncompile(rtlight_t *rtlight)
3133 if (rtlight->compiled)
3135 if (rtlight->static_meshchain_shadow_shadowmap)
3136 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3137 rtlight->static_meshchain_shadow_shadowmap = NULL;
3138 // these allocations are grouped
3139 if (rtlight->static_surfacelist)
3140 Mem_Free(rtlight->static_surfacelist);
3141 rtlight->static_numleafs = 0;
3142 rtlight->static_numleafpvsbytes = 0;
3143 rtlight->static_leaflist = NULL;
3144 rtlight->static_leafpvs = NULL;
3145 rtlight->static_numsurfaces = 0;
3146 rtlight->static_surfacelist = NULL;
3147 rtlight->static_numshadowtrispvsbytes = 0;
3148 rtlight->static_shadowtrispvs = NULL;
3149 rtlight->static_numlighttrispvsbytes = 0;
3150 rtlight->static_lighttrispvs = NULL;
3151 rtlight->compiled = false;
3155 void R_Shadow_UncompileWorldLights(void)
3159 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3160 for (lightindex = 0;lightindex < range;lightindex++)
3162 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3165 R_RTLight_Uncompile(&light->rtlight);
3169 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3173 // reset the count of frustum planes
3174 // see rtlight->cached_frustumplanes definition for how much this array
3176 rtlight->cached_numfrustumplanes = 0;
3178 if (r_trippy.integer)
3181 // haven't implemented a culling path for ortho rendering
3182 if (!r_refdef.view.useperspective)
3184 // check if the light is on screen and copy the 4 planes if it is
3185 for (i = 0;i < 4;i++)
3186 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3189 for (i = 0;i < 4;i++)
3190 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3195 // generate a deformed frustum that includes the light origin, this is
3196 // used to cull shadow casting surfaces that can not possibly cast a
3197 // shadow onto the visible light-receiving surfaces, which can be a
3200 // if the light origin is onscreen the result will be 4 planes exactly
3201 // if the light origin is offscreen on only one axis the result will
3202 // be exactly 5 planes (split-side case)
3203 // if the light origin is offscreen on two axes the result will be
3204 // exactly 4 planes (stretched corner case)
3205 for (i = 0;i < 4;i++)
3207 // quickly reject standard frustum planes that put the light
3208 // origin outside the frustum
3209 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3212 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3214 // if all the standard frustum planes were accepted, the light is onscreen
3215 // otherwise we need to generate some more planes below...
3216 if (rtlight->cached_numfrustumplanes < 4)
3218 // at least one of the stock frustum planes failed, so we need to
3219 // create one or two custom planes to enclose the light origin
3220 for (i = 0;i < 4;i++)
3222 // create a plane using the view origin and light origin, and a
3223 // single point from the frustum corner set
3224 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3225 VectorNormalize(plane.normal);
3226 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3227 // see if this plane is backwards and flip it if so
3228 for (j = 0;j < 4;j++)
3229 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3233 VectorNegate(plane.normal, plane.normal);
3235 // flipped plane, test again to see if it is now valid
3236 for (j = 0;j < 4;j++)
3237 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3239 // if the plane is still not valid, then it is dividing the
3240 // frustum and has to be rejected
3244 // we have created a valid plane, compute extra info
3245 PlaneClassify(&plane);
3247 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3249 // if we've found 5 frustum planes then we have constructed a
3250 // proper split-side case and do not need to keep searching for
3251 // planes to enclose the light origin
3252 if (rtlight->cached_numfrustumplanes == 5)
3260 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3262 plane = rtlight->cached_frustumplanes[i];
3263 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));
3268 // now add the light-space box planes if the light box is rotated, as any
3269 // caster outside the oriented light box is irrelevant (even if it passed
3270 // the worldspace light box, which is axial)
3271 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3273 for (i = 0;i < 6;i++)
3277 v[i >> 1] = (i & 1) ? -1 : 1;
3278 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3279 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3280 plane.dist = VectorNormalizeLength(plane.normal);
3281 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3282 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3288 // add the world-space reduced box planes
3289 for (i = 0;i < 6;i++)
3291 VectorClear(plane.normal);
3292 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3293 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3294 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3303 // reduce all plane distances to tightly fit the rtlight cull box, which
3305 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3306 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3307 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3308 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3309 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3310 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3311 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3312 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3313 oldnum = rtlight->cached_numfrustumplanes;
3314 rtlight->cached_numfrustumplanes = 0;
3315 for (j = 0;j < oldnum;j++)
3317 // find the nearest point on the box to this plane
3318 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3319 for (i = 1;i < 8;i++)
3321 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3322 if (bestdist > dist)
3325 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);
3326 // if the nearest point is near or behind the plane, we want this
3327 // plane, otherwise the plane is useless as it won't cull anything
3328 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3330 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3331 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3338 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3340 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3342 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3344 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3345 if (mesh->sidetotals[r_shadow_shadowmapside])
3348 GL_CullFace(GL_NONE);
3349 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3350 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3351 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);
3355 else if (r_refdef.scene.worldentity->model)
3356 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);
3358 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3361 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3363 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3364 vec_t relativeshadowradius;
3365 RSurf_ActiveModelEntity(ent, false, false, false);
3366 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3367 // we need to re-init the shader for each entity because the matrix changed
3368 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3369 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3370 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3371 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3372 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3373 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3374 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3375 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3376 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3379 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3381 // set up properties for rendering light onto this entity
3382 RSurf_ActiveModelEntity(ent, true, true, false);
3383 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3384 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3385 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3386 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3389 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3391 if (!r_refdef.scene.worldmodel->DrawLight)
3394 // set up properties for rendering light onto this entity
3395 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3396 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3397 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3398 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3399 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3401 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3403 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3406 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3408 dp_model_t *model = ent->model;
3409 if (!model->DrawLight)
3412 R_Shadow_SetupEntityLight(ent);
3414 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3416 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3419 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3423 int numleafs, numsurfaces;
3424 int *leaflist, *surfacelist;
3425 unsigned char *leafpvs;
3426 unsigned char *shadowtrispvs;
3427 unsigned char *lighttrispvs;
3428 //unsigned char *surfacesides;
3429 int numlightentities;
3430 int numlightentities_noselfshadow;
3431 int numshadowentities;
3432 int numshadowentities_noselfshadow;
3433 // FIXME: bounds check lightentities and shadowentities, etc.
3434 static entity_render_t *lightentities[MAX_EDICTS];
3435 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3436 static entity_render_t *shadowentities[MAX_EDICTS];
3437 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3439 qboolean castshadows;
3441 rtlight->draw = false;
3442 rtlight->cached_numlightentities = 0;
3443 rtlight->cached_numlightentities_noselfshadow = 0;
3444 rtlight->cached_numshadowentities = 0;
3445 rtlight->cached_numshadowentities_noselfshadow = 0;
3446 rtlight->cached_numsurfaces = 0;
3447 rtlight->cached_lightentities = NULL;
3448 rtlight->cached_lightentities_noselfshadow = NULL;
3449 rtlight->cached_shadowentities = NULL;
3450 rtlight->cached_shadowentities_noselfshadow = NULL;
3451 rtlight->cached_shadowtrispvs = NULL;
3452 rtlight->cached_lighttrispvs = NULL;
3453 rtlight->cached_surfacelist = NULL;
3454 rtlight->shadowmapsidesize = 0;
3456 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3457 // skip lights that are basically invisible (color 0 0 0)
3458 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3460 // loading is done before visibility checks because loading should happen
3461 // all at once at the start of a level, not when it stalls gameplay.
3462 // (especially important to benchmarks)
3464 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3466 if (rtlight->compiled)
3467 R_RTLight_Uncompile(rtlight);
3468 R_RTLight_Compile(rtlight);
3472 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3474 // look up the light style value at this time
3475 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3476 VectorScale(rtlight->color, f, rtlight->currentcolor);
3478 if (rtlight->selected)
3480 f = 2 + sin(realtime * M_PI * 4.0);
3481 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3485 // skip if lightstyle is currently off
3486 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3489 // skip processing on corona-only lights
3493 // skip if the light box is not touching any visible leafs
3494 if (r_shadow_culllights_pvs.integer
3495 && r_refdef.scene.worldmodel
3496 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3497 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3500 // skip if the light box is not visible to traceline
3501 if (r_shadow_culllights_trace.integer)
3503 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))
3504 rtlight->trace_timer = realtime;
3505 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3509 // skip if the light box is off screen
3510 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3513 // in the typical case this will be quickly replaced by GetLightInfo
3514 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3515 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3517 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3519 // 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
3520 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3523 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3525 // compiled light, world available and can receive realtime lighting
3526 // retrieve leaf information
3527 numleafs = rtlight->static_numleafs;
3528 leaflist = rtlight->static_leaflist;
3529 leafpvs = rtlight->static_leafpvs;
3530 numsurfaces = rtlight->static_numsurfaces;
3531 surfacelist = rtlight->static_surfacelist;
3532 //surfacesides = NULL;
3533 shadowtrispvs = rtlight->static_shadowtrispvs;
3534 lighttrispvs = rtlight->static_lighttrispvs;
3536 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3538 // dynamic light, world available and can receive realtime lighting
3539 // calculate lit surfaces and leafs
3540 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);
3541 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3542 leaflist = r_shadow_buffer_leaflist;
3543 leafpvs = r_shadow_buffer_leafpvs;
3544 surfacelist = r_shadow_buffer_surfacelist;
3545 //surfacesides = r_shadow_buffer_surfacesides;
3546 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3547 lighttrispvs = r_shadow_buffer_lighttrispvs;
3548 // if the reduced leaf bounds are offscreen, skip it
3549 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3560 //surfacesides = NULL;
3561 shadowtrispvs = NULL;
3562 lighttrispvs = NULL;
3564 // check if light is illuminating any visible leafs
3567 for (i = 0; i < numleafs; i++)
3568 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3574 // make a list of lit entities and shadow casting entities
3575 numlightentities = 0;
3576 numlightentities_noselfshadow = 0;
3577 numshadowentities = 0;
3578 numshadowentities_noselfshadow = 0;
3580 // add dynamic entities that are lit by the light
3581 for (i = 0; i < r_refdef.scene.numentities; i++)
3584 entity_render_t *ent = r_refdef.scene.entities[i];
3586 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3588 // skip the object entirely if it is not within the valid
3589 // shadow-casting region (which includes the lit region)
3590 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3592 if (!(model = ent->model))
3594 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3596 // this entity wants to receive light, is visible, and is
3597 // inside the light box
3598 // TODO: check if the surfaces in the model can receive light
3599 // so now check if it's in a leaf seen by the light
3600 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))
3602 if (ent->flags & RENDER_NOSELFSHADOW)
3603 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3605 lightentities[numlightentities++] = ent;
3606 // since it is lit, it probably also casts a shadow...
3607 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3608 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3609 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3611 // note: exterior models without the RENDER_NOSELFSHADOW
3612 // flag still create a RENDER_NOSELFSHADOW shadow but
3613 // are lit normally, this means that they are
3614 // self-shadowing but do not shadow other
3615 // RENDER_NOSELFSHADOW entities such as the gun
3616 // (very weird, but keeps the player shadow off the gun)
3617 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3618 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3620 shadowentities[numshadowentities++] = ent;
3623 else if (ent->flags & RENDER_SHADOW)
3625 // this entity is not receiving light, but may still need to
3627 // TODO: check if the surfaces in the model can cast shadow
3628 // now check if it is in a leaf seen by the light
3629 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))
3631 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3632 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3633 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3635 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3636 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3638 shadowentities[numshadowentities++] = ent;
3643 // return if there's nothing at all to light
3644 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3647 // count this light in the r_speeds
3648 r_refdef.stats[r_stat_lights]++;
3650 // flag it as worth drawing later
3651 rtlight->draw = true;
3653 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3654 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3656 numshadowentities = numshadowentities_noselfshadow = 0;
3657 rtlight->castshadows = castshadows;
3659 // cache all the animated entities that cast a shadow but are not visible
3660 for (i = 0; i < numshadowentities; i++)
3661 R_AnimCache_GetEntity(shadowentities[i], false, false);
3662 for (i = 0; i < numshadowentities_noselfshadow; i++)
3663 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3665 // 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)
3666 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3668 for (i = 0; i < numshadowentities_noselfshadow; i++)
3669 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3670 numshadowentities_noselfshadow = 0;
3673 // we can convert noselfshadow to regular if there are no casters of that type
3674 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3676 for (i = 0; i < numlightentities_noselfshadow; i++)
3677 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3678 numlightentities_noselfshadow = 0;
3681 // allocate some temporary memory for rendering this light later in the frame
3682 // reusable buffers need to be copied, static data can be used as-is
3683 rtlight->cached_numlightentities = numlightentities;
3684 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3685 rtlight->cached_numshadowentities = numshadowentities;
3686 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3687 rtlight->cached_numsurfaces = numsurfaces;
3688 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3689 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3690 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3691 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3692 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3694 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3695 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3696 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3697 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3698 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3702 // compiled light data
3703 rtlight->cached_shadowtrispvs = shadowtrispvs;
3704 rtlight->cached_lighttrispvs = lighttrispvs;
3705 rtlight->cached_surfacelist = surfacelist;
3708 if (R_Shadow_ShadowMappingEnabled())
3710 // figure out the shadowmapping parameters for this light
3711 vec3_t nearestpoint;
3714 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3715 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3716 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3717 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3718 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3719 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3720 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3721 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3722 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3726 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3730 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3731 int numlightentities;
3732 int numlightentities_noselfshadow;
3733 int numshadowentities;
3734 int numshadowentities_noselfshadow;
3735 entity_render_t **lightentities;
3736 entity_render_t **lightentities_noselfshadow;
3737 entity_render_t **shadowentities;
3738 entity_render_t **shadowentities_noselfshadow;
3740 static unsigned char entitysides[MAX_EDICTS];
3741 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3747 matrix4x4_t radiustolight;
3749 // check if we cached this light this frame (meaning it is worth drawing)
3750 if (!rtlight->draw || !rtlight->castshadows)
3753 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3754 if (rtlight->shadowmapatlassidesize == 0)
3756 rtlight->castshadows = false;
3760 // set up a scissor rectangle for this light
3761 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3764 // don't let sound skip if going slow
3765 if (r_refdef.scene.extraupdate)
3768 numlightentities = rtlight->cached_numlightentities;
3769 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3770 numshadowentities = rtlight->cached_numshadowentities;
3771 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3772 numsurfaces = rtlight->cached_numsurfaces;
3773 lightentities = rtlight->cached_lightentities;
3774 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3775 shadowentities = rtlight->cached_shadowentities;
3776 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3777 shadowtrispvs = rtlight->cached_shadowtrispvs;
3778 lighttrispvs = rtlight->cached_lighttrispvs;
3779 surfacelist = rtlight->cached_surfacelist;
3781 // make this the active rtlight for rendering purposes
3782 R_Shadow_RenderMode_ActiveLight(rtlight);
3784 radiustolight = rtlight->matrix_worldtolight;
3785 Matrix4x4_Abs(&radiustolight);
3787 size = rtlight->shadowmapatlassidesize;
3788 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3790 surfacesides = NULL;
3795 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3797 castermask = rtlight->static_shadowmap_casters;
3798 receivermask = rtlight->static_shadowmap_receivers;
3802 surfacesides = r_shadow_buffer_surfacesides;
3803 for (i = 0; i < numsurfaces; i++)
3805 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3806 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3807 castermask |= surfacesides[i];
3808 receivermask |= surfacesides[i];
3813 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3814 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3815 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3816 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3818 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3822 for (i = 0; i < numshadowentities; i++)
3823 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3824 for (i = 0; i < numshadowentities_noselfshadow; i++)
3825 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3828 // there is no need to render shadows for sides that have no receivers...
3829 castermask &= receivermask;
3831 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3833 // render shadow casters into shadowmaps for this light
3834 for (side = 0; side < 6; side++)
3836 int bit = 1 << side;
3837 if (castermask & bit)
3839 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3841 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3842 for (i = 0; i < numshadowentities; i++)
3843 if (entitysides[i] & bit)
3844 R_Shadow_DrawEntityShadow(shadowentities[i]);
3845 for (i = 0; i < numshadowentities_noselfshadow; i++)
3846 if (entitysides_noselfshadow[i] & bit)
3847 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3850 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3851 if (numshadowentities_noselfshadow)
3853 for (side = 0; side < 6; side++)
3855 int bit = 1 << side;
3856 if (castermask & bit)
3858 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3860 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3861 for (i = 0; i < numshadowentities; i++)
3862 if (entitysides[i] & bit)
3863 R_Shadow_DrawEntityShadow(shadowentities[i]);
3869 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3873 unsigned char *shadowtrispvs, *lighttrispvs;
3874 int numlightentities;
3875 int numlightentities_noselfshadow;
3876 int numshadowentities;
3877 int numshadowentities_noselfshadow;
3878 entity_render_t **lightentities;
3879 entity_render_t **lightentities_noselfshadow;
3880 entity_render_t **shadowentities;
3881 entity_render_t **shadowentities_noselfshadow;
3883 qboolean castshadows;
3885 // check if we cached this light this frame (meaning it is worth drawing)
3889 // set up a scissor rectangle for this light
3890 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3893 // don't let sound skip if going slow
3894 if (r_refdef.scene.extraupdate)
3897 numlightentities = rtlight->cached_numlightentities;
3898 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3899 numshadowentities = rtlight->cached_numshadowentities;
3900 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3901 numsurfaces = rtlight->cached_numsurfaces;
3902 lightentities = rtlight->cached_lightentities;
3903 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3904 shadowentities = rtlight->cached_shadowentities;
3905 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3906 shadowtrispvs = rtlight->cached_shadowtrispvs;
3907 lighttrispvs = rtlight->cached_lighttrispvs;
3908 surfacelist = rtlight->cached_surfacelist;
3909 castshadows = rtlight->castshadows;
3911 // make this the active rtlight for rendering purposes
3912 R_Shadow_RenderMode_ActiveLight(rtlight);
3914 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3916 // optionally draw the illuminated areas
3917 // for performance analysis by level designers
3918 R_Shadow_RenderMode_VisibleLighting(false);
3920 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3921 for (i = 0;i < numlightentities;i++)
3922 R_Shadow_DrawEntityLight(lightentities[i]);
3923 for (i = 0;i < numlightentities_noselfshadow;i++)
3924 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3927 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3931 float shadowmapoffsetnoselfshadow = 0;
3932 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3933 Matrix4x4_Abs(&radiustolight);
3935 size = rtlight->shadowmapatlassidesize;
3936 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3938 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3940 if (rtlight->cached_numshadowentities_noselfshadow)
3941 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3943 // render lighting using the depth texture as shadowmap
3944 // draw lighting in the unmasked areas
3945 if (numsurfaces + numlightentities)
3947 R_Shadow_RenderMode_Lighting(false, true, false);
3948 // draw lighting in the unmasked areas
3950 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3951 for (i = 0; i < numlightentities; i++)
3952 R_Shadow_DrawEntityLight(lightentities[i]);
3954 // offset to the noselfshadow part of the atlas and draw those too
3955 if (numlightentities_noselfshadow)
3957 R_Shadow_RenderMode_Lighting(false, true, true);
3958 for (i = 0; i < numlightentities_noselfshadow; i++)
3959 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3962 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3963 if (r_shadow_usingdeferredprepass)
3964 R_Shadow_RenderMode_DrawDeferredLight(true);
3968 // draw lighting in the unmasked areas
3969 R_Shadow_RenderMode_Lighting(false, false, false);
3971 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3972 for (i = 0;i < numlightentities;i++)
3973 R_Shadow_DrawEntityLight(lightentities[i]);
3974 for (i = 0;i < numlightentities_noselfshadow;i++)
3975 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3977 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3978 if (r_shadow_usingdeferredprepass)
3979 R_Shadow_RenderMode_DrawDeferredLight(false);
3983 static void R_Shadow_FreeDeferred(void)
3985 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3986 r_shadow_prepassgeometryfbo = 0;
3988 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3989 r_shadow_prepasslightingdiffusespecularfbo = 0;
3991 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3992 r_shadow_prepasslightingdiffusefbo = 0;
3994 if (r_shadow_prepassgeometrydepthbuffer)
3995 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3996 r_shadow_prepassgeometrydepthbuffer = NULL;
3998 if (r_shadow_prepassgeometrynormalmaptexture)
3999 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4000 r_shadow_prepassgeometrynormalmaptexture = NULL;
4002 if (r_shadow_prepasslightingdiffusetexture)
4003 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4004 r_shadow_prepasslightingdiffusetexture = NULL;
4006 if (r_shadow_prepasslightingspeculartexture)
4007 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4008 r_shadow_prepasslightingspeculartexture = NULL;
4011 void R_Shadow_DrawPrepass(void)
4015 entity_render_t *ent;
4016 float clearcolor[4];
4018 R_Mesh_ResetTextureState();
4020 GL_ColorMask(1,1,1,1);
4021 GL_BlendFunc(GL_ONE, GL_ZERO);
4024 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4025 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4026 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4027 if (r_timereport_active)
4028 R_TimeReport("prepasscleargeom");
4030 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4031 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4032 if (r_timereport_active)
4033 R_TimeReport("prepassworld");
4035 for (i = 0;i < r_refdef.scene.numentities;i++)
4037 if (!r_refdef.viewcache.entityvisible[i])
4039 ent = r_refdef.scene.entities[i];
4040 if (ent->model && ent->model->DrawPrepass != NULL)
4041 ent->model->DrawPrepass(ent);
4044 if (r_timereport_active)
4045 R_TimeReport("prepassmodels");
4047 GL_DepthMask(false);
4048 GL_ColorMask(1,1,1,1);
4051 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4052 Vector4Set(clearcolor, 0, 0, 0, 0);
4053 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4054 if (r_timereport_active)
4055 R_TimeReport("prepassclearlit");
4057 R_Shadow_RenderMode_Begin();
4059 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4060 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4062 R_Shadow_RenderMode_End();
4064 if (r_timereport_active)
4065 R_TimeReport("prepasslights");
4068 #define MAX_SCENELIGHTS 65536
4069 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4071 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4073 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4075 r_shadow_scenemaxlights *= 2;
4076 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4077 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4079 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4083 void R_Shadow_DrawLightSprites(void);
4084 void R_Shadow_PrepareLights(void)
4093 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4094 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4095 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4097 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4098 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4099 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4100 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4101 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4102 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4103 r_shadow_shadowmapborder != shadowmapborder ||
4104 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4105 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4106 R_Shadow_FreeShadowMaps();
4108 r_shadow_usingshadowmaportho = false;
4110 switch (vid.renderpath)
4112 case RENDERPATH_GL32:
4114 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4116 r_shadow_usingdeferredprepass = false;
4117 if (r_shadow_prepass_width)
4118 R_Shadow_FreeDeferred();
4119 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4123 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4125 R_Shadow_FreeDeferred();
4127 r_shadow_usingdeferredprepass = true;
4128 r_shadow_prepass_width = vid.width;
4129 r_shadow_prepass_height = vid.height;
4130 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4131 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);
4132 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);
4133 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);
4135 // set up the geometry pass fbo (depth + normalmap)
4136 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4137 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4138 // render depth into a renderbuffer and other important properties into the normalmap texture
4140 // set up the lighting pass fbo (diffuse + specular)
4141 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4142 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4143 // render diffuse into one texture and specular into another,
4144 // with depth and normalmap bound as textures,
4145 // with depth bound as attachment as well
4147 // set up the lighting pass fbo (diffuse)
4148 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4149 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4150 // render diffuse into one texture,
4151 // with depth and normalmap bound as textures,
4152 // with depth bound as attachment as well
4156 case RENDERPATH_GLES2:
4157 r_shadow_usingdeferredprepass = false;
4161 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);
4163 r_shadow_scenenumlights = 0;
4164 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4165 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4166 for (lightindex = 0; lightindex < range; lightindex++)
4168 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4169 if (light && (light->flags & flag))
4171 R_Shadow_PrepareLight(&light->rtlight);
4172 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4175 if (r_refdef.scene.rtdlight)
4177 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4179 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4180 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4183 else if (gl_flashblend.integer)
4185 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4187 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4188 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4189 VectorScale(rtlight->color, f, rtlight->currentcolor);
4193 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4194 if (r_shadow_debuglight.integer >= 0)
4196 r_shadow_scenenumlights = 0;
4197 lightindex = r_shadow_debuglight.integer;
4198 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4201 R_Shadow_PrepareLight(&light->rtlight);
4202 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4206 // if we're doing shadowmaps we need to prepare the atlas layout now
4207 if (R_Shadow_ShadowMappingEnabled())
4211 // allocate shadowmaps in the atlas now
4212 // 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...
4213 for (lod = 0; lod < 16; lod++)
4215 int packing_success = 0;
4216 int packing_failure = 0;
4217 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4218 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4219 if (r_shadow_shadowmapatlas_modelshadows_size)
4220 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);
4221 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4223 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4224 int size = rtlight->shadowmapsidesize >> lod;
4226 if (!rtlight->castshadows)
4228 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4231 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4232 if (rtlight->cached_numshadowentities_noselfshadow)
4234 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4236 rtlight->shadowmapatlassidesize = size;
4241 // note down that we failed to pack this one, it will have to disable shadows
4242 rtlight->shadowmapatlassidesize = 0;
4246 // generally everything fits and we stop here on the first iteration
4247 if (packing_failure == 0)
4252 if (r_editlights.integer)
4253 R_Shadow_DrawLightSprites();
4256 void R_Shadow_DrawShadowMaps(void)
4258 R_Shadow_RenderMode_Begin();
4259 R_Shadow_RenderMode_ActiveLight(NULL);
4261 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4262 R_Shadow_ClearShadowMapTexture();
4264 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4265 if (r_shadow_shadowmapatlas_modelshadows_size)
4267 R_Shadow_DrawModelShadowMaps();
4268 // don't let sound skip if going slow
4269 if (r_refdef.scene.extraupdate)
4273 if (R_Shadow_ShadowMappingEnabled())
4276 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4277 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4280 R_Shadow_RenderMode_End();
4283 void R_Shadow_DrawLights(void)
4287 R_Shadow_RenderMode_Begin();
4289 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4290 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4292 R_Shadow_RenderMode_End();
4295 #define MAX_MODELSHADOWS 1024
4296 static int r_shadow_nummodelshadows;
4297 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4299 void R_Shadow_PrepareModelShadows(void)
4302 float scale, size, radius, dot1, dot2;
4303 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4304 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4305 entity_render_t *ent;
4307 r_shadow_nummodelshadows = 0;
4308 r_shadow_shadowmapatlas_modelshadows_size = 0;
4310 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4313 size = r_shadow_shadowmaptexturesize / 4;
4314 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4315 radius = 0.5f * size / scale;
4317 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4318 VectorCopy(prvmshadowdir, shadowdir);
4319 VectorNormalize(shadowdir);
4320 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4321 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4322 if (fabs(dot1) <= fabs(dot2))
4323 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4325 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4326 VectorNormalize(shadowforward);
4327 CrossProduct(shadowdir, shadowforward, shadowright);
4328 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4329 VectorCopy(prvmshadowfocus, shadowfocus);
4330 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4331 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4332 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4333 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4334 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4336 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4338 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4339 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4340 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4341 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4342 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4343 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4345 for (i = 0; i < r_refdef.scene.numentities; i++)
4347 ent = r_refdef.scene.entities[i];
4348 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4350 // cast shadows from anything of the map (submodels are optional)
4351 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4353 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4355 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4356 R_AnimCache_GetEntity(ent, false, false);
4360 if (r_shadow_nummodelshadows)
4362 r_shadow_shadowmapatlas_modelshadows_x = 0;
4363 r_shadow_shadowmapatlas_modelshadows_y = 0;
4364 r_shadow_shadowmapatlas_modelshadows_size = size;
4368 static void R_Shadow_DrawModelShadowMaps(void)
4371 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4372 entity_render_t *ent;
4373 vec3_t relativelightorigin;
4374 vec3_t relativelightdirection, relativeforward, relativeright;
4375 vec3_t relativeshadowmins, relativeshadowmaxs;
4376 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4377 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4379 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4380 r_viewport_t viewport;
4382 size = r_shadow_shadowmapatlas_modelshadows_size;
4383 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4384 radius = 0.5f / scale;
4385 nearclip = -r_shadows_throwdistance.value;
4386 farclip = r_shadows_throwdistance.value;
4387 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);
4389 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4390 r_shadow_modelshadowmap_parameters[0] = size;
4391 r_shadow_modelshadowmap_parameters[1] = size;
4392 r_shadow_modelshadowmap_parameters[2] = 1.0;
4393 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4394 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4395 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4396 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4397 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4398 r_shadow_usingshadowmaportho = true;
4400 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4401 VectorCopy(prvmshadowdir, shadowdir);
4402 VectorNormalize(shadowdir);
4403 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4404 VectorCopy(prvmshadowfocus, shadowfocus);
4405 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4406 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4407 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4408 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4409 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4410 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4411 if (fabs(dot1) <= fabs(dot2))
4412 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4414 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4415 VectorNormalize(shadowforward);
4416 VectorM(scale, shadowforward, &m[0]);
4417 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4419 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4420 CrossProduct(shadowdir, shadowforward, shadowright);
4421 VectorM(scale, shadowright, &m[4]);
4422 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4423 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4424 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4425 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4426 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4427 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);
4428 R_SetViewport(&viewport);
4430 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4432 // render into a slightly restricted region so that the borders of the
4433 // shadowmap area fade away, rather than streaking across everything
4434 // outside the usable area
4435 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4437 for (i = 0;i < r_shadow_nummodelshadows;i++)
4439 ent = r_shadow_modelshadows[i];
4440 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4441 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4442 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4443 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4444 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4445 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4446 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4447 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4448 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4449 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4450 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4451 RSurf_ActiveModelEntity(ent, false, false, false);
4452 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4453 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4459 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4461 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4463 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4464 Cvar_SetValueQuick(&r_test, 0);
4469 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4470 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4471 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4472 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4473 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4474 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4477 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4480 vec3_t centerorigin;
4484 // if it's too close, skip it
4485 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4487 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4490 if (usequery && r_numqueries + 2 <= r_maxqueries)
4492 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4493 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4494 // 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
4495 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4497 switch(vid.renderpath)
4499 case RENDERPATH_GL32:
4500 case RENDERPATH_GLES2:
4503 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4504 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4505 GL_DepthFunc(GL_ALWAYS);
4506 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4507 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4508 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4509 qglEndQuery(GL_SAMPLES_PASSED);
4510 GL_DepthFunc(GL_LEQUAL);
4511 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4512 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4513 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4514 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4515 qglEndQuery(GL_SAMPLES_PASSED);
4521 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4524 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4526 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4529 unsigned int occlude = 0;
4531 // now we have to check the query result
4532 if (rtlight->corona_queryindex_visiblepixels)
4534 switch(vid.renderpath)
4536 case RENDERPATH_GL32:
4537 case RENDERPATH_GLES2:
4539 // store the pixel counts into a uniform buffer for the shader to
4540 // use - we'll never know the results on the cpu without
4541 // synchronizing and we don't want that
4542 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4543 if (!r_shadow_occlusion_buf) {
4544 qglGenBuffers(1, &r_shadow_occlusion_buf);
4545 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4546 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4548 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4550 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4551 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4552 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4553 occlude = MATERIALFLAG_OCCLUDE;
4554 cscale *= rtlight->corona_visibility;
4564 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4567 VectorScale(rtlight->currentcolor, cscale, color);
4568 if (VectorLength(color) > (1.0f / 256.0f))
4571 qboolean negated = (color[0] + color[1] + color[2] < 0);
4574 VectorNegate(color, color);
4575 GL_BlendEquationSubtract(true);
4577 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4578 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);
4579 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4581 GL_BlendEquationSubtract(false);
4585 void R_Shadow_DrawCoronas(void)
4588 qboolean usequery = false;
4593 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4595 if (r_fb.water.renderingscene)
4597 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4598 R_EntityMatrix(&identitymatrix);
4600 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4602 // check occlusion of coronas, using occlusion queries or raytraces
4604 switch (vid.renderpath)
4606 case RENDERPATH_GL32:
4607 case RENDERPATH_GLES2:
4608 usequery = r_coronas_occlusionquery.integer;
4612 GL_ColorMask(0,0,0,0);
4613 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4614 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4617 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4618 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4620 qglGenQueries(r_maxqueries - i, r_queries + i);
4623 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4624 GL_BlendFunc(GL_ONE, GL_ZERO);
4625 GL_CullFace(GL_NONE);
4626 GL_DepthMask(false);
4627 GL_DepthRange(0, 1);
4628 GL_PolygonOffset(0, 0);
4630 R_Mesh_ResetTextureState();
4631 R_SetupShader_Generic_NoTexture(false, false);
4636 for (lightindex = 0;lightindex < range;lightindex++)
4638 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4641 rtlight = &light->rtlight;
4642 rtlight->corona_visibility = 0;
4643 rtlight->corona_queryindex_visiblepixels = 0;
4644 rtlight->corona_queryindex_allpixels = 0;
4645 if (!(rtlight->flags & flag))
4647 if (rtlight->corona <= 0)
4649 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4651 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4653 for (i = 0;i < r_refdef.scene.numlights;i++)
4655 rtlight = r_refdef.scene.lights[i];
4656 rtlight->corona_visibility = 0;
4657 rtlight->corona_queryindex_visiblepixels = 0;
4658 rtlight->corona_queryindex_allpixels = 0;
4659 if (!(rtlight->flags & flag))
4661 if (rtlight->corona <= 0)
4663 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4666 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4668 // now draw the coronas using the query data for intensity info
4669 for (lightindex = 0;lightindex < range;lightindex++)
4671 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4674 rtlight = &light->rtlight;
4675 if (rtlight->corona_visibility <= 0)
4677 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4679 for (i = 0;i < r_refdef.scene.numlights;i++)
4681 rtlight = r_refdef.scene.lights[i];
4682 if (rtlight->corona_visibility <= 0)
4684 if (gl_flashblend.integer)
4685 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4687 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4693 static dlight_t *R_Shadow_NewWorldLight(void)
4695 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4698 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)
4702 // 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
4704 // validate parameters
4708 // copy to light properties
4709 VectorCopy(origin, light->origin);
4710 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4711 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4712 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4714 light->color[0] = max(color[0], 0);
4715 light->color[1] = max(color[1], 0);
4716 light->color[2] = max(color[2], 0);
4718 light->color[0] = color[0];
4719 light->color[1] = color[1];
4720 light->color[2] = color[2];
4721 light->radius = max(radius, 0);
4722 light->style = style;
4723 light->shadow = shadowenable;
4724 light->corona = corona;
4725 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4726 light->coronasizescale = coronasizescale;
4727 light->ambientscale = ambientscale;
4728 light->diffusescale = diffusescale;
4729 light->specularscale = specularscale;
4730 light->flags = flags;
4732 // update renderable light data
4733 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4734 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);
4737 static void R_Shadow_FreeWorldLight(dlight_t *light)
4739 if (r_shadow_selectedlight == light)
4740 r_shadow_selectedlight = NULL;
4741 R_RTLight_Uncompile(&light->rtlight);
4742 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4745 void R_Shadow_ClearWorldLights(void)
4749 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4750 for (lightindex = 0;lightindex < range;lightindex++)
4752 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4754 R_Shadow_FreeWorldLight(light);
4756 r_shadow_selectedlight = NULL;
4759 static void R_Shadow_SelectLight(dlight_t *light)
4761 if (r_shadow_selectedlight)
4762 r_shadow_selectedlight->selected = false;
4763 r_shadow_selectedlight = light;
4764 if (r_shadow_selectedlight)
4765 r_shadow_selectedlight->selected = true;
4768 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4770 // this is never batched (there can be only one)
4772 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4773 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4774 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4777 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4782 skinframe_t *skinframe;
4785 // this is never batched (due to the ent parameter changing every time)
4786 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4787 const dlight_t *light = (dlight_t *)ent;
4790 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4793 VectorScale(light->color, intensity, spritecolor);
4794 if (VectorLength(spritecolor) < 0.1732f)
4795 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4796 if (VectorLength(spritecolor) > 1.0f)
4797 VectorNormalize(spritecolor);
4799 // draw light sprite
4800 if (light->cubemapname[0] && !light->shadow)
4801 skinframe = r_editlights_sprcubemapnoshadowlight;
4802 else if (light->cubemapname[0])
4803 skinframe = r_editlights_sprcubemaplight;
4804 else if (!light->shadow)
4805 skinframe = r_editlights_sprnoshadowlight;
4807 skinframe = r_editlights_sprlight;
4809 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);
4810 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4812 // draw selection sprite if light is selected
4813 if (light->selected)
4815 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4816 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4817 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4821 void R_Shadow_DrawLightSprites(void)
4825 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4826 for (lightindex = 0;lightindex < range;lightindex++)
4828 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4830 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4832 if (!r_editlights_lockcursor)
4833 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4836 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4841 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4842 if (lightindex >= range)
4844 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4847 rtlight = &light->rtlight;
4848 //if (!(rtlight->flags & flag))
4850 VectorCopy(rtlight->shadoworigin, origin);
4851 *radius = rtlight->radius;
4852 VectorCopy(rtlight->color, color);
4856 static void R_Shadow_SelectLightInView(void)
4858 float bestrating, rating, temp[3];
4862 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4866 if (r_editlights_lockcursor)
4868 for (lightindex = 0;lightindex < range;lightindex++)
4870 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4873 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4874 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4877 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4878 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)
4880 bestrating = rating;
4885 R_Shadow_SelectLight(best);
4888 void R_Shadow_LoadWorldLights(void)
4890 int n, a, style, shadow, flags;
4891 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4892 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4893 if (cl.worldmodel == NULL)
4895 Con_Print("No map loaded.\n");
4898 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4899 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4909 for (;COM_Parse(t, true) && strcmp(
4910 if (COM_Parse(t, true))
4912 if (com_token[0] == '!')
4915 origin[0] = atof(com_token+1);
4918 origin[0] = atof(com_token);
4923 while (*s && *s != '\n' && *s != '\r')
4929 // check for modifier flags
4936 #if _MSC_VER >= 1400
4937 #define sscanf sscanf_s
4939 cubemapname[sizeof(cubemapname)-1] = 0;
4940 #if MAX_QPATH != 128
4941 #error update this code if MAX_QPATH changes
4943 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
4944 #if _MSC_VER >= 1400
4945 , (unsigned int)sizeof(cubemapname)
4947 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4950 flags = LIGHTFLAG_REALTIMEMODE;
4958 coronasizescale = 0.25f;
4960 VectorClear(angles);
4963 if (a < 9 || !strcmp(cubemapname, "\"\""))
4965 // remove quotes on cubemapname
4966 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4969 namelen = strlen(cubemapname) - 2;
4970 memmove(cubemapname, cubemapname + 1, namelen);
4971 cubemapname[namelen] = '\0';
4975 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);
4978 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4986 Con_Printf("invalid rtlights file \"%s\"\n", name);
4987 Mem_Free(lightsstring);
4991 void R_Shadow_SaveWorldLights(void)
4995 size_t bufchars, bufmaxchars;
4997 char name[MAX_QPATH];
4998 char line[MAX_INPUTLINE];
4999 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5000 // I hate lines which are 3 times my screen size :( --blub
5003 if (cl.worldmodel == NULL)
5005 Con_Print("No map loaded.\n");
5008 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5009 bufchars = bufmaxchars = 0;
5011 for (lightindex = 0;lightindex < range;lightindex++)
5013 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5016 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5017 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);
5018 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5019 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]);
5021 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);
5022 if (bufchars + strlen(line) > bufmaxchars)
5024 bufmaxchars = bufchars + strlen(line) + 2048;
5026 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5030 memcpy(buf, oldbuf, bufchars);
5036 memcpy(buf + bufchars, line, strlen(line));
5037 bufchars += strlen(line);
5041 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5046 void R_Shadow_LoadLightsFile(void)
5049 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5050 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5051 if (cl.worldmodel == NULL)
5053 Con_Print("No map loaded.\n");
5056 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5057 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5065 while (*s && *s != '\n' && *s != '\r')
5071 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);
5075 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);
5078 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5079 radius = bound(15, radius, 4096);
5080 VectorScale(color, (2.0f / (8388608.0f)), color);
5081 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5089 Con_Printf("invalid lights file \"%s\"\n", name);
5090 Mem_Free(lightsstring);
5094 // tyrlite/hmap2 light types in the delay field
5095 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5097 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5109 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5110 char key[256], value[MAX_INPUTLINE];
5113 if (cl.worldmodel == NULL)
5115 Con_Print("No map loaded.\n");
5118 // try to load a .ent file first
5119 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5120 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5121 // and if that is not found, fall back to the bsp file entity string
5123 data = cl.worldmodel->brush.entities;
5126 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5128 type = LIGHTTYPE_MINUSX;
5129 origin[0] = origin[1] = origin[2] = 0;
5130 originhack[0] = originhack[1] = originhack[2] = 0;
5131 angles[0] = angles[1] = angles[2] = 0;
5132 color[0] = color[1] = color[2] = 1;
5133 light[0] = light[1] = light[2] = 1;light[3] = 300;
5134 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5144 if (!COM_ParseToken_Simple(&data, false, false, true))
5146 if (com_token[0] == '}')
5147 break; // end of entity
5148 if (com_token[0] == '_')
5149 strlcpy(key, com_token + 1, sizeof(key));
5151 strlcpy(key, com_token, sizeof(key));
5152 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5153 key[strlen(key)-1] = 0;
5154 if (!COM_ParseToken_Simple(&data, false, false, true))
5156 strlcpy(value, com_token, sizeof(value));
5158 // now that we have the key pair worked out...
5159 if (!strcmp("light", key))
5161 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5165 light[0] = vec[0] * (1.0f / 256.0f);
5166 light[1] = vec[0] * (1.0f / 256.0f);
5167 light[2] = vec[0] * (1.0f / 256.0f);
5173 light[0] = vec[0] * (1.0f / 255.0f);
5174 light[1] = vec[1] * (1.0f / 255.0f);
5175 light[2] = vec[2] * (1.0f / 255.0f);
5179 else if (!strcmp("delay", key))
5181 else if (!strcmp("origin", key))
5182 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5183 else if (!strcmp("angle", key))
5184 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5185 else if (!strcmp("angles", key))
5186 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5187 else if (!strcmp("color", key))
5188 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5189 else if (!strcmp("wait", key))
5190 fadescale = atof(value);
5191 else if (!strcmp("classname", key))
5193 if (!strncmp(value, "light", 5))
5196 if (!strcmp(value, "light_fluoro"))
5201 overridecolor[0] = 1;
5202 overridecolor[1] = 1;
5203 overridecolor[2] = 1;
5205 if (!strcmp(value, "light_fluorospark"))
5210 overridecolor[0] = 1;
5211 overridecolor[1] = 1;
5212 overridecolor[2] = 1;
5214 if (!strcmp(value, "light_globe"))
5219 overridecolor[0] = 1;
5220 overridecolor[1] = 0.8;
5221 overridecolor[2] = 0.4;
5223 if (!strcmp(value, "light_flame_large_yellow"))
5228 overridecolor[0] = 1;
5229 overridecolor[1] = 0.5;
5230 overridecolor[2] = 0.1;
5232 if (!strcmp(value, "light_flame_small_yellow"))
5237 overridecolor[0] = 1;
5238 overridecolor[1] = 0.5;
5239 overridecolor[2] = 0.1;
5241 if (!strcmp(value, "light_torch_small_white"))
5246 overridecolor[0] = 1;
5247 overridecolor[1] = 0.5;
5248 overridecolor[2] = 0.1;
5250 if (!strcmp(value, "light_torch_small_walltorch"))
5255 overridecolor[0] = 1;
5256 overridecolor[1] = 0.5;
5257 overridecolor[2] = 0.1;
5261 else if (!strcmp("style", key))
5262 style = atoi(value);
5263 else if (!strcmp("skin", key))
5264 skin = (int)atof(value);
5265 else if (!strcmp("pflags", key))
5266 pflags = (int)atof(value);
5267 //else if (!strcmp("effects", key))
5268 // effects = (int)atof(value);
5269 else if (cl.worldmodel->type == mod_brushq3)
5271 if (!strcmp("scale", key))
5272 lightscale = atof(value);
5273 if (!strcmp("fade", key))
5274 fadescale = atof(value);
5279 if (lightscale <= 0)
5283 if (color[0] == color[1] && color[0] == color[2])
5285 color[0] *= overridecolor[0];
5286 color[1] *= overridecolor[1];
5287 color[2] *= overridecolor[2];
5289 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5290 color[0] = color[0] * light[0];
5291 color[1] = color[1] * light[1];
5292 color[2] = color[2] * light[2];
5295 case LIGHTTYPE_MINUSX:
5297 case LIGHTTYPE_RECIPX:
5299 VectorScale(color, (1.0f / 16.0f), color);
5301 case LIGHTTYPE_RECIPXX:
5303 VectorScale(color, (1.0f / 16.0f), color);
5306 case LIGHTTYPE_NONE:
5310 case LIGHTTYPE_MINUSXX:
5313 VectorAdd(origin, originhack, origin);
5315 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);
5318 Mem_Free(entfiledata);
5322 static void R_Shadow_SetCursorLocationForView(void)
5325 vec3_t dest, endpos;
5327 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5328 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5329 if (trace.fraction < 1)
5331 dist = trace.fraction * r_editlights_cursordistance.value;
5332 push = r_editlights_cursorpushback.value;
5336 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5337 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5341 VectorClear( endpos );
5343 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5344 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5345 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5348 void R_Shadow_UpdateWorldLightSelection(void)
5350 if (r_editlights.integer)
5352 R_Shadow_SetCursorLocationForView();
5353 R_Shadow_SelectLightInView();
5356 R_Shadow_SelectLight(NULL);
5359 static void R_Shadow_EditLights_Clear_f(cmd_state_t *cmd)
5361 R_Shadow_ClearWorldLights();
5364 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd)
5368 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5369 R_Shadow_ClearWorldLights();
5370 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5372 R_Shadow_LoadWorldLights();
5373 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5374 R_Shadow_LoadLightsFile();
5376 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5378 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5379 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5383 static void R_Shadow_EditLights_Save_f(cmd_state_t *cmd)
5387 R_Shadow_SaveWorldLights();
5390 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(cmd_state_t *cmd)
5392 R_Shadow_ClearWorldLights();
5393 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5396 static void R_Shadow_EditLights_ImportLightsFile_f(cmd_state_t *cmd)
5398 R_Shadow_ClearWorldLights();
5399 R_Shadow_LoadLightsFile();
5402 static void R_Shadow_EditLights_Spawn_f(cmd_state_t *cmd)
5405 if (!r_editlights.integer)
5407 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5410 if (Cmd_Argc(cmd) != 1)
5412 Con_Print("r_editlights_spawn does not take parameters\n");
5415 color[0] = color[1] = color[2] = 1;
5416 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5419 static void R_Shadow_EditLights_Edit_f(cmd_state_t *cmd)
5421 vec3_t origin, angles, color;
5422 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5423 int style, shadows, flags, normalmode, realtimemode;
5424 char cubemapname[MAX_INPUTLINE];
5425 if (!r_editlights.integer)
5427 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5430 if (!r_shadow_selectedlight)
5432 Con_Print("No selected light.\n");
5435 VectorCopy(r_shadow_selectedlight->origin, origin);
5436 VectorCopy(r_shadow_selectedlight->angles, angles);
5437 VectorCopy(r_shadow_selectedlight->color, color);
5438 radius = r_shadow_selectedlight->radius;
5439 style = r_shadow_selectedlight->style;
5440 if (r_shadow_selectedlight->cubemapname)
5441 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5444 shadows = r_shadow_selectedlight->shadow;
5445 corona = r_shadow_selectedlight->corona;
5446 coronasizescale = r_shadow_selectedlight->coronasizescale;
5447 ambientscale = r_shadow_selectedlight->ambientscale;
5448 diffusescale = r_shadow_selectedlight->diffusescale;
5449 specularscale = r_shadow_selectedlight->specularscale;
5450 flags = r_shadow_selectedlight->flags;
5451 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5452 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5453 if (!strcmp(Cmd_Argv(cmd, 1), "origin"))
5455 if (Cmd_Argc(cmd) != 5)
5457 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5460 origin[0] = atof(Cmd_Argv(cmd, 2));
5461 origin[1] = atof(Cmd_Argv(cmd, 3));
5462 origin[2] = atof(Cmd_Argv(cmd, 4));
5464 else if (!strcmp(Cmd_Argv(cmd, 1), "originscale"))
5466 if (Cmd_Argc(cmd) != 5)
5468 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5471 origin[0] *= atof(Cmd_Argv(cmd, 2));
5472 origin[1] *= atof(Cmd_Argv(cmd, 3));
5473 origin[2] *= atof(Cmd_Argv(cmd, 4));
5475 else if (!strcmp(Cmd_Argv(cmd, 1), "originx"))
5477 if (Cmd_Argc(cmd) != 3)
5479 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5482 origin[0] = atof(Cmd_Argv(cmd, 2));
5484 else if (!strcmp(Cmd_Argv(cmd, 1), "originy"))
5486 if (Cmd_Argc(cmd) != 3)
5488 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5491 origin[1] = atof(Cmd_Argv(cmd, 2));
5493 else if (!strcmp(Cmd_Argv(cmd, 1), "originz"))
5495 if (Cmd_Argc(cmd) != 3)
5497 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5500 origin[2] = atof(Cmd_Argv(cmd, 2));
5502 else if (!strcmp(Cmd_Argv(cmd, 1), "move"))
5504 if (Cmd_Argc(cmd) != 5)
5506 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5509 origin[0] += atof(Cmd_Argv(cmd, 2));
5510 origin[1] += atof(Cmd_Argv(cmd, 3));
5511 origin[2] += atof(Cmd_Argv(cmd, 4));
5513 else if (!strcmp(Cmd_Argv(cmd, 1), "movex"))
5515 if (Cmd_Argc(cmd) != 3)
5517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5520 origin[0] += atof(Cmd_Argv(cmd, 2));
5522 else if (!strcmp(Cmd_Argv(cmd, 1), "movey"))
5524 if (Cmd_Argc(cmd) != 3)
5526 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5529 origin[1] += atof(Cmd_Argv(cmd, 2));
5531 else if (!strcmp(Cmd_Argv(cmd, 1), "movez"))
5533 if (Cmd_Argc(cmd) != 3)
5535 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5538 origin[2] += atof(Cmd_Argv(cmd, 2));
5540 else if (!strcmp(Cmd_Argv(cmd, 1), "angles"))
5542 if (Cmd_Argc(cmd) != 5)
5544 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5547 angles[0] = atof(Cmd_Argv(cmd, 2));
5548 angles[1] = atof(Cmd_Argv(cmd, 3));
5549 angles[2] = atof(Cmd_Argv(cmd, 4));
5551 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesx"))
5553 if (Cmd_Argc(cmd) != 3)
5555 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5558 angles[0] = atof(Cmd_Argv(cmd, 2));
5560 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesy"))
5562 if (Cmd_Argc(cmd) != 3)
5564 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5567 angles[1] = atof(Cmd_Argv(cmd, 2));
5569 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesz"))
5571 if (Cmd_Argc(cmd) != 3)
5573 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5576 angles[2] = atof(Cmd_Argv(cmd, 2));
5578 else if (!strcmp(Cmd_Argv(cmd, 1), "color"))
5580 if (Cmd_Argc(cmd) != 5)
5582 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(cmd, 1));
5585 color[0] = atof(Cmd_Argv(cmd, 2));
5586 color[1] = atof(Cmd_Argv(cmd, 3));
5587 color[2] = atof(Cmd_Argv(cmd, 4));
5589 else if (!strcmp(Cmd_Argv(cmd, 1), "radius"))
5591 if (Cmd_Argc(cmd) != 3)
5593 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5596 radius = atof(Cmd_Argv(cmd, 2));
5598 else if (!strcmp(Cmd_Argv(cmd, 1), "colorscale"))
5600 if (Cmd_Argc(cmd) == 3)
5602 double scale = atof(Cmd_Argv(cmd, 2));
5609 if (Cmd_Argc(cmd) != 5)
5611 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(cmd, 1));
5614 color[0] *= atof(Cmd_Argv(cmd, 2));
5615 color[1] *= atof(Cmd_Argv(cmd, 3));
5616 color[2] *= atof(Cmd_Argv(cmd, 4));
5619 else if (!strcmp(Cmd_Argv(cmd, 1), "radiusscale") || !strcmp(Cmd_Argv(cmd, 1), "sizescale"))
5621 if (Cmd_Argc(cmd) != 3)
5623 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5626 radius *= atof(Cmd_Argv(cmd, 2));
5628 else if (!strcmp(Cmd_Argv(cmd, 1), "style"))
5630 if (Cmd_Argc(cmd) != 3)
5632 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5635 style = atoi(Cmd_Argv(cmd, 2));
5637 else if (!strcmp(Cmd_Argv(cmd, 1), "cubemap"))
5639 if (Cmd_Argc(cmd) > 3)
5641 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5644 if (Cmd_Argc(cmd) == 3)
5645 strlcpy(cubemapname, Cmd_Argv(cmd, 2), sizeof(cubemapname));
5649 else if (!strcmp(Cmd_Argv(cmd, 1), "shadows"))
5651 if (Cmd_Argc(cmd) != 3)
5653 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5656 shadows = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5658 else if (!strcmp(Cmd_Argv(cmd, 1), "corona"))
5660 if (Cmd_Argc(cmd) != 3)
5662 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5665 corona = atof(Cmd_Argv(cmd, 2));
5667 else if (!strcmp(Cmd_Argv(cmd, 1), "coronasize"))
5669 if (Cmd_Argc(cmd) != 3)
5671 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5674 coronasizescale = atof(Cmd_Argv(cmd, 2));
5676 else if (!strcmp(Cmd_Argv(cmd, 1), "ambient"))
5678 if (Cmd_Argc(cmd) != 3)
5680 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5683 ambientscale = atof(Cmd_Argv(cmd, 2));
5685 else if (!strcmp(Cmd_Argv(cmd, 1), "diffuse"))
5687 if (Cmd_Argc(cmd) != 3)
5689 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5692 diffusescale = atof(Cmd_Argv(cmd, 2));
5694 else if (!strcmp(Cmd_Argv(cmd, 1), "specular"))
5696 if (Cmd_Argc(cmd) != 3)
5698 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5701 specularscale = atof(Cmd_Argv(cmd, 2));
5703 else if (!strcmp(Cmd_Argv(cmd, 1), "normalmode"))
5705 if (Cmd_Argc(cmd) != 3)
5707 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5710 normalmode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5712 else if (!strcmp(Cmd_Argv(cmd, 1), "realtimemode"))
5714 if (Cmd_Argc(cmd) != 3)
5716 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5719 realtimemode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5723 Con_Print("usage: r_editlights_edit [property] [value]\n");
5724 Con_Print("Selected light's properties:\n");
5725 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5726 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5727 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5728 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5729 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5730 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5731 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5732 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5733 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5734 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5735 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5736 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5737 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5738 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5741 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5742 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5745 static void R_Shadow_EditLights_EditAll_f(cmd_state_t *cmd)
5748 dlight_t *light, *oldselected;
5751 if (!r_editlights.integer)
5753 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5757 oldselected = r_shadow_selectedlight;
5758 // EditLights doesn't seem to have a "remove" command or something so:
5759 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5760 for (lightindex = 0;lightindex < range;lightindex++)
5762 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5765 R_Shadow_SelectLight(light);
5766 R_Shadow_EditLights_Edit_f(&cmd_client);
5768 // return to old selected (to not mess editing once selection is locked)
5769 R_Shadow_SelectLight(oldselected);
5772 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5774 int lightnumber, lightcount;
5775 size_t lightindex, range;
5780 if (!r_editlights.integer)
5783 // update cvars so QC can query them
5784 if (r_shadow_selectedlight)
5786 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5787 Cvar_SetQuick(&r_editlights_current_origin, temp);
5788 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5789 Cvar_SetQuick(&r_editlights_current_angles, temp);
5790 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5791 Cvar_SetQuick(&r_editlights_current_color, temp);
5792 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5793 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5794 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5795 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5796 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5797 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5798 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5799 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5800 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5801 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5802 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5805 // draw properties on screen
5806 if (!r_editlights_drawproperties.integer)
5808 x = vid_conwidth.value - 320;
5810 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5813 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5814 for (lightindex = 0;lightindex < range;lightindex++)
5816 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5819 if (light == r_shadow_selectedlight)
5820 lightnumber = (int)lightindex;
5823 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;
5824 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;
5826 if (r_shadow_selectedlight == NULL)
5828 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;
5829 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;
5830 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;
5831 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;
5832 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;
5833 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;
5834 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;
5835 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;
5836 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;
5837 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;
5838 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;
5839 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;
5840 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;
5841 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;
5842 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;
5844 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;
5845 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;
5846 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;
5847 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;
5848 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;
5849 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;
5850 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;
5851 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;
5852 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;
5853 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;
5856 static void R_Shadow_EditLights_ToggleShadow_f(cmd_state_t *cmd)
5858 if (!r_editlights.integer)
5860 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5863 if (!r_shadow_selectedlight)
5865 Con_Print("No selected light.\n");
5868 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);
5871 static void R_Shadow_EditLights_ToggleCorona_f(cmd_state_t *cmd)
5873 if (!r_editlights.integer)
5875 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5878 if (!r_shadow_selectedlight)
5880 Con_Print("No selected light.\n");
5883 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);
5886 static void R_Shadow_EditLights_Remove_f(cmd_state_t *cmd)
5888 if (!r_editlights.integer)
5890 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5893 if (!r_shadow_selectedlight)
5895 Con_Print("No selected light.\n");
5898 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5899 r_shadow_selectedlight = NULL;
5902 static void R_Shadow_EditLights_Help_f(cmd_state_t *cmd)
5905 "Documentation on r_editlights system:\n"
5907 "r_editlights : enable/disable editing mode\n"
5908 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5909 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5910 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5911 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5912 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5914 "r_editlights_help : this help\n"
5915 "r_editlights_clear : remove all lights\n"
5916 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5917 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5918 "r_editlights_save : save to .rtlights file\n"
5919 "r_editlights_spawn : create a light with default settings\n"
5920 "r_editlights_edit command : edit selected light - more documentation below\n"
5921 "r_editlights_remove : remove selected light\n"
5922 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5923 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5924 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5926 "origin x y z : set light location\n"
5927 "originx x: set x component of light location\n"
5928 "originy y: set y component of light location\n"
5929 "originz z: set z component of light location\n"
5930 "move x y z : adjust light location\n"
5931 "movex x: adjust x component of light location\n"
5932 "movey y: adjust y component of light location\n"
5933 "movez z: adjust z component of light location\n"
5934 "angles x y z : set light angles\n"
5935 "anglesx x: set x component of light angles\n"
5936 "anglesy y: set y component of light angles\n"
5937 "anglesz z: set z component of light angles\n"
5938 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5939 "radius radius : set radius (size) of light\n"
5940 "colorscale grey : multiply color of light (1 does nothing)\n"
5941 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5942 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5943 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5944 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5945 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5946 "cubemap basename : set filter cubemap of light\n"
5947 "shadows 1/0 : turn on/off shadows\n"
5948 "corona n : set corona intensity\n"
5949 "coronasize n : set corona size (0-1)\n"
5950 "ambient n : set ambient intensity (0-1)\n"
5951 "diffuse n : set diffuse intensity (0-1)\n"
5952 "specular n : set specular intensity (0-1)\n"
5953 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5954 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5955 "<nothing> : print light properties to console\n"
5959 static void R_Shadow_EditLights_CopyInfo_f(cmd_state_t *cmd)
5961 if (!r_editlights.integer)
5963 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5966 if (!r_shadow_selectedlight)
5968 Con_Print("No selected light.\n");
5971 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5972 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5973 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5974 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5975 if (r_shadow_selectedlight->cubemapname)
5976 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5978 r_shadow_bufferlight.cubemapname[0] = 0;
5979 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5980 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5981 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5982 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5983 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5984 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5985 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5988 static void R_Shadow_EditLights_PasteInfo_f(cmd_state_t *cmd)
5990 if (!r_editlights.integer)
5992 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5995 if (!r_shadow_selectedlight)
5997 Con_Print("No selected light.\n");
6000 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);
6003 static void R_Shadow_EditLights_Lock_f(cmd_state_t *cmd)
6005 if (!r_editlights.integer)
6007 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6010 if (r_editlights_lockcursor)
6012 r_editlights_lockcursor = false;
6015 if (!r_shadow_selectedlight)
6017 Con_Print("No selected light to lock on.\n");
6020 r_editlights_lockcursor = true;
6023 static void R_Shadow_EditLights_Init(void)
6025 Cvar_RegisterVariable(&r_editlights);
6026 Cvar_RegisterVariable(&r_editlights_cursordistance);
6027 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6028 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6029 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6030 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6031 Cvar_RegisterVariable(&r_editlights_drawproperties);
6032 Cvar_RegisterVariable(&r_editlights_current_origin);
6033 Cvar_RegisterVariable(&r_editlights_current_angles);
6034 Cvar_RegisterVariable(&r_editlights_current_color);
6035 Cvar_RegisterVariable(&r_editlights_current_radius);
6036 Cvar_RegisterVariable(&r_editlights_current_corona);
6037 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6038 Cvar_RegisterVariable(&r_editlights_current_style);
6039 Cvar_RegisterVariable(&r_editlights_current_shadows);
6040 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6041 Cvar_RegisterVariable(&r_editlights_current_ambient);
6042 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6043 Cvar_RegisterVariable(&r_editlights_current_specular);
6044 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6045 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6046 Cmd_AddCommand(&cmd_client, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6047 Cmd_AddCommand(&cmd_client, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6048 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)");
6049 Cmd_AddCommand(&cmd_client, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6050 Cmd_AddCommand(&cmd_client, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6051 Cmd_AddCommand(&cmd_client, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6052 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)");
6053 Cmd_AddCommand(&cmd_client, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6054 Cmd_AddCommand(&cmd_client, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6055 Cmd_AddCommand(&cmd_client, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6056 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)");
6057 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)");
6058 Cmd_AddCommand(&cmd_client, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6059 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)");
6060 Cmd_AddCommand(&cmd_client, "r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6066 =============================================================================
6070 =============================================================================
6073 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6075 int i, numlights, flag, q;
6078 float relativepoint[3];
6083 float sa[3], sx[3], sy[3], sz[3], sd[3];
6086 // use first order spherical harmonics to combine directional lights
6087 for (q = 0; q < 3; q++)
6088 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6090 if (flags & LP_LIGHTMAP)
6092 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6094 float tempambient[3];
6095 for (q = 0; q < 3; q++)
6096 tempambient[q] = color[q] = relativepoint[q] = 0;
6097 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6098 // calculate a weighted average light direction as well
6099 intensity = VectorLength(color);
6100 for (q = 0; q < 3; q++)
6102 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6103 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6104 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6105 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6106 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6111 // unlit map - fullbright but scaled by lightmapintensity
6112 for (q = 0; q < 3; q++)
6113 sa[q] += lightmapintensity;
6117 if (flags & LP_RTWORLD)
6119 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6120 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6121 for (i = 0; i < numlights; i++)
6123 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6126 light = &dlight->rtlight;
6127 if (!(light->flags & flag))
6130 lightradius2 = light->radius * light->radius;
6131 VectorSubtract(light->shadoworigin, p, relativepoint);
6132 dist2 = VectorLength2(relativepoint);
6133 if (dist2 >= lightradius2)
6135 dist = sqrt(dist2) / light->radius;
6136 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6137 if (intensity <= 0.0f)
6139 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)
6141 for (q = 0; q < 3; q++)
6142 color[q] = light->currentcolor[q] * intensity;
6143 intensity = VectorLength(color);
6144 VectorNormalize(relativepoint);
6145 for (q = 0; q < 3; q++)
6147 sa[q] += 0.5f * color[q];
6148 sx[q] += relativepoint[0] * color[q];
6149 sy[q] += relativepoint[1] * color[q];
6150 sz[q] += relativepoint[2] * color[q];
6151 sd[q] += intensity * relativepoint[q];
6154 // FIXME: sample bouncegrid too!
6157 if (flags & LP_DYNLIGHT)
6160 for (i = 0;i < r_refdef.scene.numlights;i++)
6162 light = r_refdef.scene.lights[i];
6164 lightradius2 = light->radius * light->radius;
6165 VectorSubtract(light->shadoworigin, p, relativepoint);
6166 dist2 = VectorLength2(relativepoint);
6167 if (dist2 >= lightradius2)
6169 dist = sqrt(dist2) / light->radius;
6170 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6171 if (intensity <= 0.0f)
6173 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)
6175 for (q = 0; q < 3; q++)
6176 color[q] = light->currentcolor[q] * intensity;
6177 intensity = VectorLength(color);
6178 VectorNormalize(relativepoint);
6179 for (q = 0; q < 3; q++)
6181 sa[q] += 0.5f * color[q];
6182 sx[q] += relativepoint[0] * color[q];
6183 sy[q] += relativepoint[1] * color[q];
6184 sz[q] += relativepoint[2] * color[q];
6185 sd[q] += intensity * relativepoint[q];
6190 // calculate the weighted-average light direction (bentnormal)
6191 for (q = 0; q < 3; q++)
6192 lightdir[q] = sd[q];
6193 VectorNormalize(lightdir);
6194 for (q = 0; q < 3; q++)
6196 // extract the diffuse color along the chosen direction and scale it
6197 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6198 // subtract some of diffuse from ambient
6199 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;