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;
1951 normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1952 for (lightindex = 0;lightindex < range2;lightindex++)
1954 if (lightindex < range)
1956 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1959 rtlight = &light->rtlight;
1960 VectorClear(rtlight->bouncegrid_photoncolor);
1961 rtlight->bouncegrid_photons = 0;
1962 rtlight->bouncegrid_hits = 0;
1963 rtlight->bouncegrid_traces = 0;
1964 rtlight->bouncegrid_effectiveradius = 0;
1965 if (!(light->flags & flag))
1967 if (r_shadow_bouncegrid_state.settings.staticmode)
1969 // when static, we skip styled lights because they tend to change...
1970 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
1973 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
1978 rtlight = r_refdef.scene.lights[lightindex - range];
1979 VectorClear(rtlight->bouncegrid_photoncolor);
1980 rtlight->bouncegrid_photons = 0;
1981 rtlight->bouncegrid_hits = 0;
1982 rtlight->bouncegrid_traces = 0;
1983 rtlight->bouncegrid_effectiveradius = 0;
1985 // draw only visible lights (major speedup)
1986 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
1987 cullmins[0] = rtlight->shadoworigin[0] - radius;
1988 cullmins[1] = rtlight->shadoworigin[1] - radius;
1989 cullmins[2] = rtlight->shadoworigin[2] - radius;
1990 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
1991 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
1992 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
1993 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
1994 if (!r_shadow_bouncegrid_state.settings.staticmode)
1996 // skip if the expanded light box does not touch any visible leafs
1997 if (r_refdef.scene.worldmodel
1998 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
1999 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2001 // skip if the expanded light box is not visible to traceline
2002 // note that PrepareLight already did this check but for a smaller box, so we
2003 // end up casting more traces per frame per light when using bouncegrid, which
2004 // is probably fine (and they use the same timer)
2005 if (r_shadow_culllights_trace.integer)
2007 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))
2008 rtlight->trace_timer = realtime;
2009 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2012 // skip if expanded light box is offscreen
2013 if (R_CullBox(cullmins, cullmaxs))
2015 // skip if overall light intensity is zero
2016 if (w * VectorLength2(rtlight->color) == 0.0f)
2019 // a light that does not emit any light before style is applied, can be
2020 // skipped entirely (it may just be a corona)
2021 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2023 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2024 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2025 // skip lights that will emit no photons
2026 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2028 // shoot particles from this light
2029 // use a calculation for the number of particles that will not
2030 // vary with lightstyle, otherwise we get randomized particle
2031 // distribution, the seeded random is only consistent for a
2032 // consistent number of particles on this light...
2033 s = rtlight->radius;
2034 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2035 if (lightindex >= range)
2036 lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2037 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2038 photoncount += rtlight->bouncegrid_photons;
2039 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2040 // if the lightstyle happens to be off right now, we can skip actually
2041 // firing the photons, but we did have to count them in the total.
2042 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2043 // rtlight->bouncegrid_photons = 0;
2045 // the user provided an energyperphoton value which we try to use
2046 // if that results in too many photons to shoot this frame, then we cap it
2047 // which causes photons to appear/disappear from frame to frame, so we don't
2048 // like doing that in the typical case
2049 photonscaling = 1.0f;
2050 photonintensity = 1.0f;
2051 if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2053 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2054 photonintensity = 1.0f / photonscaling;
2057 // modify the lights to reflect our computed scaling
2058 for (lightindex = 0; lightindex < range2; lightindex++)
2060 if (lightindex < range)
2062 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2065 rtlight = &light->rtlight;
2068 rtlight = r_refdef.scene.lights[lightindex - range];
2069 rtlight->bouncegrid_photons *= photonscaling;
2070 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2073 // compute a seed for the unstable random modes
2074 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2075 seed = realtime * 1000.0;
2077 for (lightindex = 0; lightindex < range2; lightindex++)
2079 if (lightindex < range)
2081 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2084 rtlight = &light->rtlight;
2087 rtlight = r_refdef.scene.lights[lightindex - range];
2088 // note that this code used to keep track of residual photons and
2089 // distribute them evenly to achieve exactly a desired photon count,
2090 // but that caused unwanted flickering in dynamic mode
2091 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2092 // skip if we won't be shooting any photons
2093 if (!shootparticles)
2095 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2096 //s = settings.particleintensity / shootparticles;
2097 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2098 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2099 if (VectorLength2(baseshotcolor) <= 0.0f)
2101 r_refdef.stats[r_stat_bouncegrid_lights]++;
2102 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2103 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2104 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2106 // check material at shadoworigin to see what the initial refractive index should be
2107 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2109 // for seeded random we start the RNG with the position of the light
2110 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2118 u.f[0] = rtlight->shadoworigin[0];
2119 u.f[1] = rtlight->shadoworigin[1];
2120 u.f[2] = rtlight->shadoworigin[2];
2122 switch (r_shadow_bouncegrid_state.settings.rng_type)
2126 // we have to shift the seed provided by the user because the result must be odd
2127 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2130 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2135 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2137 r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2138 VectorCopy(baseshotcolor, p->color);
2139 VectorCopy(rtlight->shadoworigin, p->start);
2140 switch (r_shadow_bouncegrid_state.settings.rng_type)
2144 // figure out a random direction for the initial photon to go
2145 VectorLehmerRandom(&randomseed, p->end);
2148 // figure out a random direction for the initial photon to go
2149 VectorCheeseRandom(seed, p->end);
2153 // we want a uniform distribution spherically, not merely within the sphere
2154 if (r_shadow_bouncegrid_state.settings.normalizevectors)
2155 VectorNormalize(p->end);
2157 VectorMA(p->start, radius, p->end, p->end);
2158 p->bounceminimumintensity2 = bounceminimumintensity2;
2159 p->startrefractiveindex = startrefractiveindex;
2167 static void R_Shadow_BounceGrid_Slice(int zi)
2169 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2170 int xi, yi; // pixel increments
2171 float color[32] = { 0 };
2172 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2173 float iradius = 1.0f / radius;
2174 int slicemins[3], slicemaxs[3];
2176 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2177 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2179 int samples = r_shadow_bouncegrid_state.settings.subsamples;
2180 float isamples = 1.0f / samples;
2181 float samplescolorscale = isamples * isamples * isamples;
2183 // we use these a lot, so get a local copy
2184 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2186 for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2188 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2190 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2192 r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2193 float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2195 VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2196 VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2198 pathmins[2] = min(pathstart[2], pathend[2]);
2199 slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2200 pathmaxs[2] = max(pathstart[2], pathend[2]);
2201 slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2203 // skip if the path doesn't touch this slice
2204 if (zi < slicemins[2] || zi >= slicemaxs[2])
2207 pathmins[0] = min(pathstart[0], pathend[0]);
2208 slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2209 slicemins[0] = max(slicemins[0], 1);
2210 pathmaxs[0] = max(pathstart[0], pathend[0]);
2211 slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2212 slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2214 pathmins[1] = min(pathstart[1], pathend[1]);
2215 slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2216 slicemins[1] = max(slicemins[1], 1);
2217 pathmaxs[1] = max(pathstart[1], pathend[1]);
2218 slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2219 slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2221 // skip if the path is out of bounds on X or Y
2222 if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2225 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2226 // accumulate average shotcolor
2227 VectorSubtract(pathend, pathstart, pathdelta);
2228 pathlength2 = VectorLength2(pathdelta);
2229 pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2230 VectorScale(pathdelta, pathilength, pathdir);
2231 // the color is scaled by the number of subsamples
2232 color[0] = path->color[0] * samplescolorscale;
2233 color[1] = path->color[1] * samplescolorscale;
2234 color[2] = path->color[2] * samplescolorscale;
2238 // store bentnormal in case the shader has a use for it,
2239 // bentnormal is an intensity-weighted average of the directions,
2240 // and will be normalized on conversion to texture pixels.
2241 float intensity = VectorLength(color);
2242 color[4] = pathdir[0] * intensity;
2243 color[5] = pathdir[1] * intensity;
2244 color[6] = pathdir[2] * intensity;
2245 color[7] = intensity;
2246 // for each color component (R, G, B) calculate the amount that a
2247 // direction contributes
2248 color[8] = color[0] * max(0.0f, pathdir[0]);
2249 color[9] = color[0] * max(0.0f, pathdir[1]);
2250 color[10] = color[0] * max(0.0f, pathdir[2]);
2252 color[12] = color[1] * max(0.0f, pathdir[0]);
2253 color[13] = color[1] * max(0.0f, pathdir[1]);
2254 color[14] = color[1] * max(0.0f, pathdir[2]);
2256 color[16] = color[2] * max(0.0f, pathdir[0]);
2257 color[17] = color[2] * max(0.0f, pathdir[1]);
2258 color[18] = color[2] * max(0.0f, pathdir[2]);
2260 // and do the same for negative directions
2261 color[20] = color[0] * max(0.0f, -pathdir[0]);
2262 color[21] = color[0] * max(0.0f, -pathdir[1]);
2263 color[22] = color[0] * max(0.0f, -pathdir[2]);
2265 color[24] = color[1] * max(0.0f, -pathdir[0]);
2266 color[25] = color[1] * max(0.0f, -pathdir[1]);
2267 color[26] = color[1] * max(0.0f, -pathdir[2]);
2269 color[28] = color[2] * max(0.0f, -pathdir[0]);
2270 color[29] = color[2] * max(0.0f, -pathdir[1]);
2271 color[30] = color[2] * max(0.0f, -pathdir[2]);
2275 for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2277 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2279 float sample[3], diff[3], nearest[3], along, distance2;
2280 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2282 // loop over the subsamples
2283 for (zs = 0; zs < samples; zs++)
2285 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2286 for (ys = 0; ys < samples; ys++)
2288 sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2289 for (xs = 0; xs < samples; xs++)
2291 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2293 // measure distance from subsample to line segment and see if it is within radius
2294 along = DotProduct(sample, pathdir) * pathilength;
2296 VectorCopy(pathstart, nearest);
2297 else if (along >= 1)
2298 VectorCopy(pathend, nearest);
2300 VectorLerp(pathstart, along, pathend, nearest);
2301 VectorSubtract(sample, nearest, diff);
2302 VectorScale(diff, iradius, diff);
2303 distance2 = VectorLength2(diff);
2304 if (distance2 < 1.0f)
2306 // contribute some color to this pixel, across all bands
2307 float w = 1.0f - sqrt(distance2);
2312 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2313 p[pixelsperband * 4 + 3] += color[7] * w;
2315 for (band = 0; band < pixelbands; band++)
2317 // add to the pixel color (RGB only - see above)
2318 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2319 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2320 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2332 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2334 R_Shadow_BounceGrid_Slice((int)t->i[0]);
2338 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2341 // we need to wait for the texture clear to finish before we start adding light to it
2342 if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2347 slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2348 for (i = 0; i < slices; i++)
2349 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2350 TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2351 TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2352 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2356 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2358 const float *inpixel;
2360 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2363 unsigned int x, y, z;
2364 unsigned int resolution[3];
2365 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2366 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2368 for (z = 1;z < resolution[2]-1;z++)
2370 for (y = 1;y < resolution[1]-1;y++)
2373 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2374 inpixel = inpixels + 4*index;
2375 outpixel = outpixels + 4*index;
2376 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2378 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2379 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2380 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2381 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2388 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2391 unsigned int resolution[3];
2392 if (r_shadow_bouncegrid_state.settings.blur)
2394 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2396 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2397 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2398 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2399 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2402 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2404 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2406 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2408 // toggle the state, highpixels now points to pixels[3] result
2409 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2410 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2415 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2417 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2418 unsigned char *pixelsbgra8 = NULL;
2419 unsigned char *pixelbgra8;
2420 unsigned short *pixelsrgba16f = NULL;
2421 unsigned short *pixelrgba16f;
2422 float *pixelsrgba32f = NULL;
2423 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2426 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2427 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2428 unsigned int pixelband;
2429 unsigned int x, y, z;
2430 unsigned int index, bandindex;
2431 unsigned int resolution[3];
2433 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2435 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2437 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2438 r_shadow_bouncegrid_state.texture = NULL;
2441 // if bentnormals exist, we need to normalize and bias them for the shader
2445 for (z = 0;z < resolution[2]-1;z++)
2447 for (y = 0;y < resolution[1]-1;y++)
2450 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2451 highpixel = highpixels + 4*index;
2452 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2454 // only convert pixels that were hit by photons
2455 if (highpixel[3] != 0.0f)
2456 VectorNormalize(highpixel);
2457 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2458 highpixel[pixelsperband * 4 + 3] = 1.0f;
2464 // start by clearing the pixels array - we won't be writing to all of it
2466 // then process only the pixels that have at least some color, skipping
2467 // the higher bands for speed on pixels that are black
2468 switch (floatcolors)
2471 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2472 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2473 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2474 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2477 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2479 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2481 for (z = 1;z < resolution[2]-1;z++)
2483 for (y = 1;y < resolution[1]-1;y++)
2487 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2488 highpixel = highpixels + 4*index;
2489 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2491 // only convert pixels that were hit by photons
2492 if (VectorLength2(highpixel))
2494 // normalize the bentnormal now
2497 VectorNormalize(highpixel + pixelsperband * 4);
2498 highpixel[pixelsperband * 4 + 3] = 1.0f;
2500 // process all of the pixelbands for this pixel
2501 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2503 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2504 bandpixel = highpixels + 4*bandindex;
2505 c[0] = (int)(bandpixel[0]*256.0f);
2506 c[1] = (int)(bandpixel[1]*256.0f);
2507 c[2] = (int)(bandpixel[2]*256.0f);
2508 c[3] = (int)(bandpixel[3]*256.0f);
2509 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2510 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2511 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2512 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2519 if (!r_shadow_bouncegrid_state.createtexture)
2520 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2522 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);
2525 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2526 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2527 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2528 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2529 for (z = 1;z < resolution[2]-1;z++)
2531 for (y = 1;y < resolution[1]-1;y++)
2535 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2536 highpixel = highpixels + 4*index;
2537 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2539 // only convert pixels that were hit by photons
2540 if (VectorLength2(highpixel))
2542 // process all of the pixelbands for this pixel
2543 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2545 // time to have fun with IEEE 754 bit hacking...
2548 unsigned int raw[4];
2550 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2551 bandpixel = highpixels + 4*bandindex;
2552 VectorCopy4(bandpixel, u.f);
2553 VectorCopy4(u.raw, c);
2554 // this math supports negative numbers, snaps denormals to zero
2555 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2556 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2557 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2558 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2559 // this math does not support negative
2560 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2561 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2562 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2563 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2570 if (!r_shadow_bouncegrid_state.createtexture)
2571 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2573 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);
2576 // our native format happens to match, so this is easy.
2577 pixelsrgba32f = highpixels;
2579 if (!r_shadow_bouncegrid_state.createtexture)
2580 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2582 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);
2586 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2589 void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2591 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2595 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)
2597 int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2599 vec3_t surfacenormal;
2600 vec3_t reflectstart, reflectend, reflectcolor;
2601 vec3_t refractstart, refractend, refractcolor;
2603 float reflectamount = 1.0f;
2605 // figure out what we want to interact with
2606 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2607 skipsupercontentsmask = 0;
2608 skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2609 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2610 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2611 if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2613 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2614 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2615 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);
2619 // dynamic mode fires many rays and most will match the cache from the previous frame
2620 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);
2622 VectorCopy(cliptrace.endpos, shothit);
2623 if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2625 qboolean notculled = true;
2626 // cull paths that fail R_CullBox in dynamic mode
2627 if (!r_shadow_bouncegrid_state.settings.staticmode
2628 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2630 vec3_t cullmins, cullmaxs;
2631 cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2632 cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2633 cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2634 cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2635 cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2636 cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2637 if (R_CullBox(cullmins, cullmaxs))
2642 r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2643 VectorCopy(shotstart, path->start);
2644 VectorCopy(shothit, path->end);
2645 VectorCopy(shotcolor, path->color);
2648 if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2650 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2651 // also clamp the resulting color to never add energy, even if the user requests extreme values
2652 VectorCopy(cliptrace.plane.normal, surfacenormal);
2653 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2654 VectorClear(refractcolor);
2655 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2656 if (cliptrace.hittexture)
2658 if (cliptrace.hittexture->currentskinframe)
2659 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2660 if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2662 reflectamount *= cliptrace.hittexture->currentalpha;
2663 if (cliptrace.hittexture->currentskinframe)
2664 reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2666 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2670 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2671 VectorSubtract(shotstart, shotend, lightdir);
2672 VectorNormalize(lightdir);
2673 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2674 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2675 reflectamount *= Fresnel;
2676 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2678 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2679 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2680 // make sure we do not gain energy even if surface colors are out of bounds
2681 reflectcolor[0] = min(reflectcolor[0], 1.0f);
2682 reflectcolor[1] = min(reflectcolor[1], 1.0f);
2683 reflectcolor[2] = min(reflectcolor[2], 1.0f);
2684 refractcolor[0] = min(refractcolor[0], 1.0f);
2685 refractcolor[1] = min(refractcolor[1], 1.0f);
2686 refractcolor[2] = min(refractcolor[2], 1.0f);
2688 // reflected and refracted shots
2689 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2690 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2691 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2692 VectorMultiply(refractcolor, shotcolor, refractcolor);
2694 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2696 // reflect the remaining portion of the line across plane normal
2697 VectorSubtract(shotend, shothit, reflectend);
2698 VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2699 // calculate the new line start and end
2700 VectorCopy(shothit, reflectstart);
2701 VectorAdd(reflectstart, reflectend, reflectend);
2702 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2705 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2707 // Check what refractive index is on the other side
2708 float refractiveindex;
2709 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2710 refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2711 // reflect the remaining portion of the line across plane normal
2712 VectorSubtract(shotend, shothit, refractend);
2713 s = refractiveindex / previousrefractiveindex;
2714 VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2715 // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2716 // calculate the new line start and end
2717 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2718 VectorAdd(refractstart, refractend, refractend);
2719 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2724 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2726 r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2727 R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2731 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2734 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2735 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2736 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);
2737 if (r_shadow_bouncegrid_threaded.integer)
2739 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2740 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2744 // when not threaded we still have to report task status
2745 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2746 r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2747 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2752 void R_Shadow_UpdateBounceGridTexture(void)
2754 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2755 r_shadow_bouncegrid_settings_t settings;
2756 qboolean enable = false;
2757 qboolean settingschanged;
2759 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2761 R_Shadow_BounceGrid_GenerateSettings(&settings);
2763 // changing intensity does not require an update
2764 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2766 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2768 // when settings change, we free everything as it is just simpler that way.
2769 if (settingschanged || !enable)
2771 // not enabled, make sure we free anything we don't need anymore.
2772 if (r_shadow_bouncegrid_state.texture)
2774 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2775 r_shadow_bouncegrid_state.texture = NULL;
2777 r_shadow_bouncegrid_state.highpixels = NULL;
2778 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2779 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2780 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2781 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2782 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2783 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2784 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2785 r_shadow_bouncegrid_state.numpixels = 0;
2786 r_shadow_bouncegrid_state.numphotons = 0;
2787 r_shadow_bouncegrid_state.directional = false;
2793 // if all the settings seem identical to the previous update, return
2794 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2797 // store the new settings
2798 r_shadow_bouncegrid_state.settings = settings;
2800 R_Shadow_BounceGrid_UpdateSpacing();
2802 // allocate the highpixels array we'll be accumulating light into
2803 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2804 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2805 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2806 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2807 r_shadow_bouncegrid_state.highpixels_index = 0;
2808 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2810 // set up the tracking of photon data
2811 if (r_shadow_bouncegrid_state.photons == NULL)
2812 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));
2813 if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2814 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2815 r_shadow_bouncegrid_state.numphotons = 0;
2817 // set up the tracking of slice tasks
2818 if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2819 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2821 memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2822 memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2823 memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2824 memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2825 memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2826 memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2827 memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2828 memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2829 memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2831 // clear the texture
2832 TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2833 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2835 // calculate weighting factors for distributing photons among the lights
2836 TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2837 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2839 // enqueue tasks to trace the photons from lights
2840 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2841 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2843 // accumulate the light paths into texture
2844 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);
2845 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2847 // apply a mild blur filter to the texture
2848 TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2849 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2851 TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2852 R_TimeReport("bouncegrid_gen");
2854 // convert the pixels to lower precision and upload the texture
2855 // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2856 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2857 R_TimeReport("bouncegrid_tex");
2859 // after we compute the static lighting we don't need to keep the highpixels array around
2860 if (settings.staticmode)
2862 r_shadow_bouncegrid_state.highpixels = NULL;
2863 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2864 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2865 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2866 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2867 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2868 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2869 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2873 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2875 R_Shadow_RenderMode_Reset();
2876 GL_BlendFunc(GL_ONE, GL_ONE);
2877 GL_DepthRange(0, 1);
2878 GL_DepthTest(r_showlighting.integer < 2);
2879 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2881 GL_DepthFunc(GL_EQUAL);
2882 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2885 void R_Shadow_RenderMode_End(void)
2887 R_Shadow_RenderMode_Reset();
2888 R_Shadow_RenderMode_ActiveLight(NULL);
2890 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2891 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2894 int bboxedges[12][2] =
2913 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2915 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2917 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2918 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2919 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2920 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2923 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2924 return true; // invisible
2925 if(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)
2929 r_refdef.stats[r_stat_lights_scissored]++;
2933 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2935 // used to display how many times a surface is lit for level design purposes
2936 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2937 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2941 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])
2943 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2944 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2948 extern cvar_t gl_lightmaps;
2949 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2952 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2953 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2954 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2955 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2956 if (!r_shadow_usenormalmap.integer)
2958 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2959 VectorClear(diffusecolor);
2960 VectorClear(specularcolor);
2962 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2963 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2964 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2965 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2967 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2970 VectorNegate(ambientcolor, ambientcolor);
2971 VectorNegate(diffusecolor, diffusecolor);
2972 VectorNegate(specularcolor, specularcolor);
2973 GL_BlendEquationSubtract(true);
2975 RSurf_SetupDepthAndCulling();
2976 switch (r_shadow_rendermode)
2978 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2979 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2980 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2982 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2983 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2986 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2990 GL_BlendEquationSubtract(false);
2993 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)
2995 matrix4x4_t tempmatrix = *matrix;
2996 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2998 // if this light has been compiled before, free the associated data
2999 R_RTLight_Uncompile(rtlight);
3001 // clear it completely to avoid any lingering data
3002 memset(rtlight, 0, sizeof(*rtlight));
3004 // copy the properties
3005 rtlight->matrix_lighttoworld = tempmatrix;
3006 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3007 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3008 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3009 VectorCopy(color, rtlight->color);
3010 rtlight->cubemapname[0] = 0;
3011 if (cubemapname && cubemapname[0])
3012 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3013 rtlight->shadow = shadow;
3014 rtlight->corona = corona;
3015 rtlight->style = style;
3016 rtlight->isstatic = isstatic;
3017 rtlight->coronasizescale = coronasizescale;
3018 rtlight->ambientscale = ambientscale;
3019 rtlight->diffusescale = diffusescale;
3020 rtlight->specularscale = specularscale;
3021 rtlight->flags = flags;
3023 // compute derived data
3024 //rtlight->cullradius = rtlight->radius;
3025 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3026 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3027 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3028 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3029 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3030 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3031 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3034 // compiles rtlight geometry
3035 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3036 void R_RTLight_Compile(rtlight_t *rtlight)
3039 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3040 int lighttris, shadowtris;
3041 entity_render_t *ent = r_refdef.scene.worldentity;
3042 dp_model_t *model = r_refdef.scene.worldmodel;
3043 unsigned char *data;
3045 // compile the light
3046 rtlight->compiled = true;
3047 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3048 rtlight->static_numleafs = 0;
3049 rtlight->static_numleafpvsbytes = 0;
3050 rtlight->static_leaflist = NULL;
3051 rtlight->static_leafpvs = NULL;
3052 rtlight->static_numsurfaces = 0;
3053 rtlight->static_surfacelist = NULL;
3054 rtlight->static_shadowmap_receivers = 0x3F;
3055 rtlight->static_shadowmap_casters = 0x3F;
3056 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3057 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3058 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3059 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3060 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3061 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3063 if (model && model->GetLightInfo)
3065 // this variable must be set for the CompileShadowMap code
3066 r_shadow_compilingrtlight = rtlight;
3067 R_FrameData_SetMark();
3068 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);
3069 R_FrameData_ReturnToMark();
3070 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3071 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3072 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3073 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3074 rtlight->static_numsurfaces = numsurfaces;
3075 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3076 rtlight->static_numleafs = numleafs;
3077 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3078 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3079 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3080 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3081 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3082 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3083 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3084 if (rtlight->static_numsurfaces)
3085 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3086 if (rtlight->static_numleafs)
3087 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3088 if (rtlight->static_numleafpvsbytes)
3089 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3090 if (rtlight->static_numshadowtrispvsbytes)
3091 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3092 if (rtlight->static_numlighttrispvsbytes)
3093 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3094 R_FrameData_SetMark();
3095 if (model->CompileShadowMap && rtlight->shadow)
3096 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3097 R_FrameData_ReturnToMark();
3098 // now we're done compiling the rtlight
3099 r_shadow_compilingrtlight = NULL;
3103 // use smallest available cullradius - box radius or light radius
3104 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3105 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3108 if (rtlight->static_numlighttrispvsbytes)
3109 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3110 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3114 if (rtlight->static_numshadowtrispvsbytes)
3115 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3116 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3119 if (developer_extra.integer)
3120 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);
3123 void R_RTLight_Uncompile(rtlight_t *rtlight)
3125 if (rtlight->compiled)
3127 if (rtlight->static_meshchain_shadow_shadowmap)
3128 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3129 rtlight->static_meshchain_shadow_shadowmap = NULL;
3130 // these allocations are grouped
3131 if (rtlight->static_surfacelist)
3132 Mem_Free(rtlight->static_surfacelist);
3133 rtlight->static_numleafs = 0;
3134 rtlight->static_numleafpvsbytes = 0;
3135 rtlight->static_leaflist = NULL;
3136 rtlight->static_leafpvs = NULL;
3137 rtlight->static_numsurfaces = 0;
3138 rtlight->static_surfacelist = NULL;
3139 rtlight->static_numshadowtrispvsbytes = 0;
3140 rtlight->static_shadowtrispvs = NULL;
3141 rtlight->static_numlighttrispvsbytes = 0;
3142 rtlight->static_lighttrispvs = NULL;
3143 rtlight->compiled = false;
3147 void R_Shadow_UncompileWorldLights(void)
3151 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3152 for (lightindex = 0;lightindex < range;lightindex++)
3154 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3157 R_RTLight_Uncompile(&light->rtlight);
3161 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3165 // reset the count of frustum planes
3166 // see rtlight->cached_frustumplanes definition for how much this array
3168 rtlight->cached_numfrustumplanes = 0;
3170 if (r_trippy.integer)
3173 // haven't implemented a culling path for ortho rendering
3174 if (!r_refdef.view.useperspective)
3176 // check if the light is on screen and copy the 4 planes if it is
3177 for (i = 0;i < 4;i++)
3178 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3181 for (i = 0;i < 4;i++)
3182 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3187 // generate a deformed frustum that includes the light origin, this is
3188 // used to cull shadow casting surfaces that can not possibly cast a
3189 // shadow onto the visible light-receiving surfaces, which can be a
3192 // if the light origin is onscreen the result will be 4 planes exactly
3193 // if the light origin is offscreen on only one axis the result will
3194 // be exactly 5 planes (split-side case)
3195 // if the light origin is offscreen on two axes the result will be
3196 // exactly 4 planes (stretched corner case)
3197 for (i = 0;i < 4;i++)
3199 // quickly reject standard frustum planes that put the light
3200 // origin outside the frustum
3201 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3204 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3206 // if all the standard frustum planes were accepted, the light is onscreen
3207 // otherwise we need to generate some more planes below...
3208 if (rtlight->cached_numfrustumplanes < 4)
3210 // at least one of the stock frustum planes failed, so we need to
3211 // create one or two custom planes to enclose the light origin
3212 for (i = 0;i < 4;i++)
3214 // create a plane using the view origin and light origin, and a
3215 // single point from the frustum corner set
3216 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3217 VectorNormalize(plane.normal);
3218 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3219 // see if this plane is backwards and flip it if so
3220 for (j = 0;j < 4;j++)
3221 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3225 VectorNegate(plane.normal, plane.normal);
3227 // flipped plane, test again to see if it is now valid
3228 for (j = 0;j < 4;j++)
3229 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3231 // if the plane is still not valid, then it is dividing the
3232 // frustum and has to be rejected
3236 // we have created a valid plane, compute extra info
3237 PlaneClassify(&plane);
3239 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3241 // if we've found 5 frustum planes then we have constructed a
3242 // proper split-side case and do not need to keep searching for
3243 // planes to enclose the light origin
3244 if (rtlight->cached_numfrustumplanes == 5)
3252 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3254 plane = rtlight->cached_frustumplanes[i];
3255 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));
3260 // now add the light-space box planes if the light box is rotated, as any
3261 // caster outside the oriented light box is irrelevant (even if it passed
3262 // the worldspace light box, which is axial)
3263 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3265 for (i = 0;i < 6;i++)
3269 v[i >> 1] = (i & 1) ? -1 : 1;
3270 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3271 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3272 plane.dist = VectorNormalizeLength(plane.normal);
3273 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3274 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3280 // add the world-space reduced box planes
3281 for (i = 0;i < 6;i++)
3283 VectorClear(plane.normal);
3284 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3285 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3286 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3295 // reduce all plane distances to tightly fit the rtlight cull box, which
3297 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3298 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3299 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3300 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3301 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3302 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3303 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3304 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3305 oldnum = rtlight->cached_numfrustumplanes;
3306 rtlight->cached_numfrustumplanes = 0;
3307 for (j = 0;j < oldnum;j++)
3309 // find the nearest point on the box to this plane
3310 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3311 for (i = 1;i < 8;i++)
3313 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3314 if (bestdist > dist)
3317 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);
3318 // if the nearest point is near or behind the plane, we want this
3319 // plane, otherwise the plane is useless as it won't cull anything
3320 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3322 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3323 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3330 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3332 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3334 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3336 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3337 if (mesh->sidetotals[r_shadow_shadowmapside])
3340 GL_CullFace(GL_NONE);
3341 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3342 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3343 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);
3347 else if (r_refdef.scene.worldentity->model)
3348 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);
3350 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3353 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3355 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3356 vec_t relativeshadowradius;
3357 RSurf_ActiveModelEntity(ent, false, false, false);
3358 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3359 // we need to re-init the shader for each entity because the matrix changed
3360 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3361 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3362 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3363 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3364 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3365 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3366 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3367 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3368 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3371 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3373 // set up properties for rendering light onto this entity
3374 RSurf_ActiveModelEntity(ent, true, true, false);
3375 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3376 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3377 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3378 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3381 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3383 if (!r_refdef.scene.worldmodel->DrawLight)
3386 // set up properties for rendering light onto this entity
3387 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3388 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3389 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3390 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3391 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3393 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3395 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3398 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3400 dp_model_t *model = ent->model;
3401 if (!model->DrawLight)
3404 R_Shadow_SetupEntityLight(ent);
3406 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3408 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3411 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3415 int numleafs, numsurfaces;
3416 int *leaflist, *surfacelist;
3417 unsigned char *leafpvs;
3418 unsigned char *shadowtrispvs;
3419 unsigned char *lighttrispvs;
3420 //unsigned char *surfacesides;
3421 int numlightentities;
3422 int numlightentities_noselfshadow;
3423 int numshadowentities;
3424 int numshadowentities_noselfshadow;
3425 // FIXME: bounds check lightentities and shadowentities, etc.
3426 static entity_render_t *lightentities[MAX_EDICTS];
3427 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3428 static entity_render_t *shadowentities[MAX_EDICTS];
3429 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3431 qboolean castshadows;
3433 rtlight->draw = false;
3434 rtlight->cached_numlightentities = 0;
3435 rtlight->cached_numlightentities_noselfshadow = 0;
3436 rtlight->cached_numshadowentities = 0;
3437 rtlight->cached_numshadowentities_noselfshadow = 0;
3438 rtlight->cached_numsurfaces = 0;
3439 rtlight->cached_lightentities = NULL;
3440 rtlight->cached_lightentities_noselfshadow = NULL;
3441 rtlight->cached_shadowentities = NULL;
3442 rtlight->cached_shadowentities_noselfshadow = NULL;
3443 rtlight->cached_shadowtrispvs = NULL;
3444 rtlight->cached_lighttrispvs = NULL;
3445 rtlight->cached_surfacelist = NULL;
3446 rtlight->shadowmapsidesize = 0;
3448 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3449 // skip lights that are basically invisible (color 0 0 0)
3450 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3452 // loading is done before visibility checks because loading should happen
3453 // all at once at the start of a level, not when it stalls gameplay.
3454 // (especially important to benchmarks)
3456 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3458 if (rtlight->compiled)
3459 R_RTLight_Uncompile(rtlight);
3460 R_RTLight_Compile(rtlight);
3464 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3466 // look up the light style value at this time
3467 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3468 VectorScale(rtlight->color, f, rtlight->currentcolor);
3470 if (rtlight->selected)
3472 f = 2 + sin(realtime * M_PI * 4.0);
3473 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3477 // skip if lightstyle is currently off
3478 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3481 // skip processing on corona-only lights
3485 // skip if the light box is not touching any visible leafs
3486 if (r_shadow_culllights_pvs.integer
3487 && r_refdef.scene.worldmodel
3488 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3489 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3492 // skip if the light box is not visible to traceline
3493 if (r_shadow_culllights_trace.integer)
3495 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))
3496 rtlight->trace_timer = realtime;
3497 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3501 // skip if the light box is off screen
3502 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3505 // in the typical case this will be quickly replaced by GetLightInfo
3506 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3507 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3509 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3511 // 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
3512 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3515 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3517 // compiled light, world available and can receive realtime lighting
3518 // retrieve leaf information
3519 numleafs = rtlight->static_numleafs;
3520 leaflist = rtlight->static_leaflist;
3521 leafpvs = rtlight->static_leafpvs;
3522 numsurfaces = rtlight->static_numsurfaces;
3523 surfacelist = rtlight->static_surfacelist;
3524 //surfacesides = NULL;
3525 shadowtrispvs = rtlight->static_shadowtrispvs;
3526 lighttrispvs = rtlight->static_lighttrispvs;
3528 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3530 // dynamic light, world available and can receive realtime lighting
3531 // calculate lit surfaces and leafs
3532 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);
3533 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3534 leaflist = r_shadow_buffer_leaflist;
3535 leafpvs = r_shadow_buffer_leafpvs;
3536 surfacelist = r_shadow_buffer_surfacelist;
3537 //surfacesides = r_shadow_buffer_surfacesides;
3538 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3539 lighttrispvs = r_shadow_buffer_lighttrispvs;
3540 // if the reduced leaf bounds are offscreen, skip it
3541 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3552 //surfacesides = NULL;
3553 shadowtrispvs = NULL;
3554 lighttrispvs = NULL;
3556 // check if light is illuminating any visible leafs
3559 for (i = 0; i < numleafs; i++)
3560 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3566 // make a list of lit entities and shadow casting entities
3567 numlightentities = 0;
3568 numlightentities_noselfshadow = 0;
3569 numshadowentities = 0;
3570 numshadowentities_noselfshadow = 0;
3572 // add dynamic entities that are lit by the light
3573 for (i = 0; i < r_refdef.scene.numentities; i++)
3576 entity_render_t *ent = r_refdef.scene.entities[i];
3578 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3580 // skip the object entirely if it is not within the valid
3581 // shadow-casting region (which includes the lit region)
3582 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3584 if (!(model = ent->model))
3586 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3588 // this entity wants to receive light, is visible, and is
3589 // inside the light box
3590 // TODO: check if the surfaces in the model can receive light
3591 // so now check if it's in a leaf seen by the light
3592 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))
3594 if (ent->flags & RENDER_NOSELFSHADOW)
3595 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3597 lightentities[numlightentities++] = ent;
3598 // since it is lit, it probably also casts a shadow...
3599 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3600 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3601 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3603 // note: exterior models without the RENDER_NOSELFSHADOW
3604 // flag still create a RENDER_NOSELFSHADOW shadow but
3605 // are lit normally, this means that they are
3606 // self-shadowing but do not shadow other
3607 // RENDER_NOSELFSHADOW entities such as the gun
3608 // (very weird, but keeps the player shadow off the gun)
3609 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3610 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3612 shadowentities[numshadowentities++] = ent;
3615 else if (ent->flags & RENDER_SHADOW)
3617 // this entity is not receiving light, but may still need to
3619 // TODO: check if the surfaces in the model can cast shadow
3620 // now check if it is in a leaf seen by the light
3621 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))
3623 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3624 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3625 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3627 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3628 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3630 shadowentities[numshadowentities++] = ent;
3635 // return if there's nothing at all to light
3636 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3639 // count this light in the r_speeds
3640 r_refdef.stats[r_stat_lights]++;
3642 // flag it as worth drawing later
3643 rtlight->draw = true;
3645 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3646 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3648 numshadowentities = numshadowentities_noselfshadow = 0;
3649 rtlight->castshadows = castshadows;
3651 // cache all the animated entities that cast a shadow but are not visible
3652 for (i = 0; i < numshadowentities; i++)
3653 R_AnimCache_GetEntity(shadowentities[i], false, false);
3654 for (i = 0; i < numshadowentities_noselfshadow; i++)
3655 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3657 // 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)
3658 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3660 for (i = 0; i < numshadowentities_noselfshadow; i++)
3661 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3662 numshadowentities_noselfshadow = 0;
3665 // we can convert noselfshadow to regular if there are no casters of that type
3666 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3668 for (i = 0; i < numlightentities_noselfshadow; i++)
3669 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3670 numlightentities_noselfshadow = 0;
3673 // allocate some temporary memory for rendering this light later in the frame
3674 // reusable buffers need to be copied, static data can be used as-is
3675 rtlight->cached_numlightentities = numlightentities;
3676 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3677 rtlight->cached_numshadowentities = numshadowentities;
3678 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3679 rtlight->cached_numsurfaces = numsurfaces;
3680 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3681 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3682 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3683 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3684 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3686 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3687 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3688 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3689 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3690 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3694 // compiled light data
3695 rtlight->cached_shadowtrispvs = shadowtrispvs;
3696 rtlight->cached_lighttrispvs = lighttrispvs;
3697 rtlight->cached_surfacelist = surfacelist;
3700 if (R_Shadow_ShadowMappingEnabled())
3702 // figure out the shadowmapping parameters for this light
3703 vec3_t nearestpoint;
3706 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3707 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3708 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3709 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3710 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3711 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3712 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3713 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3714 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3718 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3722 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3723 int numlightentities;
3724 int numlightentities_noselfshadow;
3725 int numshadowentities;
3726 int numshadowentities_noselfshadow;
3727 entity_render_t **lightentities;
3728 entity_render_t **lightentities_noselfshadow;
3729 entity_render_t **shadowentities;
3730 entity_render_t **shadowentities_noselfshadow;
3732 static unsigned char entitysides[MAX_EDICTS];
3733 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3739 matrix4x4_t radiustolight;
3741 // check if we cached this light this frame (meaning it is worth drawing)
3742 if (!rtlight->draw || !rtlight->castshadows)
3745 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3746 if (rtlight->shadowmapatlassidesize == 0)
3748 rtlight->castshadows = false;
3752 // set up a scissor rectangle for this light
3753 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3756 // don't let sound skip if going slow
3757 if (r_refdef.scene.extraupdate)
3760 numlightentities = rtlight->cached_numlightentities;
3761 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3762 numshadowentities = rtlight->cached_numshadowentities;
3763 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3764 numsurfaces = rtlight->cached_numsurfaces;
3765 lightentities = rtlight->cached_lightentities;
3766 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3767 shadowentities = rtlight->cached_shadowentities;
3768 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3769 shadowtrispvs = rtlight->cached_shadowtrispvs;
3770 lighttrispvs = rtlight->cached_lighttrispvs;
3771 surfacelist = rtlight->cached_surfacelist;
3773 // make this the active rtlight for rendering purposes
3774 R_Shadow_RenderMode_ActiveLight(rtlight);
3776 radiustolight = rtlight->matrix_worldtolight;
3777 Matrix4x4_Abs(&radiustolight);
3779 size = rtlight->shadowmapatlassidesize;
3780 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3782 surfacesides = NULL;
3787 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3789 castermask = rtlight->static_shadowmap_casters;
3790 receivermask = rtlight->static_shadowmap_receivers;
3794 surfacesides = r_shadow_buffer_surfacesides;
3795 for (i = 0; i < numsurfaces; i++)
3797 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3798 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3799 castermask |= surfacesides[i];
3800 receivermask |= surfacesides[i];
3805 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3806 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3807 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3808 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3810 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3814 for (i = 0; i < numshadowentities; i++)
3815 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3816 for (i = 0; i < numshadowentities_noselfshadow; i++)
3817 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3820 // there is no need to render shadows for sides that have no receivers...
3821 castermask &= receivermask;
3823 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3825 // render shadow casters into shadowmaps for this light
3826 for (side = 0; side < 6; side++)
3828 int bit = 1 << side;
3829 if (castermask & bit)
3831 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3833 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3834 for (i = 0; i < numshadowentities; i++)
3835 if (entitysides[i] & bit)
3836 R_Shadow_DrawEntityShadow(shadowentities[i]);
3837 for (i = 0; i < numshadowentities_noselfshadow; i++)
3838 if (entitysides_noselfshadow[i] & bit)
3839 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3842 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3843 if (numshadowentities_noselfshadow)
3845 for (side = 0; side < 6; side++)
3847 int bit = 1 << side;
3848 if (castermask & bit)
3850 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3852 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3853 for (i = 0; i < numshadowentities; i++)
3854 if (entitysides[i] & bit)
3855 R_Shadow_DrawEntityShadow(shadowentities[i]);
3861 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3865 unsigned char *shadowtrispvs, *lighttrispvs;
3866 int numlightentities;
3867 int numlightentities_noselfshadow;
3868 int numshadowentities;
3869 int numshadowentities_noselfshadow;
3870 entity_render_t **lightentities;
3871 entity_render_t **lightentities_noselfshadow;
3872 entity_render_t **shadowentities;
3873 entity_render_t **shadowentities_noselfshadow;
3875 qboolean castshadows;
3877 // check if we cached this light this frame (meaning it is worth drawing)
3881 // set up a scissor rectangle for this light
3882 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3885 // don't let sound skip if going slow
3886 if (r_refdef.scene.extraupdate)
3889 numlightentities = rtlight->cached_numlightentities;
3890 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3891 numshadowentities = rtlight->cached_numshadowentities;
3892 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3893 numsurfaces = rtlight->cached_numsurfaces;
3894 lightentities = rtlight->cached_lightentities;
3895 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3896 shadowentities = rtlight->cached_shadowentities;
3897 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3898 shadowtrispvs = rtlight->cached_shadowtrispvs;
3899 lighttrispvs = rtlight->cached_lighttrispvs;
3900 surfacelist = rtlight->cached_surfacelist;
3901 castshadows = rtlight->castshadows;
3903 // make this the active rtlight for rendering purposes
3904 R_Shadow_RenderMode_ActiveLight(rtlight);
3906 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3908 // optionally draw the illuminated areas
3909 // for performance analysis by level designers
3910 R_Shadow_RenderMode_VisibleLighting(false);
3912 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3913 for (i = 0;i < numlightentities;i++)
3914 R_Shadow_DrawEntityLight(lightentities[i]);
3915 for (i = 0;i < numlightentities_noselfshadow;i++)
3916 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3919 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3923 float shadowmapoffsetnoselfshadow = 0;
3924 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3925 Matrix4x4_Abs(&radiustolight);
3927 size = rtlight->shadowmapatlassidesize;
3928 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3930 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3932 if (rtlight->cached_numshadowentities_noselfshadow)
3933 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3935 // render lighting using the depth texture as shadowmap
3936 // draw lighting in the unmasked areas
3937 if (numsurfaces + numlightentities)
3939 R_Shadow_RenderMode_Lighting(false, true, false);
3940 // draw lighting in the unmasked areas
3942 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3943 for (i = 0; i < numlightentities; i++)
3944 R_Shadow_DrawEntityLight(lightentities[i]);
3946 // offset to the noselfshadow part of the atlas and draw those too
3947 if (numlightentities_noselfshadow)
3949 R_Shadow_RenderMode_Lighting(false, true, true);
3950 for (i = 0; i < numlightentities_noselfshadow; i++)
3951 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3954 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3955 if (r_shadow_usingdeferredprepass)
3956 R_Shadow_RenderMode_DrawDeferredLight(true);
3960 // draw lighting in the unmasked areas
3961 R_Shadow_RenderMode_Lighting(false, false, false);
3963 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3964 for (i = 0;i < numlightentities;i++)
3965 R_Shadow_DrawEntityLight(lightentities[i]);
3966 for (i = 0;i < numlightentities_noselfshadow;i++)
3967 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3969 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3970 if (r_shadow_usingdeferredprepass)
3971 R_Shadow_RenderMode_DrawDeferredLight(false);
3975 static void R_Shadow_FreeDeferred(void)
3977 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3978 r_shadow_prepassgeometryfbo = 0;
3980 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3981 r_shadow_prepasslightingdiffusespecularfbo = 0;
3983 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3984 r_shadow_prepasslightingdiffusefbo = 0;
3986 if (r_shadow_prepassgeometrydepthbuffer)
3987 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3988 r_shadow_prepassgeometrydepthbuffer = NULL;
3990 if (r_shadow_prepassgeometrynormalmaptexture)
3991 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3992 r_shadow_prepassgeometrynormalmaptexture = NULL;
3994 if (r_shadow_prepasslightingdiffusetexture)
3995 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3996 r_shadow_prepasslightingdiffusetexture = NULL;
3998 if (r_shadow_prepasslightingspeculartexture)
3999 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4000 r_shadow_prepasslightingspeculartexture = NULL;
4003 void R_Shadow_DrawPrepass(void)
4007 entity_render_t *ent;
4008 float clearcolor[4];
4010 R_Mesh_ResetTextureState();
4012 GL_ColorMask(1,1,1,1);
4013 GL_BlendFunc(GL_ONE, GL_ZERO);
4016 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4017 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4018 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4019 if (r_timereport_active)
4020 R_TimeReport("prepasscleargeom");
4022 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4023 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4024 if (r_timereport_active)
4025 R_TimeReport("prepassworld");
4027 for (i = 0;i < r_refdef.scene.numentities;i++)
4029 if (!r_refdef.viewcache.entityvisible[i])
4031 ent = r_refdef.scene.entities[i];
4032 if (ent->model && ent->model->DrawPrepass != NULL)
4033 ent->model->DrawPrepass(ent);
4036 if (r_timereport_active)
4037 R_TimeReport("prepassmodels");
4039 GL_DepthMask(false);
4040 GL_ColorMask(1,1,1,1);
4043 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4044 Vector4Set(clearcolor, 0, 0, 0, 0);
4045 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4046 if (r_timereport_active)
4047 R_TimeReport("prepassclearlit");
4049 R_Shadow_RenderMode_Begin();
4051 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4052 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4054 R_Shadow_RenderMode_End();
4056 if (r_timereport_active)
4057 R_TimeReport("prepasslights");
4060 #define MAX_SCENELIGHTS 65536
4061 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4063 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4065 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4067 r_shadow_scenemaxlights *= 2;
4068 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4069 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4071 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4075 void R_Shadow_DrawLightSprites(void);
4076 void R_Shadow_PrepareLights(void)
4085 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4086 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4087 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4089 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4090 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4091 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4092 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4093 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4094 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4095 r_shadow_shadowmapborder != shadowmapborder ||
4096 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4097 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4098 R_Shadow_FreeShadowMaps();
4100 r_shadow_usingshadowmaportho = false;
4102 switch (vid.renderpath)
4104 case RENDERPATH_GL32:
4106 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4108 r_shadow_usingdeferredprepass = false;
4109 if (r_shadow_prepass_width)
4110 R_Shadow_FreeDeferred();
4111 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4115 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4117 R_Shadow_FreeDeferred();
4119 r_shadow_usingdeferredprepass = true;
4120 r_shadow_prepass_width = vid.width;
4121 r_shadow_prepass_height = vid.height;
4122 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4123 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);
4124 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);
4125 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);
4127 // set up the geometry pass fbo (depth + normalmap)
4128 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4129 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4130 // render depth into a renderbuffer and other important properties into the normalmap texture
4132 // set up the lighting pass fbo (diffuse + specular)
4133 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4134 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4135 // render diffuse into one texture and specular into another,
4136 // with depth and normalmap bound as textures,
4137 // with depth bound as attachment as well
4139 // set up the lighting pass fbo (diffuse)
4140 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4141 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4142 // render diffuse into one texture,
4143 // with depth and normalmap bound as textures,
4144 // with depth bound as attachment as well
4148 case RENDERPATH_GLES2:
4149 r_shadow_usingdeferredprepass = false;
4153 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);
4155 r_shadow_scenenumlights = 0;
4156 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4157 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4158 for (lightindex = 0; lightindex < range; lightindex++)
4160 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4161 if (light && (light->flags & flag))
4163 R_Shadow_PrepareLight(&light->rtlight);
4164 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4167 if (r_refdef.scene.rtdlight)
4169 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4171 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4172 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4175 else if (gl_flashblend.integer)
4177 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4179 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4180 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4181 VectorScale(rtlight->color, f, rtlight->currentcolor);
4185 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4186 if (r_shadow_debuglight.integer >= 0)
4188 r_shadow_scenenumlights = 0;
4189 lightindex = r_shadow_debuglight.integer;
4190 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4193 R_Shadow_PrepareLight(&light->rtlight);
4194 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4198 // if we're doing shadowmaps we need to prepare the atlas layout now
4199 if (R_Shadow_ShadowMappingEnabled())
4203 // allocate shadowmaps in the atlas now
4204 // 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...
4205 for (lod = 0; lod < 16; lod++)
4207 int packing_success = 0;
4208 int packing_failure = 0;
4209 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4210 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4211 if (r_shadow_shadowmapatlas_modelshadows_size)
4212 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);
4213 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4215 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4216 int size = rtlight->shadowmapsidesize >> lod;
4218 if (!rtlight->castshadows)
4220 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4223 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4224 if (rtlight->cached_numshadowentities_noselfshadow)
4226 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4228 rtlight->shadowmapatlassidesize = size;
4233 // note down that we failed to pack this one, it will have to disable shadows
4234 rtlight->shadowmapatlassidesize = 0;
4238 // generally everything fits and we stop here on the first iteration
4239 if (packing_failure == 0)
4244 if (r_editlights.integer)
4245 R_Shadow_DrawLightSprites();
4248 void R_Shadow_DrawShadowMaps(void)
4250 R_Shadow_RenderMode_Begin();
4251 R_Shadow_RenderMode_ActiveLight(NULL);
4253 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4254 R_Shadow_ClearShadowMapTexture();
4256 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4257 if (r_shadow_shadowmapatlas_modelshadows_size)
4259 R_Shadow_DrawModelShadowMaps();
4260 // don't let sound skip if going slow
4261 if (r_refdef.scene.extraupdate)
4265 if (R_Shadow_ShadowMappingEnabled())
4268 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4269 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4272 R_Shadow_RenderMode_End();
4275 void R_Shadow_DrawLights(void)
4279 R_Shadow_RenderMode_Begin();
4281 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4282 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4284 R_Shadow_RenderMode_End();
4287 #define MAX_MODELSHADOWS 1024
4288 static int r_shadow_nummodelshadows;
4289 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4291 void R_Shadow_PrepareModelShadows(void)
4294 float scale, size, radius, dot1, dot2;
4295 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4296 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4297 entity_render_t *ent;
4299 r_shadow_nummodelshadows = 0;
4300 r_shadow_shadowmapatlas_modelshadows_size = 0;
4302 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4305 size = r_shadow_shadowmaptexturesize / 4;
4306 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4307 radius = 0.5f * size / scale;
4309 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4310 VectorCopy(prvmshadowdir, shadowdir);
4311 VectorNormalize(shadowdir);
4312 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4313 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4314 if (fabs(dot1) <= fabs(dot2))
4315 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4317 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4318 VectorNormalize(shadowforward);
4319 CrossProduct(shadowdir, shadowforward, shadowright);
4320 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4321 VectorCopy(prvmshadowfocus, shadowfocus);
4322 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4323 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4324 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4325 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4326 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4328 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4330 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4331 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4332 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4333 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4334 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4335 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4337 for (i = 0; i < r_refdef.scene.numentities; i++)
4339 ent = r_refdef.scene.entities[i];
4340 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4342 // cast shadows from anything of the map (submodels are optional)
4343 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4345 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4347 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4348 R_AnimCache_GetEntity(ent, false, false);
4352 if (r_shadow_nummodelshadows)
4354 r_shadow_shadowmapatlas_modelshadows_x = 0;
4355 r_shadow_shadowmapatlas_modelshadows_y = 0;
4356 r_shadow_shadowmapatlas_modelshadows_size = size;
4360 static void R_Shadow_DrawModelShadowMaps(void)
4363 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4364 entity_render_t *ent;
4365 vec3_t relativelightorigin;
4366 vec3_t relativelightdirection, relativeforward, relativeright;
4367 vec3_t relativeshadowmins, relativeshadowmaxs;
4368 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4369 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4371 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4372 r_viewport_t viewport;
4374 size = r_shadow_shadowmapatlas_modelshadows_size;
4375 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4376 radius = 0.5f / scale;
4377 nearclip = -r_shadows_throwdistance.value;
4378 farclip = r_shadows_throwdistance.value;
4379 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);
4381 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4382 r_shadow_modelshadowmap_parameters[0] = size;
4383 r_shadow_modelshadowmap_parameters[1] = size;
4384 r_shadow_modelshadowmap_parameters[2] = 1.0;
4385 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4386 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4387 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4388 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4389 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4390 r_shadow_usingshadowmaportho = true;
4392 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4393 VectorCopy(prvmshadowdir, shadowdir);
4394 VectorNormalize(shadowdir);
4395 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4396 VectorCopy(prvmshadowfocus, shadowfocus);
4397 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4398 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4399 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4400 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4401 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4402 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4403 if (fabs(dot1) <= fabs(dot2))
4404 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4406 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4407 VectorNormalize(shadowforward);
4408 VectorM(scale, shadowforward, &m[0]);
4409 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4411 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4412 CrossProduct(shadowdir, shadowforward, shadowright);
4413 VectorM(scale, shadowright, &m[4]);
4414 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4415 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4416 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4417 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4418 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4419 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);
4420 R_SetViewport(&viewport);
4422 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4424 // render into a slightly restricted region so that the borders of the
4425 // shadowmap area fade away, rather than streaking across everything
4426 // outside the usable area
4427 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4429 for (i = 0;i < r_shadow_nummodelshadows;i++)
4431 ent = r_shadow_modelshadows[i];
4432 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4433 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4434 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4435 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4436 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4437 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4438 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4439 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4440 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4441 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4442 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4443 RSurf_ActiveModelEntity(ent, false, false, false);
4444 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4445 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4451 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4453 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4455 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4456 Cvar_SetValueQuick(&r_test, 0);
4461 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4462 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4463 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4464 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4465 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4466 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4469 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4472 vec3_t centerorigin;
4476 // if it's too close, skip it
4477 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4479 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4482 if (usequery && r_numqueries + 2 <= r_maxqueries)
4484 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4485 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4486 // 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
4487 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4489 switch(vid.renderpath)
4491 case RENDERPATH_GL32:
4492 case RENDERPATH_GLES2:
4495 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4496 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4497 GL_DepthFunc(GL_ALWAYS);
4498 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4499 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4500 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4501 qglEndQuery(GL_SAMPLES_PASSED);
4502 GL_DepthFunc(GL_LEQUAL);
4503 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4504 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4505 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4506 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4507 qglEndQuery(GL_SAMPLES_PASSED);
4513 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4516 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4518 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4521 unsigned int occlude = 0;
4523 // now we have to check the query result
4524 if (rtlight->corona_queryindex_visiblepixels)
4526 switch(vid.renderpath)
4528 case RENDERPATH_GL32:
4529 case RENDERPATH_GLES2:
4531 // store the pixel counts into a uniform buffer for the shader to
4532 // use - we'll never know the results on the cpu without
4533 // synchronizing and we don't want that
4534 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4535 if (!r_shadow_occlusion_buf) {
4536 qglGenBuffers(1, &r_shadow_occlusion_buf);
4537 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4538 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4540 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4542 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4543 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4544 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4545 occlude = MATERIALFLAG_OCCLUDE;
4546 cscale *= rtlight->corona_visibility;
4556 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4559 VectorScale(rtlight->currentcolor, cscale, color);
4560 if (VectorLength(color) > (1.0f / 256.0f))
4563 qboolean negated = (color[0] + color[1] + color[2] < 0);
4566 VectorNegate(color, color);
4567 GL_BlendEquationSubtract(true);
4569 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4570 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);
4571 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4573 GL_BlendEquationSubtract(false);
4577 void R_Shadow_DrawCoronas(void)
4580 qboolean usequery = false;
4585 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4587 if (r_fb.water.renderingscene)
4589 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4590 R_EntityMatrix(&identitymatrix);
4592 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4594 // check occlusion of coronas, using occlusion queries or raytraces
4596 switch (vid.renderpath)
4598 case RENDERPATH_GL32:
4599 case RENDERPATH_GLES2:
4600 usequery = r_coronas_occlusionquery.integer;
4604 GL_ColorMask(0,0,0,0);
4605 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4606 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4609 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4610 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4612 qglGenQueries(r_maxqueries - i, r_queries + i);
4615 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4616 GL_BlendFunc(GL_ONE, GL_ZERO);
4617 GL_CullFace(GL_NONE);
4618 GL_DepthMask(false);
4619 GL_DepthRange(0, 1);
4620 GL_PolygonOffset(0, 0);
4622 R_Mesh_ResetTextureState();
4623 R_SetupShader_Generic_NoTexture(false, false);
4628 for (lightindex = 0;lightindex < range;lightindex++)
4630 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4633 rtlight = &light->rtlight;
4634 rtlight->corona_visibility = 0;
4635 rtlight->corona_queryindex_visiblepixels = 0;
4636 rtlight->corona_queryindex_allpixels = 0;
4637 if (!(rtlight->flags & flag))
4639 if (rtlight->corona <= 0)
4641 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4643 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4645 for (i = 0;i < r_refdef.scene.numlights;i++)
4647 rtlight = r_refdef.scene.lights[i];
4648 rtlight->corona_visibility = 0;
4649 rtlight->corona_queryindex_visiblepixels = 0;
4650 rtlight->corona_queryindex_allpixels = 0;
4651 if (!(rtlight->flags & flag))
4653 if (rtlight->corona <= 0)
4655 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4658 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4660 // now draw the coronas using the query data for intensity info
4661 for (lightindex = 0;lightindex < range;lightindex++)
4663 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4666 rtlight = &light->rtlight;
4667 if (rtlight->corona_visibility <= 0)
4669 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4671 for (i = 0;i < r_refdef.scene.numlights;i++)
4673 rtlight = r_refdef.scene.lights[i];
4674 if (rtlight->corona_visibility <= 0)
4676 if (gl_flashblend.integer)
4677 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4679 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4685 static dlight_t *R_Shadow_NewWorldLight(void)
4687 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4690 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)
4694 // 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
4696 // validate parameters
4700 // copy to light properties
4701 VectorCopy(origin, light->origin);
4702 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4703 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4704 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4706 light->color[0] = max(color[0], 0);
4707 light->color[1] = max(color[1], 0);
4708 light->color[2] = max(color[2], 0);
4710 light->color[0] = color[0];
4711 light->color[1] = color[1];
4712 light->color[2] = color[2];
4713 light->radius = max(radius, 0);
4714 light->style = style;
4715 light->shadow = shadowenable;
4716 light->corona = corona;
4717 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4718 light->coronasizescale = coronasizescale;
4719 light->ambientscale = ambientscale;
4720 light->diffusescale = diffusescale;
4721 light->specularscale = specularscale;
4722 light->flags = flags;
4724 // update renderable light data
4725 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4726 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);
4729 static void R_Shadow_FreeWorldLight(dlight_t *light)
4731 if (r_shadow_selectedlight == light)
4732 r_shadow_selectedlight = NULL;
4733 R_RTLight_Uncompile(&light->rtlight);
4734 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4737 void R_Shadow_ClearWorldLights(void)
4741 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4742 for (lightindex = 0;lightindex < range;lightindex++)
4744 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4746 R_Shadow_FreeWorldLight(light);
4748 r_shadow_selectedlight = NULL;
4751 static void R_Shadow_SelectLight(dlight_t *light)
4753 if (r_shadow_selectedlight)
4754 r_shadow_selectedlight->selected = false;
4755 r_shadow_selectedlight = light;
4756 if (r_shadow_selectedlight)
4757 r_shadow_selectedlight->selected = true;
4760 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4762 // this is never batched (there can be only one)
4764 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4765 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4766 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4769 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4774 skinframe_t *skinframe;
4777 // this is never batched (due to the ent parameter changing every time)
4778 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4779 const dlight_t *light = (dlight_t *)ent;
4782 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4785 VectorScale(light->color, intensity, spritecolor);
4786 if (VectorLength(spritecolor) < 0.1732f)
4787 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4788 if (VectorLength(spritecolor) > 1.0f)
4789 VectorNormalize(spritecolor);
4791 // draw light sprite
4792 if (light->cubemapname[0] && !light->shadow)
4793 skinframe = r_editlights_sprcubemapnoshadowlight;
4794 else if (light->cubemapname[0])
4795 skinframe = r_editlights_sprcubemaplight;
4796 else if (!light->shadow)
4797 skinframe = r_editlights_sprnoshadowlight;
4799 skinframe = r_editlights_sprlight;
4801 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);
4802 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4804 // draw selection sprite if light is selected
4805 if (light->selected)
4807 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4808 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4809 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4813 void R_Shadow_DrawLightSprites(void)
4817 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4818 for (lightindex = 0;lightindex < range;lightindex++)
4820 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4822 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4824 if (!r_editlights_lockcursor)
4825 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4828 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4833 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4834 if (lightindex >= range)
4836 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4839 rtlight = &light->rtlight;
4840 //if (!(rtlight->flags & flag))
4842 VectorCopy(rtlight->shadoworigin, origin);
4843 *radius = rtlight->radius;
4844 VectorCopy(rtlight->color, color);
4848 static void R_Shadow_SelectLightInView(void)
4850 float bestrating, rating, temp[3];
4854 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4858 if (r_editlights_lockcursor)
4860 for (lightindex = 0;lightindex < range;lightindex++)
4862 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4865 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4866 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4869 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4870 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)
4872 bestrating = rating;
4877 R_Shadow_SelectLight(best);
4880 void R_Shadow_LoadWorldLights(void)
4882 int n, a, style, shadow, flags;
4883 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4884 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4885 if (cl.worldmodel == NULL)
4887 Con_Print("No map loaded.\n");
4890 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4891 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4901 for (;COM_Parse(t, true) && strcmp(
4902 if (COM_Parse(t, true))
4904 if (com_token[0] == '!')
4907 origin[0] = atof(com_token+1);
4910 origin[0] = atof(com_token);
4915 while (*s && *s != '\n' && *s != '\r')
4921 // check for modifier flags
4928 #if _MSC_VER >= 1400
4929 #define sscanf sscanf_s
4931 cubemapname[sizeof(cubemapname)-1] = 0;
4932 #if MAX_QPATH != 128
4933 #error update this code if MAX_QPATH changes
4935 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
4936 #if _MSC_VER >= 1400
4937 , (unsigned int)sizeof(cubemapname)
4939 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4942 flags = LIGHTFLAG_REALTIMEMODE;
4950 coronasizescale = 0.25f;
4952 VectorClear(angles);
4955 if (a < 9 || !strcmp(cubemapname, "\"\""))
4957 // remove quotes on cubemapname
4958 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4961 namelen = strlen(cubemapname) - 2;
4962 memmove(cubemapname, cubemapname + 1, namelen);
4963 cubemapname[namelen] = '\0';
4967 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);
4970 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4978 Con_Printf("invalid rtlights file \"%s\"\n", name);
4979 Mem_Free(lightsstring);
4983 void R_Shadow_SaveWorldLights(void)
4987 size_t bufchars, bufmaxchars;
4989 char name[MAX_QPATH];
4990 char line[MAX_INPUTLINE];
4991 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4992 // I hate lines which are 3 times my screen size :( --blub
4995 if (cl.worldmodel == NULL)
4997 Con_Print("No map loaded.\n");
5000 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5001 bufchars = bufmaxchars = 0;
5003 for (lightindex = 0;lightindex < range;lightindex++)
5005 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5008 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5009 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);
5010 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5011 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]);
5013 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);
5014 if (bufchars + strlen(line) > bufmaxchars)
5016 bufmaxchars = bufchars + strlen(line) + 2048;
5018 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5022 memcpy(buf, oldbuf, bufchars);
5028 memcpy(buf + bufchars, line, strlen(line));
5029 bufchars += strlen(line);
5033 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5038 void R_Shadow_LoadLightsFile(void)
5041 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5042 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5043 if (cl.worldmodel == NULL)
5045 Con_Print("No map loaded.\n");
5048 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5049 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5057 while (*s && *s != '\n' && *s != '\r')
5063 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);
5067 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);
5070 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5071 radius = bound(15, radius, 4096);
5072 VectorScale(color, (2.0f / (8388608.0f)), color);
5073 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5081 Con_Printf("invalid lights file \"%s\"\n", name);
5082 Mem_Free(lightsstring);
5086 // tyrlite/hmap2 light types in the delay field
5087 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5089 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5101 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5102 char key[256], value[MAX_INPUTLINE];
5105 if (cl.worldmodel == NULL)
5107 Con_Print("No map loaded.\n");
5110 // try to load a .ent file first
5111 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5112 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5113 // and if that is not found, fall back to the bsp file entity string
5115 data = cl.worldmodel->brush.entities;
5118 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5120 type = LIGHTTYPE_MINUSX;
5121 origin[0] = origin[1] = origin[2] = 0;
5122 originhack[0] = originhack[1] = originhack[2] = 0;
5123 angles[0] = angles[1] = angles[2] = 0;
5124 color[0] = color[1] = color[2] = 1;
5125 light[0] = light[1] = light[2] = 1;light[3] = 300;
5126 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5136 if (!COM_ParseToken_Simple(&data, false, false, true))
5138 if (com_token[0] == '}')
5139 break; // end of entity
5140 if (com_token[0] == '_')
5141 strlcpy(key, com_token + 1, sizeof(key));
5143 strlcpy(key, com_token, sizeof(key));
5144 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5145 key[strlen(key)-1] = 0;
5146 if (!COM_ParseToken_Simple(&data, false, false, true))
5148 strlcpy(value, com_token, sizeof(value));
5150 // now that we have the key pair worked out...
5151 if (!strcmp("light", key))
5153 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5157 light[0] = vec[0] * (1.0f / 256.0f);
5158 light[1] = vec[0] * (1.0f / 256.0f);
5159 light[2] = vec[0] * (1.0f / 256.0f);
5165 light[0] = vec[0] * (1.0f / 255.0f);
5166 light[1] = vec[1] * (1.0f / 255.0f);
5167 light[2] = vec[2] * (1.0f / 255.0f);
5171 else if (!strcmp("delay", key))
5173 else if (!strcmp("origin", key))
5174 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5175 else if (!strcmp("angle", key))
5176 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5177 else if (!strcmp("angles", key))
5178 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5179 else if (!strcmp("color", key))
5180 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5181 else if (!strcmp("wait", key))
5182 fadescale = atof(value);
5183 else if (!strcmp("classname", key))
5185 if (!strncmp(value, "light", 5))
5188 if (!strcmp(value, "light_fluoro"))
5193 overridecolor[0] = 1;
5194 overridecolor[1] = 1;
5195 overridecolor[2] = 1;
5197 if (!strcmp(value, "light_fluorospark"))
5202 overridecolor[0] = 1;
5203 overridecolor[1] = 1;
5204 overridecolor[2] = 1;
5206 if (!strcmp(value, "light_globe"))
5211 overridecolor[0] = 1;
5212 overridecolor[1] = 0.8;
5213 overridecolor[2] = 0.4;
5215 if (!strcmp(value, "light_flame_large_yellow"))
5220 overridecolor[0] = 1;
5221 overridecolor[1] = 0.5;
5222 overridecolor[2] = 0.1;
5224 if (!strcmp(value, "light_flame_small_yellow"))
5229 overridecolor[0] = 1;
5230 overridecolor[1] = 0.5;
5231 overridecolor[2] = 0.1;
5233 if (!strcmp(value, "light_torch_small_white"))
5238 overridecolor[0] = 1;
5239 overridecolor[1] = 0.5;
5240 overridecolor[2] = 0.1;
5242 if (!strcmp(value, "light_torch_small_walltorch"))
5247 overridecolor[0] = 1;
5248 overridecolor[1] = 0.5;
5249 overridecolor[2] = 0.1;
5253 else if (!strcmp("style", key))
5254 style = atoi(value);
5255 else if (!strcmp("skin", key))
5256 skin = (int)atof(value);
5257 else if (!strcmp("pflags", key))
5258 pflags = (int)atof(value);
5259 //else if (!strcmp("effects", key))
5260 // effects = (int)atof(value);
5261 else if (cl.worldmodel->type == mod_brushq3)
5263 if (!strcmp("scale", key))
5264 lightscale = atof(value);
5265 if (!strcmp("fade", key))
5266 fadescale = atof(value);
5271 if (lightscale <= 0)
5275 if (color[0] == color[1] && color[0] == color[2])
5277 color[0] *= overridecolor[0];
5278 color[1] *= overridecolor[1];
5279 color[2] *= overridecolor[2];
5281 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5282 color[0] = color[0] * light[0];
5283 color[1] = color[1] * light[1];
5284 color[2] = color[2] * light[2];
5287 case LIGHTTYPE_MINUSX:
5289 case LIGHTTYPE_RECIPX:
5291 VectorScale(color, (1.0f / 16.0f), color);
5293 case LIGHTTYPE_RECIPXX:
5295 VectorScale(color, (1.0f / 16.0f), color);
5298 case LIGHTTYPE_NONE:
5302 case LIGHTTYPE_MINUSXX:
5305 VectorAdd(origin, originhack, origin);
5307 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);
5310 Mem_Free(entfiledata);
5314 static void R_Shadow_SetCursorLocationForView(void)
5317 vec3_t dest, endpos;
5319 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5320 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5321 if (trace.fraction < 1)
5323 dist = trace.fraction * r_editlights_cursordistance.value;
5324 push = r_editlights_cursorpushback.value;
5328 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5329 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5333 VectorClear( endpos );
5335 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5336 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5337 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5340 void R_Shadow_UpdateWorldLightSelection(void)
5342 if (r_editlights.integer)
5344 R_Shadow_SetCursorLocationForView();
5345 R_Shadow_SelectLightInView();
5348 R_Shadow_SelectLight(NULL);
5351 static void R_Shadow_EditLights_Clear_f(cmd_state_t *cmd)
5353 R_Shadow_ClearWorldLights();
5356 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd)
5360 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5361 R_Shadow_ClearWorldLights();
5362 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5364 R_Shadow_LoadWorldLights();
5365 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5366 R_Shadow_LoadLightsFile();
5368 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5370 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5371 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5375 static void R_Shadow_EditLights_Save_f(cmd_state_t *cmd)
5379 R_Shadow_SaveWorldLights();
5382 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(cmd_state_t *cmd)
5384 R_Shadow_ClearWorldLights();
5385 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5388 static void R_Shadow_EditLights_ImportLightsFile_f(cmd_state_t *cmd)
5390 R_Shadow_ClearWorldLights();
5391 R_Shadow_LoadLightsFile();
5394 static void R_Shadow_EditLights_Spawn_f(cmd_state_t *cmd)
5397 if (!r_editlights.integer)
5399 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5402 if (Cmd_Argc(cmd) != 1)
5404 Con_Print("r_editlights_spawn does not take parameters\n");
5407 color[0] = color[1] = color[2] = 1;
5408 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5411 static void R_Shadow_EditLights_Edit_f(cmd_state_t *cmd)
5413 vec3_t origin, angles, color;
5414 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5415 int style, shadows, flags, normalmode, realtimemode;
5416 char cubemapname[MAX_INPUTLINE];
5417 if (!r_editlights.integer)
5419 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5422 if (!r_shadow_selectedlight)
5424 Con_Print("No selected light.\n");
5427 VectorCopy(r_shadow_selectedlight->origin, origin);
5428 VectorCopy(r_shadow_selectedlight->angles, angles);
5429 VectorCopy(r_shadow_selectedlight->color, color);
5430 radius = r_shadow_selectedlight->radius;
5431 style = r_shadow_selectedlight->style;
5432 if (r_shadow_selectedlight->cubemapname)
5433 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5436 shadows = r_shadow_selectedlight->shadow;
5437 corona = r_shadow_selectedlight->corona;
5438 coronasizescale = r_shadow_selectedlight->coronasizescale;
5439 ambientscale = r_shadow_selectedlight->ambientscale;
5440 diffusescale = r_shadow_selectedlight->diffusescale;
5441 specularscale = r_shadow_selectedlight->specularscale;
5442 flags = r_shadow_selectedlight->flags;
5443 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5444 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5445 if (!strcmp(Cmd_Argv(cmd, 1), "origin"))
5447 if (Cmd_Argc(cmd) != 5)
5449 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5452 origin[0] = atof(Cmd_Argv(cmd, 2));
5453 origin[1] = atof(Cmd_Argv(cmd, 3));
5454 origin[2] = atof(Cmd_Argv(cmd, 4));
5456 else if (!strcmp(Cmd_Argv(cmd, 1), "originscale"))
5458 if (Cmd_Argc(cmd) != 5)
5460 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5463 origin[0] *= atof(Cmd_Argv(cmd, 2));
5464 origin[1] *= atof(Cmd_Argv(cmd, 3));
5465 origin[2] *= atof(Cmd_Argv(cmd, 4));
5467 else if (!strcmp(Cmd_Argv(cmd, 1), "originx"))
5469 if (Cmd_Argc(cmd) != 3)
5471 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5474 origin[0] = atof(Cmd_Argv(cmd, 2));
5476 else if (!strcmp(Cmd_Argv(cmd, 1), "originy"))
5478 if (Cmd_Argc(cmd) != 3)
5480 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5483 origin[1] = atof(Cmd_Argv(cmd, 2));
5485 else if (!strcmp(Cmd_Argv(cmd, 1), "originz"))
5487 if (Cmd_Argc(cmd) != 3)
5489 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5492 origin[2] = atof(Cmd_Argv(cmd, 2));
5494 else if (!strcmp(Cmd_Argv(cmd, 1), "move"))
5496 if (Cmd_Argc(cmd) != 5)
5498 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5501 origin[0] += atof(Cmd_Argv(cmd, 2));
5502 origin[1] += atof(Cmd_Argv(cmd, 3));
5503 origin[2] += atof(Cmd_Argv(cmd, 4));
5505 else if (!strcmp(Cmd_Argv(cmd, 1), "movex"))
5507 if (Cmd_Argc(cmd) != 3)
5509 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5512 origin[0] += atof(Cmd_Argv(cmd, 2));
5514 else if (!strcmp(Cmd_Argv(cmd, 1), "movey"))
5516 if (Cmd_Argc(cmd) != 3)
5518 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5521 origin[1] += atof(Cmd_Argv(cmd, 2));
5523 else if (!strcmp(Cmd_Argv(cmd, 1), "movez"))
5525 if (Cmd_Argc(cmd) != 3)
5527 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5530 origin[2] += atof(Cmd_Argv(cmd, 2));
5532 else if (!strcmp(Cmd_Argv(cmd, 1), "angles"))
5534 if (Cmd_Argc(cmd) != 5)
5536 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5539 angles[0] = atof(Cmd_Argv(cmd, 2));
5540 angles[1] = atof(Cmd_Argv(cmd, 3));
5541 angles[2] = atof(Cmd_Argv(cmd, 4));
5543 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesx"))
5545 if (Cmd_Argc(cmd) != 3)
5547 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5550 angles[0] = atof(Cmd_Argv(cmd, 2));
5552 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesy"))
5554 if (Cmd_Argc(cmd) != 3)
5556 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5559 angles[1] = atof(Cmd_Argv(cmd, 2));
5561 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesz"))
5563 if (Cmd_Argc(cmd) != 3)
5565 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5568 angles[2] = atof(Cmd_Argv(cmd, 2));
5570 else if (!strcmp(Cmd_Argv(cmd, 1), "color"))
5572 if (Cmd_Argc(cmd) != 5)
5574 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(cmd, 1));
5577 color[0] = atof(Cmd_Argv(cmd, 2));
5578 color[1] = atof(Cmd_Argv(cmd, 3));
5579 color[2] = atof(Cmd_Argv(cmd, 4));
5581 else if (!strcmp(Cmd_Argv(cmd, 1), "radius"))
5583 if (Cmd_Argc(cmd) != 3)
5585 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5588 radius = atof(Cmd_Argv(cmd, 2));
5590 else if (!strcmp(Cmd_Argv(cmd, 1), "colorscale"))
5592 if (Cmd_Argc(cmd) == 3)
5594 double scale = atof(Cmd_Argv(cmd, 2));
5601 if (Cmd_Argc(cmd) != 5)
5603 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(cmd, 1));
5606 color[0] *= atof(Cmd_Argv(cmd, 2));
5607 color[1] *= atof(Cmd_Argv(cmd, 3));
5608 color[2] *= atof(Cmd_Argv(cmd, 4));
5611 else if (!strcmp(Cmd_Argv(cmd, 1), "radiusscale") || !strcmp(Cmd_Argv(cmd, 1), "sizescale"))
5613 if (Cmd_Argc(cmd) != 3)
5615 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5618 radius *= atof(Cmd_Argv(cmd, 2));
5620 else if (!strcmp(Cmd_Argv(cmd, 1), "style"))
5622 if (Cmd_Argc(cmd) != 3)
5624 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5627 style = atoi(Cmd_Argv(cmd, 2));
5629 else if (!strcmp(Cmd_Argv(cmd, 1), "cubemap"))
5631 if (Cmd_Argc(cmd) > 3)
5633 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5636 if (Cmd_Argc(cmd) == 3)
5637 strlcpy(cubemapname, Cmd_Argv(cmd, 2), sizeof(cubemapname));
5641 else if (!strcmp(Cmd_Argv(cmd, 1), "shadows"))
5643 if (Cmd_Argc(cmd) != 3)
5645 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5648 shadows = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5650 else if (!strcmp(Cmd_Argv(cmd, 1), "corona"))
5652 if (Cmd_Argc(cmd) != 3)
5654 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5657 corona = atof(Cmd_Argv(cmd, 2));
5659 else if (!strcmp(Cmd_Argv(cmd, 1), "coronasize"))
5661 if (Cmd_Argc(cmd) != 3)
5663 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5666 coronasizescale = atof(Cmd_Argv(cmd, 2));
5668 else if (!strcmp(Cmd_Argv(cmd, 1), "ambient"))
5670 if (Cmd_Argc(cmd) != 3)
5672 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5675 ambientscale = atof(Cmd_Argv(cmd, 2));
5677 else if (!strcmp(Cmd_Argv(cmd, 1), "diffuse"))
5679 if (Cmd_Argc(cmd) != 3)
5681 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5684 diffusescale = atof(Cmd_Argv(cmd, 2));
5686 else if (!strcmp(Cmd_Argv(cmd, 1), "specular"))
5688 if (Cmd_Argc(cmd) != 3)
5690 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5693 specularscale = atof(Cmd_Argv(cmd, 2));
5695 else if (!strcmp(Cmd_Argv(cmd, 1), "normalmode"))
5697 if (Cmd_Argc(cmd) != 3)
5699 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5702 normalmode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5704 else if (!strcmp(Cmd_Argv(cmd, 1), "realtimemode"))
5706 if (Cmd_Argc(cmd) != 3)
5708 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5711 realtimemode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5715 Con_Print("usage: r_editlights_edit [property] [value]\n");
5716 Con_Print("Selected light's properties:\n");
5717 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5718 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5719 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5720 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5721 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5722 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5723 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5724 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5725 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5726 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5727 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5728 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5729 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5730 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5733 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5734 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5737 static void R_Shadow_EditLights_EditAll_f(cmd_state_t *cmd)
5740 dlight_t *light, *oldselected;
5743 if (!r_editlights.integer)
5745 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5749 oldselected = r_shadow_selectedlight;
5750 // EditLights doesn't seem to have a "remove" command or something so:
5751 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5752 for (lightindex = 0;lightindex < range;lightindex++)
5754 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5757 R_Shadow_SelectLight(light);
5758 R_Shadow_EditLights_Edit_f(&cmd_client);
5760 // return to old selected (to not mess editing once selection is locked)
5761 R_Shadow_SelectLight(oldselected);
5764 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5766 int lightnumber, lightcount;
5767 size_t lightindex, range;
5772 if (!r_editlights.integer)
5775 // update cvars so QC can query them
5776 if (r_shadow_selectedlight)
5778 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5779 Cvar_SetQuick(&r_editlights_current_origin, temp);
5780 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5781 Cvar_SetQuick(&r_editlights_current_angles, temp);
5782 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5783 Cvar_SetQuick(&r_editlights_current_color, temp);
5784 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5785 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5786 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5787 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5788 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5789 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5790 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5791 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5792 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5793 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5794 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5797 // draw properties on screen
5798 if (!r_editlights_drawproperties.integer)
5800 x = vid_conwidth.value - 320;
5802 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5805 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5806 for (lightindex = 0;lightindex < range;lightindex++)
5808 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5811 if (light == r_shadow_selectedlight)
5812 lightnumber = (int)lightindex;
5815 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;
5816 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;
5818 if (r_shadow_selectedlight == NULL)
5820 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;
5821 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;
5822 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;
5823 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;
5824 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;
5825 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;
5826 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;
5827 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;
5828 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;
5829 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;
5830 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;
5831 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;
5832 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;
5833 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;
5834 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;
5836 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;
5837 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;
5838 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;
5839 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;
5840 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;
5841 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;
5842 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;
5843 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;
5844 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;
5845 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;
5848 static void R_Shadow_EditLights_ToggleShadow_f(cmd_state_t *cmd)
5850 if (!r_editlights.integer)
5852 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5855 if (!r_shadow_selectedlight)
5857 Con_Print("No selected light.\n");
5860 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);
5863 static void R_Shadow_EditLights_ToggleCorona_f(cmd_state_t *cmd)
5865 if (!r_editlights.integer)
5867 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5870 if (!r_shadow_selectedlight)
5872 Con_Print("No selected light.\n");
5875 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);
5878 static void R_Shadow_EditLights_Remove_f(cmd_state_t *cmd)
5880 if (!r_editlights.integer)
5882 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5885 if (!r_shadow_selectedlight)
5887 Con_Print("No selected light.\n");
5890 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5891 r_shadow_selectedlight = NULL;
5894 static void R_Shadow_EditLights_Help_f(cmd_state_t *cmd)
5897 "Documentation on r_editlights system:\n"
5899 "r_editlights : enable/disable editing mode\n"
5900 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5901 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5902 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5903 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5904 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5906 "r_editlights_help : this help\n"
5907 "r_editlights_clear : remove all lights\n"
5908 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5909 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5910 "r_editlights_save : save to .rtlights file\n"
5911 "r_editlights_spawn : create a light with default settings\n"
5912 "r_editlights_edit command : edit selected light - more documentation below\n"
5913 "r_editlights_remove : remove selected light\n"
5914 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5915 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5916 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5918 "origin x y z : set light location\n"
5919 "originx x: set x component of light location\n"
5920 "originy y: set y component of light location\n"
5921 "originz z: set z component of light location\n"
5922 "move x y z : adjust light location\n"
5923 "movex x: adjust x component of light location\n"
5924 "movey y: adjust y component of light location\n"
5925 "movez z: adjust z component of light location\n"
5926 "angles x y z : set light angles\n"
5927 "anglesx x: set x component of light angles\n"
5928 "anglesy y: set y component of light angles\n"
5929 "anglesz z: set z component of light angles\n"
5930 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5931 "radius radius : set radius (size) of light\n"
5932 "colorscale grey : multiply color of light (1 does nothing)\n"
5933 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5934 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5935 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5936 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5937 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5938 "cubemap basename : set filter cubemap of light\n"
5939 "shadows 1/0 : turn on/off shadows\n"
5940 "corona n : set corona intensity\n"
5941 "coronasize n : set corona size (0-1)\n"
5942 "ambient n : set ambient intensity (0-1)\n"
5943 "diffuse n : set diffuse intensity (0-1)\n"
5944 "specular n : set specular intensity (0-1)\n"
5945 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5946 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5947 "<nothing> : print light properties to console\n"
5951 static void R_Shadow_EditLights_CopyInfo_f(cmd_state_t *cmd)
5953 if (!r_editlights.integer)
5955 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5958 if (!r_shadow_selectedlight)
5960 Con_Print("No selected light.\n");
5963 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5964 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5965 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5966 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5967 if (r_shadow_selectedlight->cubemapname)
5968 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5970 r_shadow_bufferlight.cubemapname[0] = 0;
5971 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5972 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5973 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5974 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5975 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5976 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5977 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5980 static void R_Shadow_EditLights_PasteInfo_f(cmd_state_t *cmd)
5982 if (!r_editlights.integer)
5984 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5987 if (!r_shadow_selectedlight)
5989 Con_Print("No selected light.\n");
5992 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);
5995 static void R_Shadow_EditLights_Lock_f(cmd_state_t *cmd)
5997 if (!r_editlights.integer)
5999 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6002 if (r_editlights_lockcursor)
6004 r_editlights_lockcursor = false;
6007 if (!r_shadow_selectedlight)
6009 Con_Print("No selected light to lock on.\n");
6012 r_editlights_lockcursor = true;
6015 static void R_Shadow_EditLights_Init(void)
6017 Cvar_RegisterVariable(&r_editlights);
6018 Cvar_RegisterVariable(&r_editlights_cursordistance);
6019 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6020 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6021 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6022 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6023 Cvar_RegisterVariable(&r_editlights_drawproperties);
6024 Cvar_RegisterVariable(&r_editlights_current_origin);
6025 Cvar_RegisterVariable(&r_editlights_current_angles);
6026 Cvar_RegisterVariable(&r_editlights_current_color);
6027 Cvar_RegisterVariable(&r_editlights_current_radius);
6028 Cvar_RegisterVariable(&r_editlights_current_corona);
6029 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6030 Cvar_RegisterVariable(&r_editlights_current_style);
6031 Cvar_RegisterVariable(&r_editlights_current_shadows);
6032 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6033 Cvar_RegisterVariable(&r_editlights_current_ambient);
6034 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6035 Cvar_RegisterVariable(&r_editlights_current_specular);
6036 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6037 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6038 Cmd_AddCommand(&cmd_client, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6039 Cmd_AddCommand(&cmd_client, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6040 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)");
6041 Cmd_AddCommand(&cmd_client, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6042 Cmd_AddCommand(&cmd_client, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6043 Cmd_AddCommand(&cmd_client, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6044 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)");
6045 Cmd_AddCommand(&cmd_client, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6046 Cmd_AddCommand(&cmd_client, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6047 Cmd_AddCommand(&cmd_client, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6048 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)");
6049 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)");
6050 Cmd_AddCommand(&cmd_client, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6051 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)");
6052 Cmd_AddCommand(&cmd_client, "r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6058 =============================================================================
6062 =============================================================================
6065 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6067 int i, numlights, flag, q;
6070 float relativepoint[3];
6075 float sa[3], sx[3], sy[3], sz[3], sd[3];
6078 // use first order spherical harmonics to combine directional lights
6079 for (q = 0; q < 3; q++)
6080 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6082 if (flags & LP_LIGHTMAP)
6084 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6086 float tempambient[3];
6087 for (q = 0; q < 3; q++)
6088 tempambient[q] = color[q] = relativepoint[q] = 0;
6089 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6090 // calculate a weighted average light direction as well
6091 intensity = VectorLength(color);
6092 for (q = 0; q < 3; q++)
6094 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6095 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6096 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6097 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6098 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6103 // unlit map - fullbright but scaled by lightmapintensity
6104 for (q = 0; q < 3; q++)
6105 sa[q] += lightmapintensity;
6109 if (flags & LP_RTWORLD)
6111 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6112 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6113 for (i = 0; i < numlights; i++)
6115 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6118 light = &dlight->rtlight;
6119 if (!(light->flags & flag))
6122 lightradius2 = light->radius * light->radius;
6123 VectorSubtract(light->shadoworigin, p, relativepoint);
6124 dist2 = VectorLength2(relativepoint);
6125 if (dist2 >= lightradius2)
6127 dist = sqrt(dist2) / light->radius;
6128 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6129 if (intensity <= 0.0f)
6131 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)
6133 for (q = 0; q < 3; q++)
6134 color[q] = light->currentcolor[q] * intensity;
6135 intensity = VectorLength(color);
6136 VectorNormalize(relativepoint);
6137 for (q = 0; q < 3; q++)
6139 sa[q] += 0.5f * color[q];
6140 sx[q] += relativepoint[0] * color[q];
6141 sy[q] += relativepoint[1] * color[q];
6142 sz[q] += relativepoint[2] * color[q];
6143 sd[q] += intensity * relativepoint[q];
6146 // FIXME: sample bouncegrid too!
6149 if (flags & LP_DYNLIGHT)
6152 for (i = 0;i < r_refdef.scene.numlights;i++)
6154 light = r_refdef.scene.lights[i];
6156 lightradius2 = light->radius * light->radius;
6157 VectorSubtract(light->shadoworigin, p, relativepoint);
6158 dist2 = VectorLength2(relativepoint);
6159 if (dist2 >= lightradius2)
6161 dist = sqrt(dist2) / light->radius;
6162 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6163 if (intensity <= 0.0f)
6165 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)
6167 for (q = 0; q < 3; q++)
6168 color[q] = light->currentcolor[q] * intensity;
6169 intensity = VectorLength(color);
6170 VectorNormalize(relativepoint);
6171 for (q = 0; q < 3; q++)
6173 sa[q] += 0.5f * color[q];
6174 sx[q] += relativepoint[0] * color[q];
6175 sy[q] += relativepoint[1] * color[q];
6176 sz[q] += relativepoint[2] * color[q];
6177 sd[q] += intensity * relativepoint[q];
6182 // calculate the weighted-average light direction (bentnormal)
6183 for (q = 0; q < 3; q++)
6184 lightdir[q] = sd[q];
6185 VectorNormalize(lightdir);
6186 for (q = 0; q < 3; q++)
6188 // extract the diffuse color along the chosen direction and scale it
6189 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6190 // subtract some of diffuse from ambient
6191 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;