3 #include "cl_collision.h"
7 static void R_Shadow_EditLights_Init(void);
9 typedef enum r_shadow_rendermode_e
11 R_SHADOW_RENDERMODE_NONE,
12 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
13 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
14 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
15 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
16 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
17 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
18 R_SHADOW_RENDERMODE_LIGHT_GLSL,
19 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
20 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
21 R_SHADOW_RENDERMODE_SHADOWMAP2D
23 r_shadow_rendermode_t;
25 typedef enum r_shadow_shadowmode_e
27 R_SHADOW_SHADOWMODE_DISABLED,
28 R_SHADOW_SHADOWMODE_SHADOWMAP2D
30 r_shadow_shadowmode_t;
32 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
33 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
34 int r_shadow_scenemaxlights;
35 int r_shadow_scenenumlights;
36 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
37 qboolean r_shadow_usingshadowmap2d;
38 qboolean r_shadow_usingshadowmaportho;
39 int r_shadow_shadowmapside;
40 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
41 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
42 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
43 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
45 int r_shadow_drawbuffer;
46 int r_shadow_readbuffer;
48 int r_shadow_cullface_front, r_shadow_cullface_back;
49 GLuint r_shadow_fbo2d;
50 int r_shadow_shadowmode_shadowmapping; // cached value of r_shadow_shadowmapping cvar
51 int r_shadow_shadowmode_deferred; // cached value of r_shadow_deferred cvar
52 r_shadow_shadowmode_t r_shadow_shadowmode;
53 int r_shadow_shadowmapfilterquality;
54 int r_shadow_shadowmapdepthbits;
55 int r_shadow_shadowmapmaxsize;
56 int r_shadow_shadowmaptexturesize;
57 qboolean r_shadow_shadowmapvsdct;
58 qboolean r_shadow_shadowmapsampler;
59 qboolean r_shadow_shadowmapshadowsampler;
60 int r_shadow_shadowmappcf;
61 int r_shadow_shadowmapborder;
62 matrix4x4_t r_shadow_shadowmapmatrix;
63 int r_shadow_lightscissor[4];
64 qboolean r_shadow_usingdeferredprepass;
65 qboolean r_shadow_shadowmapdepthtexture;
66 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
67 int r_shadow_shadowmapatlas_modelshadows_x;
68 int r_shadow_shadowmapatlas_modelshadows_y;
69 int r_shadow_shadowmapatlas_modelshadows_size;
70 int maxshadowtriangles;
73 int maxshadowvertices;
74 float *shadowvertex3f;
84 unsigned char *shadowsides;
92 int r_shadow_buffer_numleafpvsbytes;
93 unsigned char *r_shadow_buffer_visitingleafpvs;
94 unsigned char *r_shadow_buffer_leafpvs;
95 int *r_shadow_buffer_leaflist;
97 int r_shadow_buffer_numsurfacepvsbytes;
98 unsigned char *r_shadow_buffer_surfacepvs;
99 int *r_shadow_buffer_surfacelist;
100 unsigned char *r_shadow_buffer_surfacesides;
102 int r_shadow_buffer_numshadowtrispvsbytes;
103 unsigned char *r_shadow_buffer_shadowtrispvs;
104 int r_shadow_buffer_numlighttrispvsbytes;
105 unsigned char *r_shadow_buffer_lighttrispvs;
107 rtexturepool_t *r_shadow_texturepool;
108 rtexture_t *r_shadow_attenuationgradienttexture;
109 skinframe_t *r_shadow_lightcorona;
110 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
111 rtexture_t *r_shadow_shadowmap2ddepthtexture;
112 rtexture_t *r_shadow_shadowmapvsdcttexture;
114 GLuint r_shadow_prepassgeometryfbo;
115 GLuint r_shadow_prepasslightingdiffusespecularfbo;
116 GLuint r_shadow_prepasslightingdiffusefbo;
117 int r_shadow_prepass_width;
118 int r_shadow_prepass_height;
119 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
120 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
121 rtexture_t *r_shadow_prepasslightingdiffusetexture;
122 rtexture_t *r_shadow_prepasslightingspeculartexture;
124 int r_shadow_viewfbo;
125 rtexture_t *r_shadow_viewdepthtexture;
126 rtexture_t *r_shadow_viewcolortexture;
129 int r_shadow_viewwidth;
130 int r_shadow_viewheight;
132 // lights are reloaded when this changes
133 char r_shadow_mapname[MAX_QPATH];
135 // buffer for doing corona fading
136 unsigned int r_shadow_occlusion_buf = 0;
138 // used only for light filters (cubemaps)
139 rtexturepool_t *r_shadow_filters_texturepool;
141 cvar_t r_shadow_bumpscale_basetexture = {CVAR_CLIENT, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
142 cvar_t r_shadow_bumpscale_bumpmap = {CVAR_CLIENT, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
143 cvar_t r_shadow_debuglight = {CVAR_CLIENT, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
144 cvar_t r_shadow_deferred = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
145 cvar_t r_shadow_usebihculling = {CVAR_CLIENT, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
146 cvar_t r_shadow_usenormalmap = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
147 cvar_t r_shadow_gloss = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
148 cvar_t r_shadow_gloss2intensity = {CVAR_CLIENT, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
149 cvar_t r_shadow_glossintensity = {CVAR_CLIENT, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
150 cvar_t r_shadow_glossexponent = {CVAR_CLIENT, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
151 cvar_t r_shadow_gloss2exponent = {CVAR_CLIENT, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
152 cvar_t r_shadow_glossexact = {CVAR_CLIENT, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
153 cvar_t r_shadow_lightattenuationdividebias = {CVAR_CLIENT, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
154 cvar_t r_shadow_lightattenuationlinearscale = {CVAR_CLIENT, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
155 cvar_t r_shadow_lightintensityscale = {CVAR_CLIENT, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
156 cvar_t r_shadow_lightradiusscale = {CVAR_CLIENT, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
157 cvar_t r_shadow_projectdistance = {CVAR_CLIENT, "r_shadow_projectdistance", "0", "how far to cast shadows"};
158 cvar_t r_shadow_frontsidecasting = {CVAR_CLIENT, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
159 cvar_t r_shadow_realtime_dlight = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
160 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
161 cvar_t r_shadow_realtime_dlight_svbspculling = {CVAR_CLIENT, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
162 cvar_t r_shadow_realtime_dlight_portalculling = {CVAR_CLIENT, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
163 cvar_t r_shadow_realtime_world = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
164 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {CVAR_CLIENT, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
165 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
166 cvar_t r_shadow_realtime_world_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
167 cvar_t r_shadow_realtime_world_compile = {CVAR_CLIENT, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
168 cvar_t r_shadow_realtime_world_compileshadow = {CVAR_CLIENT, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
169 cvar_t r_shadow_realtime_world_compilesvbsp = {CVAR_CLIENT, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
170 cvar_t r_shadow_realtime_world_compileportalculling = {CVAR_CLIENT, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
171 cvar_t r_shadow_scissor = {CVAR_CLIENT, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
172 cvar_t r_shadow_shadowmapping = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
173 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
174 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
175 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
176 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
177 cvar_t r_shadow_shadowmapping_minsize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
178 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
179 cvar_t r_shadow_shadowmapping_texturesize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
180 cvar_t r_shadow_shadowmapping_precision = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
181 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
182 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
183 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
184 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
185 cvar_t r_shadow_shadowmapping_bias = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
186 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
187 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
188 cvar_t r_shadow_sortsurfaces = {CVAR_CLIENT, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
189 cvar_t r_shadow_culllights_pvs = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
190 cvar_t r_shadow_culllights_trace = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
191 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
192 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
193 cvar_t r_shadow_culllights_trace_expand = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
194 cvar_t r_shadow_culllights_trace_pad = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_pad", "8", "accept traces that hit within this many units of the light bounds"};
195 cvar_t r_shadow_culllights_trace_samples = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
196 cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"};
197 cvar_t r_shadow_culllights_trace_delay = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
198 cvar_t r_shadow_bouncegrid = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
199 cvar_t r_shadow_bouncegrid_blur = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
200 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color"};
201 cvar_t r_shadow_bouncegrid_dynamic_culllightpaths = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_culllightpaths", "0", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
202 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "1", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
203 cvar_t r_shadow_bouncegrid_dynamic_dlightparticlemultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_dlightparticlemultiplier", "1", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
204 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
205 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1)"};
206 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0)"};
207 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxphotons", "25000", "upper bound on photons to shoot per update, divided proportionately between lights - normally the number of photons is calculated by energyperphoton"};
208 cvar_t r_shadow_bouncegrid_dynamic_quality = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_quality", "1", "amount of photons that should be fired (this is multiplied by spacing ^ 2 to make it adaptive with spacing changes)"};
209 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
210 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
211 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
212 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
213 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
214 cvar_t r_shadow_bouncegrid_floatcolors = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_floatcolors", "1", "upload texture as RGBA16F (or RGBA32F when set to 2) rather than RGBA8 format - this gives more dynamic range and accuracy"};
215 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
216 cvar_t r_shadow_bouncegrid_intensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
217 cvar_t r_shadow_bouncegrid_lightpathsize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize", "64", "radius (in game units) of the light path for accumulation of light in the bouncegrid texture"};
218 cvar_t r_shadow_bouncegrid_normalizevectors = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)"};
219 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "4", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
220 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
221 cvar_t r_shadow_bouncegrid_rng_seed = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_rng_seed", "0", "0+ = use this number as RNG seed, -1 = use time instead for disco-like craziness in dynamic mode"};
222 cvar_t r_shadow_bouncegrid_rng_type = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)"};
223 cvar_t r_shadow_bouncegrid_static = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
224 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color"};
225 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
226 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
227 cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
228 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
229 cvar_t r_shadow_bouncegrid_static_quality = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_quality", "16", "amount of photons that should be fired (this is multiplied by spacing ^ 2 to make it adaptive with spacing changes)"};
230 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
231 cvar_t r_shadow_bouncegrid_subsamples = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_subsamples", "1", "when generating the texture, sample this many points along each dimension (multisampling uses more compute but not more memory bandwidth)"};
232 cvar_t r_shadow_bouncegrid_threaded = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_threaded", "1", "enables use of taskqueue_maxthreads to perform the traces and slice rendering of bouncegrid"};
233 cvar_t r_coronas = {CVAR_CLIENT | CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
234 cvar_t r_coronas_occlusionsizescale = {CVAR_CLIENT | CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
235 cvar_t r_coronas_occlusionquery = {CVAR_CLIENT | CVAR_SAVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"};
236 cvar_t gl_flashblend = {CVAR_CLIENT | CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
237 cvar_t r_editlights = {CVAR_CLIENT, "r_editlights", "0", "enables .rtlights file editing mode"};
238 cvar_t r_editlights_cursordistance = {CVAR_CLIENT, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
239 cvar_t r_editlights_cursorpushback = {CVAR_CLIENT, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
240 cvar_t r_editlights_cursorpushoff = {CVAR_CLIENT, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
241 cvar_t r_editlights_cursorgrid = {CVAR_CLIENT, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
242 cvar_t r_editlights_quakelightsizescale = {CVAR_CLIENT | CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
243 cvar_t r_editlights_drawproperties = {CVAR_CLIENT, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
244 cvar_t r_editlights_current_origin = {CVAR_CLIENT, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
245 cvar_t r_editlights_current_angles = {CVAR_CLIENT, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
246 cvar_t r_editlights_current_color = {CVAR_CLIENT, "r_editlights_current_color", "1 1 1", "color of selected light"};
247 cvar_t r_editlights_current_radius = {CVAR_CLIENT, "r_editlights_current_radius", "0", "radius of selected light"};
248 cvar_t r_editlights_current_corona = {CVAR_CLIENT, "r_editlights_current_corona", "0", "corona intensity of selected light"};
249 cvar_t r_editlights_current_coronasize = {CVAR_CLIENT, "r_editlights_current_coronasize", "0", "corona size of selected light"};
250 cvar_t r_editlights_current_style = {CVAR_CLIENT, "r_editlights_current_style", "0", "style of selected light"};
251 cvar_t r_editlights_current_shadows = {CVAR_CLIENT, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
252 cvar_t r_editlights_current_cubemap = {CVAR_CLIENT, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
253 cvar_t r_editlights_current_ambient = {CVAR_CLIENT, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
254 cvar_t r_editlights_current_diffuse = {CVAR_CLIENT, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
255 cvar_t r_editlights_current_specular = {CVAR_CLIENT, "r_editlights_current_specular", "1", "specular intensity of selected light"};
256 cvar_t r_editlights_current_normalmode = {CVAR_CLIENT, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
257 cvar_t r_editlights_current_realtimemode = {CVAR_CLIENT, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
259 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
261 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
262 #define ATTENTABLESIZE 256
263 // 1D gradient, 2D circle and 3D sphere attenuation textures
264 #define ATTEN1DSIZE 32
265 #define ATTEN2DSIZE 64
266 #define ATTEN3DSIZE 32
268 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
269 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
270 static float r_shadow_attentable[ATTENTABLESIZE+1];
272 rtlight_t *r_shadow_compilingrtlight;
273 static memexpandablearray_t r_shadow_worldlightsarray;
274 dlight_t *r_shadow_selectedlight;
275 dlight_t r_shadow_bufferlight;
276 vec3_t r_editlights_cursorlocation;
277 qboolean r_editlights_lockcursor;
279 extern int con_vislines;
281 void R_Shadow_UncompileWorldLights(void);
282 void R_Shadow_ClearWorldLights(void);
283 void R_Shadow_SaveWorldLights(void);
284 void R_Shadow_LoadWorldLights(void);
285 void R_Shadow_LoadLightsFile(void);
286 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
287 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd);
288 static void R_Shadow_MakeTextures(void);
290 #define EDLIGHTSPRSIZE 8
291 skinframe_t *r_editlights_sprcursor;
292 skinframe_t *r_editlights_sprlight;
293 skinframe_t *r_editlights_sprnoshadowlight;
294 skinframe_t *r_editlights_sprcubemaplight;
295 skinframe_t *r_editlights_sprcubemapnoshadowlight;
296 skinframe_t *r_editlights_sprselection;
298 static void R_Shadow_DrawModelShadowMaps(void);
299 static void R_Shadow_MakeShadowMap(int texturesize);
300 static void R_Shadow_MakeVSDCT(void);
301 static void R_Shadow_SetShadowMode(void)
303 r_shadow_shadowmode_shadowmapping = r_shadow_shadowmapping.integer;
304 r_shadow_shadowmode_deferred = r_shadow_deferred.integer;
305 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
306 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
307 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
308 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
309 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
310 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
311 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
312 r_shadow_shadowmapsampler = false;
313 r_shadow_shadowmappcf = 0;
314 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
315 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_DISABLED;
316 if (r_shadow_shadowmode_shadowmapping || r_shadow_shadowmode_deferred)
318 switch (vid.renderpath)
320 case RENDERPATH_GL32:
321 if (r_shadow_shadowmapfilterquality < 0)
323 if (!r_fb.usedepthtextures)
324 r_shadow_shadowmappcf = 1;
325 else if ((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
327 r_shadow_shadowmapsampler = true;
328 r_shadow_shadowmappcf = 1;
330 else if (vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
331 r_shadow_shadowmappcf = 1;
332 else if ((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
333 r_shadow_shadowmappcf = 1;
335 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
339 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
340 switch (r_shadow_shadowmapfilterquality)
345 r_shadow_shadowmappcf = 1;
348 r_shadow_shadowmappcf = 1;
351 r_shadow_shadowmappcf = 2;
355 if (!r_fb.usedepthtextures)
356 r_shadow_shadowmapsampler = false;
357 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
359 case RENDERPATH_GLES2:
360 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
365 switch (r_shadow_shadowmode)
367 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
368 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
370 case R_SHADOW_SHADOWMODE_DISABLED:
374 if(R_CompileShader_CheckStaticParms())
375 R_GLSL_Restart_f(&cmd_client);
378 qboolean R_Shadow_ShadowMappingEnabled(void)
380 switch (r_shadow_shadowmode)
382 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
384 case R_SHADOW_SHADOWMODE_DISABLED:
390 static void R_Shadow_FreeShadowMaps(void)
392 R_Shadow_UncompileWorldLights();
394 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
396 R_Shadow_SetShadowMode();
398 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
402 if (r_shadow_shadowmap2ddepthtexture)
403 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
404 r_shadow_shadowmap2ddepthtexture = NULL;
406 if (r_shadow_shadowmap2ddepthbuffer)
407 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
408 r_shadow_shadowmap2ddepthbuffer = NULL;
410 if (r_shadow_shadowmapvsdcttexture)
411 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
412 r_shadow_shadowmapvsdcttexture = NULL;
416 static void r_shadow_start(void)
418 // allocate vertex processing arrays
419 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
420 r_shadow_attenuationgradienttexture = NULL;
421 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_DISABLED;
422 r_shadow_shadowmap2ddepthtexture = NULL;
423 r_shadow_shadowmap2ddepthbuffer = NULL;
424 r_shadow_shadowmapvsdcttexture = NULL;
425 r_shadow_shadowmapmaxsize = 0;
426 r_shadow_shadowmaptexturesize = 0;
427 r_shadow_shadowmapfilterquality = -1;
428 r_shadow_shadowmapdepthbits = 0;
429 r_shadow_shadowmapvsdct = false;
430 r_shadow_shadowmapsampler = false;
431 r_shadow_shadowmappcf = 0;
434 R_Shadow_FreeShadowMaps();
436 r_shadow_texturepool = NULL;
437 r_shadow_filters_texturepool = NULL;
438 R_Shadow_MakeTextures();
439 r_shadow_scenemaxlights = 0;
440 r_shadow_scenenumlights = 0;
441 r_shadow_scenelightlist = NULL;
442 maxshadowtriangles = 0;
443 shadowelements = NULL;
444 maxshadowvertices = 0;
445 shadowvertex3f = NULL;
453 shadowmarklist = NULL;
458 shadowsideslist = NULL;
459 r_shadow_buffer_numleafpvsbytes = 0;
460 r_shadow_buffer_visitingleafpvs = NULL;
461 r_shadow_buffer_leafpvs = NULL;
462 r_shadow_buffer_leaflist = NULL;
463 r_shadow_buffer_numsurfacepvsbytes = 0;
464 r_shadow_buffer_surfacepvs = NULL;
465 r_shadow_buffer_surfacelist = NULL;
466 r_shadow_buffer_surfacesides = NULL;
467 r_shadow_buffer_numshadowtrispvsbytes = 0;
468 r_shadow_buffer_shadowtrispvs = NULL;
469 r_shadow_buffer_numlighttrispvsbytes = 0;
470 r_shadow_buffer_lighttrispvs = NULL;
472 r_shadow_usingdeferredprepass = false;
473 r_shadow_prepass_width = r_shadow_prepass_height = 0;
475 // determine renderpath specific capabilities, we don't need to figure
476 // these out per frame...
477 switch(vid.renderpath)
479 case RENDERPATH_GL32:
480 r_shadow_bouncegrid_state.allowdirectionalshading = true;
481 r_shadow_bouncegrid_state.capable = true;
483 case RENDERPATH_GLES2:
484 // for performance reasons, do not use directional shading on GLES devices
485 r_shadow_bouncegrid_state.capable = true;
490 static void R_Shadow_FreeDeferred(void);
491 static void r_shadow_shutdown(void)
495 R_Shadow_FreeShadowMaps();
497 r_shadow_usingdeferredprepass = false;
498 if (r_shadow_prepass_width)
499 R_Shadow_FreeDeferred();
500 r_shadow_prepass_width = r_shadow_prepass_height = 0;
503 r_shadow_scenemaxlights = 0;
504 r_shadow_scenenumlights = 0;
505 if (r_shadow_scenelightlist)
506 Mem_Free(r_shadow_scenelightlist);
507 r_shadow_scenelightlist = NULL;
508 r_shadow_bouncegrid_state.highpixels = NULL;
509 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
510 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
511 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
512 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
513 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
514 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
515 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
516 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
517 r_shadow_attenuationgradienttexture = NULL;
518 R_FreeTexturePool(&r_shadow_texturepool);
519 R_FreeTexturePool(&r_shadow_filters_texturepool);
520 maxshadowtriangles = 0;
522 Mem_Free(shadowelements);
523 shadowelements = NULL;
525 Mem_Free(shadowvertex3f);
526 shadowvertex3f = NULL;
529 Mem_Free(vertexupdate);
532 Mem_Free(vertexremap);
538 Mem_Free(shadowmark);
541 Mem_Free(shadowmarklist);
542 shadowmarklist = NULL;
547 Mem_Free(shadowsides);
550 Mem_Free(shadowsideslist);
551 shadowsideslist = NULL;
552 r_shadow_buffer_numleafpvsbytes = 0;
553 if (r_shadow_buffer_visitingleafpvs)
554 Mem_Free(r_shadow_buffer_visitingleafpvs);
555 r_shadow_buffer_visitingleafpvs = NULL;
556 if (r_shadow_buffer_leafpvs)
557 Mem_Free(r_shadow_buffer_leafpvs);
558 r_shadow_buffer_leafpvs = NULL;
559 if (r_shadow_buffer_leaflist)
560 Mem_Free(r_shadow_buffer_leaflist);
561 r_shadow_buffer_leaflist = NULL;
562 r_shadow_buffer_numsurfacepvsbytes = 0;
563 if (r_shadow_buffer_surfacepvs)
564 Mem_Free(r_shadow_buffer_surfacepvs);
565 r_shadow_buffer_surfacepvs = NULL;
566 if (r_shadow_buffer_surfacelist)
567 Mem_Free(r_shadow_buffer_surfacelist);
568 r_shadow_buffer_surfacelist = NULL;
569 if (r_shadow_buffer_surfacesides)
570 Mem_Free(r_shadow_buffer_surfacesides);
571 r_shadow_buffer_surfacesides = NULL;
572 r_shadow_buffer_numshadowtrispvsbytes = 0;
573 if (r_shadow_buffer_shadowtrispvs)
574 Mem_Free(r_shadow_buffer_shadowtrispvs);
575 r_shadow_buffer_numlighttrispvsbytes = 0;
576 if (r_shadow_buffer_lighttrispvs)
577 Mem_Free(r_shadow_buffer_lighttrispvs);
580 static void r_shadow_newmap(void)
582 r_shadow_bouncegrid_state.highpixels = NULL;
583 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
584 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
585 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
586 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
587 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
588 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
589 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
591 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
592 if (r_shadow_lightcorona) { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
593 if (r_editlights_sprcursor) { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
594 if (r_editlights_sprlight) { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
595 if (r_editlights_sprnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
596 if (r_editlights_sprcubemaplight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
597 if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
598 if (r_editlights_sprselection) { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
599 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
600 R_Shadow_EditLights_Reload_f(&cmd_client);
603 void R_Shadow_Init(void)
605 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
606 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
607 Cvar_RegisterVariable(&r_shadow_usebihculling);
608 Cvar_RegisterVariable(&r_shadow_usenormalmap);
609 Cvar_RegisterVariable(&r_shadow_debuglight);
610 Cvar_RegisterVariable(&r_shadow_deferred);
611 Cvar_RegisterVariable(&r_shadow_gloss);
612 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
613 Cvar_RegisterVariable(&r_shadow_glossintensity);
614 Cvar_RegisterVariable(&r_shadow_glossexponent);
615 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
616 Cvar_RegisterVariable(&r_shadow_glossexact);
617 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
618 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
619 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
620 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
621 Cvar_RegisterVariable(&r_shadow_projectdistance);
622 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
623 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
624 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
625 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
626 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
627 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
628 Cvar_RegisterVariable(&r_shadow_realtime_world);
629 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
630 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
631 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
632 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
633 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
634 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
635 Cvar_RegisterVariable(&r_shadow_scissor);
636 Cvar_RegisterVariable(&r_shadow_shadowmapping);
637 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
638 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
639 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
640 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
641 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
642 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
643 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
644 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
645 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
646 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
647 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
648 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
649 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
650 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
651 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
652 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
653 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
654 Cvar_RegisterVariable(&r_shadow_culllights_trace);
655 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
656 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
657 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
658 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
659 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
660 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
661 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
662 Cvar_RegisterVariable(&r_shadow_bouncegrid);
663 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
664 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
665 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
666 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
667 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
668 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
669 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
670 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
671 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
672 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
673 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
674 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
675 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
676 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
677 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
678 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
679 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
680 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
681 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
682 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
683 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
684 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
685 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
686 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
687 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
688 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
689 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
690 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
691 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
692 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
693 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
694 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
695 Cvar_RegisterVariable(&r_shadow_bouncegrid_subsamples);
696 Cvar_RegisterVariable(&r_shadow_bouncegrid_threaded);
697 Cvar_RegisterVariable(&r_coronas);
698 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
699 Cvar_RegisterVariable(&r_coronas_occlusionquery);
700 Cvar_RegisterVariable(&gl_flashblend);
701 R_Shadow_EditLights_Init();
702 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
703 r_shadow_scenemaxlights = 0;
704 r_shadow_scenenumlights = 0;
705 r_shadow_scenelightlist = NULL;
706 maxshadowtriangles = 0;
707 shadowelements = NULL;
708 maxshadowvertices = 0;
709 shadowvertex3f = NULL;
717 shadowmarklist = NULL;
722 shadowsideslist = NULL;
723 r_shadow_buffer_numleafpvsbytes = 0;
724 r_shadow_buffer_visitingleafpvs = NULL;
725 r_shadow_buffer_leafpvs = NULL;
726 r_shadow_buffer_leaflist = NULL;
727 r_shadow_buffer_numsurfacepvsbytes = 0;
728 r_shadow_buffer_surfacepvs = NULL;
729 r_shadow_buffer_surfacelist = NULL;
730 r_shadow_buffer_surfacesides = NULL;
731 r_shadow_buffer_shadowtrispvs = NULL;
732 r_shadow_buffer_lighttrispvs = NULL;
733 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
736 matrix4x4_t matrix_attenuationxyz =
739 {0.5, 0.0, 0.0, 0.5},
740 {0.0, 0.5, 0.0, 0.5},
741 {0.0, 0.0, 0.5, 0.5},
746 matrix4x4_t matrix_attenuationz =
749 {0.0, 0.0, 0.5, 0.5},
750 {0.0, 0.0, 0.0, 0.5},
751 {0.0, 0.0, 0.0, 0.5},
756 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
758 numvertices = ((numvertices + 255) & ~255) * vertscale;
759 numtriangles = ((numtriangles + 255) & ~255) * triscale;
760 // make sure shadowelements is big enough for this volume
761 if (maxshadowtriangles < numtriangles)
763 maxshadowtriangles = numtriangles;
765 Mem_Free(shadowelements);
766 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
768 // make sure shadowvertex3f is big enough for this volume
769 if (maxshadowvertices < numvertices)
771 maxshadowvertices = numvertices;
773 Mem_Free(shadowvertex3f);
774 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
778 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
780 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
781 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
782 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
783 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
784 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
786 if (r_shadow_buffer_visitingleafpvs)
787 Mem_Free(r_shadow_buffer_visitingleafpvs);
788 if (r_shadow_buffer_leafpvs)
789 Mem_Free(r_shadow_buffer_leafpvs);
790 if (r_shadow_buffer_leaflist)
791 Mem_Free(r_shadow_buffer_leaflist);
792 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
793 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
794 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
795 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
797 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
799 if (r_shadow_buffer_surfacepvs)
800 Mem_Free(r_shadow_buffer_surfacepvs);
801 if (r_shadow_buffer_surfacelist)
802 Mem_Free(r_shadow_buffer_surfacelist);
803 if (r_shadow_buffer_surfacesides)
804 Mem_Free(r_shadow_buffer_surfacesides);
805 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
806 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
807 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
808 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
810 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
812 if (r_shadow_buffer_shadowtrispvs)
813 Mem_Free(r_shadow_buffer_shadowtrispvs);
814 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
815 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
817 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
819 if (r_shadow_buffer_lighttrispvs)
820 Mem_Free(r_shadow_buffer_lighttrispvs);
821 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
822 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
826 void R_Shadow_PrepareShadowMark(int numtris)
828 // make sure shadowmark is big enough for this volume
829 if (maxshadowmark < numtris)
831 maxshadowmark = numtris;
833 Mem_Free(shadowmark);
835 Mem_Free(shadowmarklist);
836 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
837 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
841 // if shadowmarkcount wrapped we clear the array and adjust accordingly
842 if (shadowmarkcount == 0)
845 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
850 void R_Shadow_PrepareShadowSides(int numtris)
852 if (maxshadowsides < numtris)
854 maxshadowsides = numtris;
856 Mem_Free(shadowsides);
858 Mem_Free(shadowsideslist);
859 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
860 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
865 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
867 // p1, p2, p3 are in the cubemap's local coordinate system
868 // bias = border/(size - border)
871 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
872 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
873 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
874 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
876 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
877 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
878 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
879 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
881 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
882 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
883 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
885 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
886 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
887 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
888 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
890 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
891 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
892 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
893 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
895 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
896 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
897 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
899 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
900 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
901 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
902 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
904 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
905 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
906 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
907 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
909 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
910 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
911 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
916 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
918 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
919 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
922 VectorSubtract(maxs, mins, radius);
923 VectorScale(radius, 0.5f, radius);
924 VectorAdd(mins, radius, center);
925 Matrix4x4_Transform(worldtolight, center, lightcenter);
926 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
927 VectorSubtract(lightcenter, lightradius, pmin);
928 VectorAdd(lightcenter, lightradius, pmax);
930 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
931 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
932 if(ap1 > bias*an1 && ap2 > bias*an2)
934 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
935 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
936 if(an1 > bias*ap1 && an2 > bias*ap2)
938 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
939 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
941 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
942 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
943 if(ap1 > bias*an1 && ap2 > bias*an2)
945 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
946 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
947 if(an1 > bias*ap1 && an2 > bias*ap2)
949 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
950 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
952 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
953 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
954 if(ap1 > bias*an1 && ap2 > bias*an2)
956 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
957 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
958 if(an1 > bias*ap1 && an2 > bias*ap2)
960 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
961 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
966 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
968 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
970 // p is in the cubemap's local coordinate system
971 // bias = border/(size - border)
972 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
973 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
974 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
976 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
977 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
978 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
979 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
980 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
981 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
985 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
989 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
990 float scale = (size - 2*border)/size, len;
991 float bias = border / (float)(size - border), dp, dn, ap, an;
992 // check if cone enclosing side would cross frustum plane
993 scale = 2 / (scale*scale + 2);
994 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
995 for (i = 0;i < 5;i++)
997 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
999 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1000 len = scale*VectorLength2(n);
1001 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1002 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1003 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1005 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1007 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1008 len = scale*VectorLength2(n);
1009 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1010 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1011 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1013 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1014 // check if frustum corners/origin cross plane sides
1016 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1017 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1018 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1019 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1020 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1021 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1022 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1023 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1024 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1025 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1026 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1027 for (i = 0;i < 4;i++)
1029 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1030 VectorSubtract(n, p, n);
1031 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1032 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1033 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1034 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1035 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1036 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1037 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1038 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1039 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1042 // finite version, assumes corners are a finite distance from origin dependent on far plane
1043 for (i = 0;i < 5;i++)
1045 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1046 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1047 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1048 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1049 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1050 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1051 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1052 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1053 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1054 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1057 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1060 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)
1068 int mask, surfacemask = 0;
1069 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1071 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1072 tend = firsttriangle + numtris;
1073 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1075 // surface box entirely inside light box, no box cull
1076 if (projectdirection)
1078 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1080 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1081 TriangleNormal(v[0], v[1], v[2], normal);
1082 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1084 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1085 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1086 surfacemask |= mask;
1089 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;
1090 shadowsides[numshadowsides] = mask;
1091 shadowsideslist[numshadowsides++] = t;
1098 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1100 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1101 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1103 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1104 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1105 surfacemask |= mask;
1108 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;
1109 shadowsides[numshadowsides] = mask;
1110 shadowsideslist[numshadowsides++] = t;
1118 // surface box not entirely inside light box, cull each triangle
1119 if (projectdirection)
1121 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1123 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1124 TriangleNormal(v[0], v[1], v[2], normal);
1125 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1126 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1128 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1129 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1130 surfacemask |= mask;
1133 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;
1134 shadowsides[numshadowsides] = mask;
1135 shadowsideslist[numshadowsides++] = t;
1142 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1144 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1145 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1146 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1148 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1149 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1150 surfacemask |= mask;
1153 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;
1154 shadowsides[numshadowsides] = mask;
1155 shadowsideslist[numshadowsides++] = t;
1164 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)
1166 int i, j, outtriangles = 0;
1167 int *outelement3i[6];
1168 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1170 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1171 // make sure shadowelements is big enough for this mesh
1172 if (maxshadowtriangles < outtriangles)
1173 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1175 // compute the offset and size of the separate index lists for each cubemap side
1177 for (i = 0;i < 6;i++)
1179 outelement3i[i] = shadowelements + outtriangles * 3;
1180 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1181 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1182 outtriangles += sidetotals[i];
1185 // gather up the (sparse) triangles into separate index lists for each cubemap side
1186 for (i = 0;i < numsidetris;i++)
1188 const int *element = elements + sidetris[i] * 3;
1189 for (j = 0;j < 6;j++)
1191 if (sides[i] & (1 << j))
1193 outelement3i[j][0] = element[0];
1194 outelement3i[j][1] = element[1];
1195 outelement3i[j][2] = element[2];
1196 outelement3i[j] += 3;
1201 Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1204 static void R_Shadow_MakeTextures_MakeCorona(void)
1208 unsigned char pixels[32][32][4];
1209 for (y = 0;y < 32;y++)
1211 dy = (y - 15.5f) * (1.0f / 16.0f);
1212 for (x = 0;x < 32;x++)
1214 dx = (x - 15.5f) * (1.0f / 16.0f);
1215 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1216 a = bound(0, a, 255);
1217 pixels[y][x][0] = a;
1218 pixels[y][x][1] = a;
1219 pixels[y][x][2] = a;
1220 pixels[y][x][3] = 255;
1223 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1226 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1228 float dist = sqrt(x*x+y*y+z*z);
1229 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1230 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1231 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1234 static void R_Shadow_MakeTextures(void)
1237 float intensity, dist;
1239 R_Shadow_FreeShadowMaps();
1240 R_FreeTexturePool(&r_shadow_texturepool);
1241 r_shadow_texturepool = R_AllocTexturePool();
1242 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1243 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1244 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1245 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1246 for (x = 0;x <= ATTENTABLESIZE;x++)
1248 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1249 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1250 r_shadow_attentable[x] = bound(0, intensity, 1);
1252 // 1D gradient texture
1253 for (x = 0;x < ATTEN1DSIZE;x++)
1254 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1255 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1258 R_Shadow_MakeTextures_MakeCorona();
1260 // Editor light sprites
1261 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1278 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1279 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1296 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1297 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1314 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1315 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1332 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1333 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1350 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1351 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1368 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1371 void R_Shadow_RenderMode_Begin(void)
1378 if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1379 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1380 R_Shadow_MakeTextures();
1383 R_Mesh_ResetTextureState();
1384 GL_BlendFunc(GL_ONE, GL_ZERO);
1385 GL_DepthRange(0, 1);
1386 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1388 GL_DepthMask(false);
1389 GL_Color(0, 0, 0, 1);
1390 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1392 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1393 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1397 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1398 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1399 r_shadow_drawbuffer = drawbuffer;
1400 r_shadow_readbuffer = readbuffer;
1402 r_shadow_cullface_front = r_refdef.view.cullface_front;
1403 r_shadow_cullface_back = r_refdef.view.cullface_back;
1406 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1408 rsurface.rtlight = rtlight;
1411 void R_Shadow_RenderMode_Reset(void)
1413 R_Mesh_ResetTextureState();
1414 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1415 R_SetViewport(&r_refdef.view.viewport);
1416 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1417 GL_DepthRange(0, 1);
1419 GL_DepthMask(false);
1420 GL_DepthFunc(GL_LEQUAL);
1421 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1422 r_refdef.view.cullface_front = r_shadow_cullface_front;
1423 r_refdef.view.cullface_back = r_shadow_cullface_back;
1424 GL_CullFace(r_refdef.view.cullface_back);
1425 GL_Color(1, 1, 1, 1);
1426 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1427 GL_BlendFunc(GL_ONE, GL_ZERO);
1428 R_SetupShader_Generic_NoTexture(false, false);
1429 r_shadow_usingshadowmap2d = false;
1432 void R_Shadow_ClearStencil(void)
1434 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1435 r_refdef.stats[r_stat_lights_clears]++;
1438 static void R_Shadow_MakeVSDCT(void)
1440 // maps to a 2x3 texture rectangle with normalized coordinates
1445 // stores abs(dir.xy), offset.xy/2.5
1446 unsigned char data[4*6] =
1448 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1449 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1450 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1451 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1452 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1453 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1455 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1458 static void R_Shadow_MakeShadowMap(int texturesize)
1460 switch (r_shadow_shadowmode)
1462 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1463 if (r_shadow_shadowmap2ddepthtexture) return;
1464 if (r_fb.usedepthtextures)
1466 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);
1467 r_shadow_shadowmap2ddepthbuffer = NULL;
1468 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1472 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1473 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1474 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1477 case R_SHADOW_SHADOWMODE_DISABLED:
1482 void R_Shadow_ClearShadowMapTexture(void)
1484 r_viewport_t viewport;
1485 float clearcolor[4];
1487 // if they don't exist, create our textures now
1488 if (!r_shadow_shadowmap2ddepthtexture)
1489 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1490 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1491 R_Shadow_MakeVSDCT();
1493 // we're setting up to render shadowmaps, so change rendermode
1494 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1496 R_Mesh_ResetTextureState();
1497 R_Shadow_RenderMode_Reset();
1498 if (r_shadow_shadowmap2ddepthbuffer)
1499 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1501 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1502 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1503 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1507 // we have to set a viewport to clear anything in some renderpaths (D3D)
1508 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1509 R_SetViewport(&viewport);
1510 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1511 if (r_shadow_shadowmap2ddepthbuffer)
1512 GL_ColorMask(1, 1, 1, 1);
1514 GL_ColorMask(0, 0, 0, 0);
1515 switch (vid.renderpath)
1517 case RENDERPATH_GL32:
1518 case RENDERPATH_GLES2:
1519 GL_CullFace(r_refdef.view.cullface_back);
1522 Vector4Set(clearcolor, 1, 1, 1, 1);
1523 if (r_shadow_shadowmap2ddepthbuffer)
1524 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1526 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1529 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1531 int size = rsurface.rtlight->shadowmapatlassidesize;
1532 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1533 float farclip = 1.0f;
1534 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1535 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1536 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1537 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1538 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1539 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1540 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1541 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1542 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1543 if (r_shadow_shadowmap2ddepthbuffer)
1545 // completely different meaning than in depthtexture approach
1546 r_shadow_lightshadowmap_parameters[1] = 0;
1547 r_shadow_lightshadowmap_parameters[3] = -bias;
1551 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1553 float nearclip, farclip;
1554 r_viewport_t viewport;
1557 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1559 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1561 R_Mesh_ResetTextureState();
1562 R_Shadow_RenderMode_Reset();
1563 if (r_shadow_shadowmap2ddepthbuffer)
1564 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1566 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1567 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1568 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1573 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1576 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1577 R_SetViewport(&viewport);
1578 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1579 flipped = (side & 1) ^ (side >> 2);
1580 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1581 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1583 if (r_shadow_shadowmap2ddepthbuffer)
1584 GL_ColorMask(1,1,1,1);
1586 GL_ColorMask(0,0,0,0);
1587 switch(vid.renderpath)
1589 case RENDERPATH_GL32:
1590 case RENDERPATH_GLES2:
1591 GL_CullFace(r_refdef.view.cullface_back);
1595 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1596 r_shadow_shadowmapside = side;
1599 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1601 R_Mesh_ResetTextureState();
1604 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1605 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1606 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1607 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1610 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1611 R_Shadow_RenderMode_Reset();
1612 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1614 GL_DepthFunc(GL_EQUAL);
1615 // do global setup needed for the chosen lighting mode
1616 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1617 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1618 r_shadow_usingshadowmap2d = shadowmapping;
1619 r_shadow_rendermode = r_shadow_lightingrendermode;
1622 static const unsigned short bboxelements[36] =
1632 static const float bboxpoints[8][3] =
1644 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1647 float vertex3f[8*3];
1648 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1649 // do global setup needed for the chosen lighting mode
1650 R_Shadow_RenderMode_Reset();
1651 r_shadow_rendermode = r_shadow_lightingrendermode;
1652 R_EntityMatrix(&identitymatrix);
1653 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1654 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1655 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1657 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1659 r_shadow_usingshadowmap2d = shadowmapping;
1661 // render the lighting
1662 R_SetupShader_DeferredLight(rsurface.rtlight);
1663 for (i = 0;i < 8;i++)
1664 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1665 GL_ColorMask(1,1,1,1);
1666 GL_DepthMask(false);
1667 GL_DepthRange(0, 1);
1668 GL_PolygonOffset(0, 0);
1670 GL_DepthFunc(GL_GREATER);
1671 GL_CullFace(r_refdef.view.cullface_back);
1672 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1673 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1676 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1678 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1685 // see if there are really any lights to render...
1686 if (enable && r_shadow_bouncegrid_static.integer)
1689 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1690 for (lightindex = 0;lightindex < range;lightindex++)
1692 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1693 if (!light || !(light->flags & flag))
1695 rtlight = &light->rtlight;
1696 // when static, we skip styled lights because they tend to change...
1697 if (rtlight->style > 0)
1699 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1700 if (!VectorLength2(lightcolor))
1710 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1712 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1713 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1714 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1715 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1717 // prevent any garbage in alignment padded areas as we'll be using memcmp
1718 memset(settings, 0, sizeof(*settings));
1720 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1721 settings->staticmode = s;
1722 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1723 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1724 settings->lightpathsize = bound(0.0f, r_shadow_bouncegrid_lightpathsize.value, 1024.0f);
1725 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1726 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1727 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1728 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1729 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1730 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1731 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1732 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) / 65536.0f;
1733 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1734 settings->energyperphoton = 4096.0f / quality;
1735 settings->spacing[0] = spacing;
1736 settings->spacing[1] = spacing;
1737 settings->spacing[2] = spacing;
1738 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1739 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1740 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1741 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1742 settings->subsamples = bound(1, r_shadow_bouncegrid_subsamples.integer, 4);
1744 // bound the values for sanity
1745 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1746 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1747 settings->maxbounce = bound(0, settings->maxbounce, 16);
1748 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1749 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1750 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1753 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1764 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1766 // get the spacing values
1767 spacing[0] = settings->spacing[0];
1768 spacing[1] = settings->spacing[1];
1769 spacing[2] = settings->spacing[2];
1770 ispacing[0] = 1.0f / spacing[0];
1771 ispacing[1] = 1.0f / spacing[1];
1772 ispacing[2] = 1.0f / spacing[2];
1774 // calculate texture size enclosing entire world bounds at the spacing
1775 if (r_refdef.scene.worldmodel)
1779 qboolean bounds_set = false;
1783 // calculate bounds enclosing world lights as they should be noticably tighter
1784 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1785 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1786 for (lightindex = 0;lightindex < range;lightindex++)
1788 const vec_t *rtlmins, *rtlmaxs;
1790 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1794 rtlight = &light->rtlight;
1795 rtlmins = rtlight->cullmins;
1796 rtlmaxs = rtlight->cullmaxs;
1800 VectorCopy(rtlmins, mins);
1801 VectorCopy(rtlmaxs, maxs);
1806 mins[0] = min(mins[0], rtlmins[0]);
1807 mins[1] = min(mins[1], rtlmins[1]);
1808 mins[2] = min(mins[2], rtlmins[2]);
1809 maxs[0] = max(maxs[0], rtlmaxs[0]);
1810 maxs[1] = max(maxs[1], rtlmaxs[1]);
1811 maxs[2] = max(maxs[2], rtlmaxs[2]);
1815 // limit to no larger than the world bounds
1816 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1817 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1818 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1819 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1820 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1821 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1823 VectorMA(mins, -2.0f, spacing, mins);
1824 VectorMA(maxs, 2.0f, spacing, maxs);
1828 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1829 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1831 VectorSubtract(maxs, mins, size);
1832 // now we can calculate the resolution we want
1833 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1834 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1835 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1836 // figure out the exact texture size (honoring power of 2 if required)
1837 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1838 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1839 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1840 size[0] = spacing[0] * resolution[0];
1841 size[1] = spacing[1] * resolution[1];
1842 size[2] = spacing[2] * resolution[2];
1844 // if dynamic we may or may not want to use the world bounds
1845 // if the dynamic size is smaller than the world bounds, use it instead
1846 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]))
1848 // we know the resolution we want
1849 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1850 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1851 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1852 // now we can calculate the texture size
1853 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1854 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1855 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1856 size[0] = spacing[0] * resolution[0];
1857 size[1] = spacing[1] * resolution[1];
1858 size[2] = spacing[2] * resolution[2];
1859 // center the rendering on the view
1860 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1861 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1862 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1865 // recalculate the maxs in case the resolution was not satisfactory
1866 VectorAdd(mins, size, maxs);
1868 // check if this changed the texture size
1869 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);
1870 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1871 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1872 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1873 VectorCopy(size, r_shadow_bouncegrid_state.size);
1874 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1875 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1876 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1878 // reallocate pixels for this update if needed...
1879 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1880 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1881 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1882 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1883 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1885 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1887 r_shadow_bouncegrid_state.highpixels = NULL;
1889 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1890 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1891 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1892 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1893 if (r_shadow_bouncegrid_state.photons) { Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL; }
1894 if (r_shadow_bouncegrid_state.photons_tasks) { Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL; }
1895 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
1897 r_shadow_bouncegrid_state.numpixels = numpixels;
1900 // update the bouncegrid matrix to put it in the world properly
1901 memset(m, 0, sizeof(m));
1902 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1903 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1904 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1905 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1906 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1907 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1909 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1912 static float R_Shadow_BounceGrid_RefractiveIndexAtPoint(vec3_t point)
1914 // check material at shadoworigin to see what the initial refractive index should be
1915 int hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
1916 int skipsupercontentsmask = 0;
1917 int skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
1918 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);
1919 if (trace.starttexture && (trace.starttexture->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)))
1920 return trace.starttexture->refractive_index;
1921 else if (trace.startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
1922 return 1.333f; // water
1924 return 1.0003f; // air
1927 // enumerate world rtlights and sum the overall amount of light in the world,
1928 // from that we can calculate a scaling factor to fairly distribute photons
1929 // to all the lights
1931 // this modifies rtlight->photoncolor and rtlight->photons
1932 static void R_Shadow_BounceGrid_AssignPhotons_Task(taskqueue_task_t *t)
1934 // get the range of light numbers we'll be looping over:
1935 // range = static lights
1936 // range1 = dynamic lights (optional)
1937 // range2 = range + range1
1938 unsigned int range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1939 unsigned int range1 = r_shadow_bouncegrid_state.settings.staticmode ? 0 : r_refdef.scene.numlights;
1940 unsigned int range2 = range + range1;
1941 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
1943 float normalphotonscaling;
1944 float photonscaling;
1945 float photonintensity;
1946 float photoncount = 0.0f;
1947 float lightintensity;
1953 unsigned int lightindex;
1958 float bounceminimumintensity2;
1959 float startrefractiveindex;
1961 randomseed_t randomseed;
1962 vec3_t baseshotcolor;
1964 normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1965 for (lightindex = 0;lightindex < range2;lightindex++)
1967 if (lightindex < range)
1969 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1972 rtlight = &light->rtlight;
1973 VectorClear(rtlight->bouncegrid_photoncolor);
1974 rtlight->bouncegrid_photons = 0;
1975 rtlight->bouncegrid_hits = 0;
1976 rtlight->bouncegrid_traces = 0;
1977 rtlight->bouncegrid_effectiveradius = 0;
1978 if (!(light->flags & flag))
1980 if (r_shadow_bouncegrid_state.settings.staticmode)
1982 // when static, we skip styled lights because they tend to change...
1983 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
1986 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
1991 rtlight = r_refdef.scene.lights[lightindex - range];
1992 VectorClear(rtlight->bouncegrid_photoncolor);
1993 rtlight->bouncegrid_photons = 0;
1994 rtlight->bouncegrid_hits = 0;
1995 rtlight->bouncegrid_traces = 0;
1996 rtlight->bouncegrid_effectiveradius = 0;
1998 // draw only visible lights (major speedup)
1999 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2000 cullmins[0] = rtlight->shadoworigin[0] - radius;
2001 cullmins[1] = rtlight->shadoworigin[1] - radius;
2002 cullmins[2] = rtlight->shadoworigin[2] - radius;
2003 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2004 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2005 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2006 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2007 if (!r_shadow_bouncegrid_state.settings.staticmode)
2009 // skip if the expanded light box does not touch any visible leafs
2010 if (r_refdef.scene.worldmodel
2011 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2012 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2014 // skip if the expanded light box is not visible to traceline
2015 // note that PrepareLight already did this check but for a smaller box, so we
2016 // end up casting more traces per frame per light when using bouncegrid, which
2017 // is probably fine (and they use the same timer)
2018 if (r_shadow_culllights_trace.integer)
2020 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))
2021 rtlight->trace_timer = realtime;
2022 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2025 // skip if expanded light box is offscreen
2026 if (R_CullBox(cullmins, cullmaxs))
2028 // skip if overall light intensity is zero
2029 if (w * VectorLength2(rtlight->color) == 0.0f)
2032 // a light that does not emit any light before style is applied, can be
2033 // skipped entirely (it may just be a corona)
2034 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2036 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2037 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2038 // skip lights that will emit no photons
2039 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2041 // shoot particles from this light
2042 // use a calculation for the number of particles that will not
2043 // vary with lightstyle, otherwise we get randomized particle
2044 // distribution, the seeded random is only consistent for a
2045 // consistent number of particles on this light...
2046 s = rtlight->radius;
2047 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2048 if (lightindex >= range)
2049 lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2050 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2051 photoncount += rtlight->bouncegrid_photons;
2052 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2053 // if the lightstyle happens to be off right now, we can skip actually
2054 // firing the photons, but we did have to count them in the total.
2055 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2056 // rtlight->bouncegrid_photons = 0;
2058 // the user provided an energyperphoton value which we try to use
2059 // if that results in too many photons to shoot this frame, then we cap it
2060 // which causes photons to appear/disappear from frame to frame, so we don't
2061 // like doing that in the typical case
2062 photonscaling = 1.0f;
2063 photonintensity = 1.0f;
2064 if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2066 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2067 photonintensity = 1.0f / photonscaling;
2070 // modify the lights to reflect our computed scaling
2071 for (lightindex = 0; lightindex < range2; lightindex++)
2073 if (lightindex < range)
2075 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2078 rtlight = &light->rtlight;
2081 rtlight = r_refdef.scene.lights[lightindex - range];
2082 rtlight->bouncegrid_photons *= photonscaling;
2083 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2086 // compute a seed for the unstable random modes
2087 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2088 seed = realtime * 1000.0;
2090 for (lightindex = 0; lightindex < range2; lightindex++)
2092 if (lightindex < range)
2094 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2097 rtlight = &light->rtlight;
2100 rtlight = r_refdef.scene.lights[lightindex - range];
2101 // note that this code used to keep track of residual photons and
2102 // distribute them evenly to achieve exactly a desired photon count,
2103 // but that caused unwanted flickering in dynamic mode
2104 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2105 // skip if we won't be shooting any photons
2106 if (!shootparticles)
2108 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2109 //s = settings.particleintensity / shootparticles;
2110 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2111 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2112 if (VectorLength2(baseshotcolor) <= 0.0f)
2114 r_refdef.stats[r_stat_bouncegrid_lights]++;
2115 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2116 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2117 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2119 // check material at shadoworigin to see what the initial refractive index should be
2120 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2122 // for seeded random we start the RNG with the position of the light
2123 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2131 u.f[0] = rtlight->shadoworigin[0];
2132 u.f[1] = rtlight->shadoworigin[1];
2133 u.f[2] = rtlight->shadoworigin[2];
2135 switch (r_shadow_bouncegrid_state.settings.rng_type)
2139 // we have to shift the seed provided by the user because the result must be odd
2140 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2143 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2148 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2150 r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2151 VectorCopy(baseshotcolor, p->color);
2152 VectorCopy(rtlight->shadoworigin, p->start);
2153 switch (r_shadow_bouncegrid_state.settings.rng_type)
2157 // figure out a random direction for the initial photon to go
2158 VectorLehmerRandom(&randomseed, p->end);
2161 // figure out a random direction for the initial photon to go
2162 VectorCheeseRandom(seed, p->end);
2166 // we want a uniform distribution spherically, not merely within the sphere
2167 if (r_shadow_bouncegrid_state.settings.normalizevectors)
2168 VectorNormalize(p->end);
2170 VectorMA(p->start, radius, p->end, p->end);
2171 p->bounceminimumintensity2 = bounceminimumintensity2;
2172 p->startrefractiveindex = startrefractiveindex;
2180 static void R_Shadow_BounceGrid_Slice(int zi)
2182 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2183 int xi, yi; // pixel increments
2184 float color[32] = { 0 };
2185 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2186 float iradius = 1.0f / radius;
2187 int slicemins[3], slicemaxs[3];
2189 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2190 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2192 int samples = r_shadow_bouncegrid_state.settings.subsamples;
2193 float isamples = 1.0f / samples;
2194 float samplescolorscale = isamples * isamples * isamples;
2196 // we use these a lot, so get a local copy
2197 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2199 for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2201 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2203 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2205 r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2206 float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2208 VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2209 VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2211 pathmins[2] = min(pathstart[2], pathend[2]);
2212 slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2213 pathmaxs[2] = max(pathstart[2], pathend[2]);
2214 slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2216 // skip if the path doesn't touch this slice
2217 if (zi < slicemins[2] || zi >= slicemaxs[2])
2220 pathmins[0] = min(pathstart[0], pathend[0]);
2221 slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2222 slicemins[0] = max(slicemins[0], 1);
2223 pathmaxs[0] = max(pathstart[0], pathend[0]);
2224 slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2225 slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2227 pathmins[1] = min(pathstart[1], pathend[1]);
2228 slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2229 slicemins[1] = max(slicemins[1], 1);
2230 pathmaxs[1] = max(pathstart[1], pathend[1]);
2231 slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2232 slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2234 // skip if the path is out of bounds on X or Y
2235 if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2238 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2239 // accumulate average shotcolor
2240 VectorSubtract(pathend, pathstart, pathdelta);
2241 pathlength2 = VectorLength2(pathdelta);
2242 pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2243 VectorScale(pathdelta, pathilength, pathdir);
2244 // the color is scaled by the number of subsamples
2245 color[0] = path->color[0] * samplescolorscale;
2246 color[1] = path->color[1] * samplescolorscale;
2247 color[2] = path->color[2] * samplescolorscale;
2251 // store bentnormal in case the shader has a use for it,
2252 // bentnormal is an intensity-weighted average of the directions,
2253 // and will be normalized on conversion to texture pixels.
2254 float intensity = VectorLength(color);
2255 color[4] = pathdir[0] * intensity;
2256 color[5] = pathdir[1] * intensity;
2257 color[6] = pathdir[2] * intensity;
2258 color[7] = intensity;
2259 // for each color component (R, G, B) calculate the amount that a
2260 // direction contributes
2261 color[8] = color[0] * max(0.0f, pathdir[0]);
2262 color[9] = color[0] * max(0.0f, pathdir[1]);
2263 color[10] = color[0] * max(0.0f, pathdir[2]);
2265 color[12] = color[1] * max(0.0f, pathdir[0]);
2266 color[13] = color[1] * max(0.0f, pathdir[1]);
2267 color[14] = color[1] * max(0.0f, pathdir[2]);
2269 color[16] = color[2] * max(0.0f, pathdir[0]);
2270 color[17] = color[2] * max(0.0f, pathdir[1]);
2271 color[18] = color[2] * max(0.0f, pathdir[2]);
2273 // and do the same for negative directions
2274 color[20] = color[0] * max(0.0f, -pathdir[0]);
2275 color[21] = color[0] * max(0.0f, -pathdir[1]);
2276 color[22] = color[0] * max(0.0f, -pathdir[2]);
2278 color[24] = color[1] * max(0.0f, -pathdir[0]);
2279 color[25] = color[1] * max(0.0f, -pathdir[1]);
2280 color[26] = color[1] * max(0.0f, -pathdir[2]);
2282 color[28] = color[2] * max(0.0f, -pathdir[0]);
2283 color[29] = color[2] * max(0.0f, -pathdir[1]);
2284 color[30] = color[2] * max(0.0f, -pathdir[2]);
2288 for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2290 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2292 float sample[3], diff[3], nearest[3], along, distance2;
2293 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2295 // loop over the subsamples
2296 for (zs = 0; zs < samples; zs++)
2298 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2299 for (ys = 0; ys < samples; ys++)
2301 sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2302 for (xs = 0; xs < samples; xs++)
2304 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2306 // measure distance from subsample to line segment and see if it is within radius
2307 along = DotProduct(sample, pathdir) * pathilength;
2309 VectorCopy(pathstart, nearest);
2310 else if (along >= 1)
2311 VectorCopy(pathend, nearest);
2313 VectorLerp(pathstart, along, pathend, nearest);
2314 VectorSubtract(sample, nearest, diff);
2315 VectorScale(diff, iradius, diff);
2316 distance2 = VectorLength2(diff);
2317 if (distance2 < 1.0f)
2319 // contribute some color to this pixel, across all bands
2320 float w = 1.0f - sqrt(distance2);
2325 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2326 p[pixelsperband * 4 + 3] += color[7] * w;
2328 for (band = 0; band < pixelbands; band++)
2330 // add to the pixel color (RGB only - see above)
2331 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2332 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2333 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2345 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2347 R_Shadow_BounceGrid_Slice((int)t->i[0]);
2351 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2354 // we need to wait for the texture clear to finish before we start adding light to it
2355 if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2360 slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2361 for (i = 0; i < slices; i++)
2362 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2363 TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2364 TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2365 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2369 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2371 const float *inpixel;
2373 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2376 unsigned int x, y, z;
2377 unsigned int resolution[3];
2378 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2379 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2381 for (z = 1;z < resolution[2]-1;z++)
2383 for (y = 1;y < resolution[1]-1;y++)
2386 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2387 inpixel = inpixels + 4*index;
2388 outpixel = outpixels + 4*index;
2389 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2391 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2392 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2393 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2394 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2401 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2404 unsigned int resolution[3];
2405 if (r_shadow_bouncegrid_state.settings.blur)
2407 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2409 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2410 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2411 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2412 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2415 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2417 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2419 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2421 // toggle the state, highpixels now points to pixels[3] result
2422 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2423 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2428 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2430 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2431 unsigned char *pixelsbgra8 = NULL;
2432 unsigned char *pixelbgra8;
2433 unsigned short *pixelsrgba16f = NULL;
2434 unsigned short *pixelrgba16f;
2435 float *pixelsrgba32f = NULL;
2436 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2439 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2440 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2441 unsigned int pixelband;
2442 unsigned int x, y, z;
2443 unsigned int index, bandindex;
2444 unsigned int resolution[3];
2446 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2448 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2450 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2451 r_shadow_bouncegrid_state.texture = NULL;
2454 // if bentnormals exist, we need to normalize and bias them for the shader
2458 for (z = 0;z < resolution[2]-1;z++)
2460 for (y = 0;y < resolution[1]-1;y++)
2463 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2464 highpixel = highpixels + 4*index;
2465 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2467 // only convert pixels that were hit by photons
2468 if (highpixel[3] != 0.0f)
2469 VectorNormalize(highpixel);
2470 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2471 highpixel[pixelsperband * 4 + 3] = 1.0f;
2477 // start by clearing the pixels array - we won't be writing to all of it
2479 // then process only the pixels that have at least some color, skipping
2480 // the higher bands for speed on pixels that are black
2481 switch (floatcolors)
2484 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2485 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2486 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2487 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2490 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2492 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2494 for (z = 1;z < resolution[2]-1;z++)
2496 for (y = 1;y < resolution[1]-1;y++)
2500 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2501 highpixel = highpixels + 4*index;
2502 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2504 // only convert pixels that were hit by photons
2505 if (VectorLength2(highpixel))
2507 // normalize the bentnormal now
2510 VectorNormalize(highpixel + pixelsperband * 4);
2511 highpixel[pixelsperband * 4 + 3] = 1.0f;
2513 // process all of the pixelbands for this pixel
2514 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2516 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2517 bandpixel = highpixels + 4*bandindex;
2518 c[0] = (int)(bandpixel[0]*256.0f);
2519 c[1] = (int)(bandpixel[1]*256.0f);
2520 c[2] = (int)(bandpixel[2]*256.0f);
2521 c[3] = (int)(bandpixel[3]*256.0f);
2522 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2523 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2524 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2525 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2532 if (!r_shadow_bouncegrid_state.createtexture)
2533 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2535 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);
2538 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2539 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2540 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2541 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2542 for (z = 1;z < resolution[2]-1;z++)
2544 for (y = 1;y < resolution[1]-1;y++)
2548 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2549 highpixel = highpixels + 4*index;
2550 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2552 // only convert pixels that were hit by photons
2553 if (VectorLength2(highpixel))
2555 // process all of the pixelbands for this pixel
2556 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2558 // time to have fun with IEEE 754 bit hacking...
2561 unsigned int raw[4];
2563 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2564 bandpixel = highpixels + 4*bandindex;
2565 VectorCopy4(bandpixel, u.f);
2566 VectorCopy4(u.raw, c);
2567 // this math supports negative numbers, snaps denormals to zero
2568 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2569 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2570 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2571 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2572 // this math does not support negative
2573 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2574 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2575 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2576 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2583 if (!r_shadow_bouncegrid_state.createtexture)
2584 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2586 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);
2589 // our native format happens to match, so this is easy.
2590 pixelsrgba32f = highpixels;
2592 if (!r_shadow_bouncegrid_state.createtexture)
2593 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2595 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);
2599 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2602 static void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2604 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2608 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)
2610 int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2612 vec3_t surfacenormal;
2613 vec3_t reflectstart, reflectend, reflectcolor;
2614 vec3_t refractstart, refractend, refractcolor;
2616 float reflectamount = 1.0f;
2618 // figure out what we want to interact with
2619 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2620 skipsupercontentsmask = 0;
2621 skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2622 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2623 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2624 if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2626 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2627 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2628 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);
2632 // dynamic mode fires many rays and most will match the cache from the previous frame
2633 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);
2635 VectorCopy(cliptrace.endpos, shothit);
2636 if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2638 qboolean notculled = true;
2639 // cull paths that fail R_CullBox in dynamic mode
2640 if (!r_shadow_bouncegrid_state.settings.staticmode
2641 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2643 vec3_t cullmins, cullmaxs;
2644 cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2645 cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2646 cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2647 cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2648 cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2649 cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2650 if (R_CullBox(cullmins, cullmaxs))
2655 r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2656 VectorCopy(shotstart, path->start);
2657 VectorCopy(shothit, path->end);
2658 VectorCopy(shotcolor, path->color);
2661 if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2663 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2664 // also clamp the resulting color to never add energy, even if the user requests extreme values
2665 VectorCopy(cliptrace.plane.normal, surfacenormal);
2666 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2667 VectorClear(refractcolor);
2668 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2669 if (cliptrace.hittexture)
2671 if (cliptrace.hittexture->currentskinframe)
2672 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2673 if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2675 reflectamount *= cliptrace.hittexture->currentalpha;
2676 if (cliptrace.hittexture->currentskinframe)
2677 reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2679 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2683 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2684 VectorSubtract(shotstart, shotend, lightdir);
2685 VectorNormalize(lightdir);
2686 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2687 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2688 reflectamount *= Fresnel;
2689 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2691 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2692 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2693 // make sure we do not gain energy even if surface colors are out of bounds
2694 reflectcolor[0] = min(reflectcolor[0], 1.0f);
2695 reflectcolor[1] = min(reflectcolor[1], 1.0f);
2696 reflectcolor[2] = min(reflectcolor[2], 1.0f);
2697 refractcolor[0] = min(refractcolor[0], 1.0f);
2698 refractcolor[1] = min(refractcolor[1], 1.0f);
2699 refractcolor[2] = min(refractcolor[2], 1.0f);
2701 // reflected and refracted shots
2702 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2703 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2704 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2705 VectorMultiply(refractcolor, shotcolor, refractcolor);
2707 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2709 // reflect the remaining portion of the line across plane normal
2710 VectorSubtract(shotend, shothit, reflectend);
2711 VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2712 // calculate the new line start and end
2713 VectorCopy(shothit, reflectstart);
2714 VectorAdd(reflectstart, reflectend, reflectend);
2715 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2718 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2720 // Check what refractive index is on the other side
2721 float refractiveindex;
2722 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2723 refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2724 // reflect the remaining portion of the line across plane normal
2725 VectorSubtract(shotend, shothit, refractend);
2726 s = refractiveindex / previousrefractiveindex;
2727 VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2728 // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2729 // calculate the new line start and end
2730 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2731 VectorAdd(refractstart, refractend, refractend);
2732 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2737 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2739 r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2740 R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2744 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2747 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2748 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2749 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);
2750 if (r_shadow_bouncegrid_threaded.integer)
2752 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2753 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2757 // when not threaded we still have to report task status
2758 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2759 r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2760 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2765 void R_Shadow_UpdateBounceGridTexture(void)
2767 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2768 r_shadow_bouncegrid_settings_t settings;
2769 qboolean enable = false;
2770 qboolean settingschanged;
2772 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2774 R_Shadow_BounceGrid_GenerateSettings(&settings);
2776 // changing intensity does not require an update
2777 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2779 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2781 // when settings change, we free everything as it is just simpler that way.
2782 if (settingschanged || !enable)
2784 // not enabled, make sure we free anything we don't need anymore.
2785 if (r_shadow_bouncegrid_state.texture)
2787 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2788 r_shadow_bouncegrid_state.texture = NULL;
2790 r_shadow_bouncegrid_state.highpixels = NULL;
2791 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2792 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2793 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2794 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2795 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2796 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2797 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2798 r_shadow_bouncegrid_state.numpixels = 0;
2799 r_shadow_bouncegrid_state.numphotons = 0;
2800 r_shadow_bouncegrid_state.directional = false;
2806 // if all the settings seem identical to the previous update, return
2807 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2810 // store the new settings
2811 r_shadow_bouncegrid_state.settings = settings;
2813 R_Shadow_BounceGrid_UpdateSpacing();
2815 // allocate the highpixels array we'll be accumulating light into
2816 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2817 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2818 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2819 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2820 r_shadow_bouncegrid_state.highpixels_index = 0;
2821 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2823 // set up the tracking of photon data
2824 if (r_shadow_bouncegrid_state.photons == NULL)
2825 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));
2826 if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2827 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2828 r_shadow_bouncegrid_state.numphotons = 0;
2830 // set up the tracking of slice tasks
2831 if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2832 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2834 memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2835 memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2836 memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2837 memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2838 memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2839 memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2840 memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2841 memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2842 memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2844 // clear the texture
2845 TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2846 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2848 // calculate weighting factors for distributing photons among the lights
2849 TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2850 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2852 // enqueue tasks to trace the photons from lights
2853 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2854 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2856 // accumulate the light paths into texture
2857 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);
2858 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2860 // apply a mild blur filter to the texture
2861 TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2862 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2864 TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2865 R_TimeReport("bouncegrid_gen");
2867 // convert the pixels to lower precision and upload the texture
2868 // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2869 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2870 R_TimeReport("bouncegrid_tex");
2872 // after we compute the static lighting we don't need to keep the highpixels array around
2873 if (settings.staticmode)
2875 r_shadow_bouncegrid_state.highpixels = NULL;
2876 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2877 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2878 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2879 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2880 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2881 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2882 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2886 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2888 R_Shadow_RenderMode_Reset();
2889 GL_BlendFunc(GL_ONE, GL_ONE);
2890 GL_DepthRange(0, 1);
2891 GL_DepthTest(r_showlighting.integer < 2);
2892 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2894 GL_DepthFunc(GL_EQUAL);
2895 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2898 void R_Shadow_RenderMode_End(void)
2900 R_Shadow_RenderMode_Reset();
2901 R_Shadow_RenderMode_ActiveLight(NULL);
2903 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2904 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2907 int bboxedges[12][2] =
2926 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2928 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2930 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2931 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2932 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2933 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2936 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2937 return true; // invisible
2938 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2939 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2940 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2941 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2942 r_refdef.stats[r_stat_lights_scissored]++;
2946 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2948 // used to display how many times a surface is lit for level design purposes
2949 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2950 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2954 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])
2956 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2957 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2961 extern cvar_t gl_lightmaps;
2962 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2965 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2966 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2967 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2968 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2969 if (!r_shadow_usenormalmap.integer)
2971 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2972 VectorClear(diffusecolor);
2973 VectorClear(specularcolor);
2975 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2976 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2977 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2978 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2980 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2983 VectorNegate(ambientcolor, ambientcolor);
2984 VectorNegate(diffusecolor, diffusecolor);
2985 VectorNegate(specularcolor, specularcolor);
2986 GL_BlendEquationSubtract(true);
2988 RSurf_SetupDepthAndCulling();
2989 switch (r_shadow_rendermode)
2991 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2992 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2993 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2995 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2996 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2999 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3003 GL_BlendEquationSubtract(false);
3006 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)
3008 matrix4x4_t tempmatrix = *matrix;
3009 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3011 // if this light has been compiled before, free the associated data
3012 R_RTLight_Uncompile(rtlight);
3014 // clear it completely to avoid any lingering data
3015 memset(rtlight, 0, sizeof(*rtlight));
3017 // copy the properties
3018 rtlight->matrix_lighttoworld = tempmatrix;
3019 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3020 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3021 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3022 VectorCopy(color, rtlight->color);
3023 rtlight->cubemapname[0] = 0;
3024 if (cubemapname && cubemapname[0])
3025 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3026 rtlight->shadow = shadow;
3027 rtlight->corona = corona;
3028 rtlight->style = style;
3029 rtlight->isstatic = isstatic;
3030 rtlight->coronasizescale = coronasizescale;
3031 rtlight->ambientscale = ambientscale;
3032 rtlight->diffusescale = diffusescale;
3033 rtlight->specularscale = specularscale;
3034 rtlight->flags = flags;
3036 // compute derived data
3037 //rtlight->cullradius = rtlight->radius;
3038 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3039 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3040 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3041 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3042 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3043 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3044 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3047 // compiles rtlight geometry
3048 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3049 void R_RTLight_Compile(rtlight_t *rtlight)
3052 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3053 int lighttris, shadowtris;
3054 entity_render_t *ent = r_refdef.scene.worldentity;
3055 dp_model_t *model = r_refdef.scene.worldmodel;
3056 unsigned char *data;
3058 // compile the light
3059 rtlight->compiled = true;
3060 rtlight->static_numleafs = 0;
3061 rtlight->static_numleafpvsbytes = 0;
3062 rtlight->static_leaflist = NULL;
3063 rtlight->static_leafpvs = NULL;
3064 rtlight->static_numsurfaces = 0;
3065 rtlight->static_surfacelist = NULL;
3066 rtlight->static_shadowmap_receivers = 0x3F;
3067 rtlight->static_shadowmap_casters = 0x3F;
3068 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3069 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3070 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3071 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3072 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3073 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3075 if (model && model->GetLightInfo)
3077 // this variable must be set for the CompileShadowMap code
3078 r_shadow_compilingrtlight = rtlight;
3079 R_FrameData_SetMark();
3080 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);
3081 R_FrameData_ReturnToMark();
3082 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3083 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3084 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3085 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3086 rtlight->static_numsurfaces = numsurfaces;
3087 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3088 rtlight->static_numleafs = numleafs;
3089 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3090 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3091 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3092 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3093 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3094 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3095 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3096 if (rtlight->static_numsurfaces)
3097 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3098 if (rtlight->static_numleafs)
3099 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3100 if (rtlight->static_numleafpvsbytes)
3101 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3102 if (rtlight->static_numshadowtrispvsbytes)
3103 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3104 if (rtlight->static_numlighttrispvsbytes)
3105 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3106 R_FrameData_SetMark();
3107 if (model->CompileShadowMap && rtlight->shadow)
3108 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3109 R_FrameData_ReturnToMark();
3110 // now we're done compiling the rtlight
3111 r_shadow_compilingrtlight = NULL;
3115 // use smallest available cullradius - box radius or light radius
3116 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3117 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3120 if (rtlight->static_numlighttrispvsbytes)
3121 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3122 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3126 if (rtlight->static_numshadowtrispvsbytes)
3127 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3128 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3131 if (developer_extra.integer)
3132 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);
3135 void R_RTLight_Uncompile(rtlight_t *rtlight)
3137 if (rtlight->compiled)
3139 if (rtlight->static_meshchain_shadow_shadowmap)
3140 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3141 rtlight->static_meshchain_shadow_shadowmap = NULL;
3142 // these allocations are grouped
3143 if (rtlight->static_surfacelist)
3144 Mem_Free(rtlight->static_surfacelist);
3145 rtlight->static_numleafs = 0;
3146 rtlight->static_numleafpvsbytes = 0;
3147 rtlight->static_leaflist = NULL;
3148 rtlight->static_leafpvs = NULL;
3149 rtlight->static_numsurfaces = 0;
3150 rtlight->static_surfacelist = NULL;
3151 rtlight->static_numshadowtrispvsbytes = 0;
3152 rtlight->static_shadowtrispvs = NULL;
3153 rtlight->static_numlighttrispvsbytes = 0;
3154 rtlight->static_lighttrispvs = NULL;
3155 rtlight->compiled = false;
3159 void R_Shadow_UncompileWorldLights(void)
3163 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3164 for (lightindex = 0;lightindex < range;lightindex++)
3166 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3169 R_RTLight_Uncompile(&light->rtlight);
3173 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3177 // reset the count of frustum planes
3178 // see rtlight->cached_frustumplanes definition for how much this array
3180 rtlight->cached_numfrustumplanes = 0;
3182 if (r_trippy.integer)
3185 // haven't implemented a culling path for ortho rendering
3186 if (!r_refdef.view.useperspective)
3188 // check if the light is on screen and copy the 4 planes if it is
3189 for (i = 0;i < 4;i++)
3190 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3193 for (i = 0;i < 4;i++)
3194 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3199 // generate a deformed frustum that includes the light origin, this is
3200 // used to cull shadow casting surfaces that can not possibly cast a
3201 // shadow onto the visible light-receiving surfaces, which can be a
3204 // if the light origin is onscreen the result will be 4 planes exactly
3205 // if the light origin is offscreen on only one axis the result will
3206 // be exactly 5 planes (split-side case)
3207 // if the light origin is offscreen on two axes the result will be
3208 // exactly 4 planes (stretched corner case)
3209 for (i = 0;i < 4;i++)
3211 // quickly reject standard frustum planes that put the light
3212 // origin outside the frustum
3213 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3216 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3218 // if all the standard frustum planes were accepted, the light is onscreen
3219 // otherwise we need to generate some more planes below...
3220 if (rtlight->cached_numfrustumplanes < 4)
3222 // at least one of the stock frustum planes failed, so we need to
3223 // create one or two custom planes to enclose the light origin
3224 for (i = 0;i < 4;i++)
3226 // create a plane using the view origin and light origin, and a
3227 // single point from the frustum corner set
3228 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3229 VectorNormalize(plane.normal);
3230 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3231 // see if this plane is backwards and flip it if so
3232 for (j = 0;j < 4;j++)
3233 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3237 VectorNegate(plane.normal, plane.normal);
3239 // flipped plane, test again to see if it is now valid
3240 for (j = 0;j < 4;j++)
3241 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3243 // if the plane is still not valid, then it is dividing the
3244 // frustum and has to be rejected
3248 // we have created a valid plane, compute extra info
3249 PlaneClassify(&plane);
3251 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3253 // if we've found 5 frustum planes then we have constructed a
3254 // proper split-side case and do not need to keep searching for
3255 // planes to enclose the light origin
3256 if (rtlight->cached_numfrustumplanes == 5)
3264 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3266 plane = rtlight->cached_frustumplanes[i];
3267 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));
3272 // now add the light-space box planes if the light box is rotated, as any
3273 // caster outside the oriented light box is irrelevant (even if it passed
3274 // the worldspace light box, which is axial)
3275 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3277 for (i = 0;i < 6;i++)
3281 v[i >> 1] = (i & 1) ? -1 : 1;
3282 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3283 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3284 plane.dist = VectorNormalizeLength(plane.normal);
3285 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3286 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3292 // add the world-space reduced box planes
3293 for (i = 0;i < 6;i++)
3295 VectorClear(plane.normal);
3296 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3297 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3298 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3307 // reduce all plane distances to tightly fit the rtlight cull box, which
3309 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3310 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3311 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3312 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3313 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3314 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3315 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3316 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3317 oldnum = rtlight->cached_numfrustumplanes;
3318 rtlight->cached_numfrustumplanes = 0;
3319 for (j = 0;j < oldnum;j++)
3321 // find the nearest point on the box to this plane
3322 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3323 for (i = 1;i < 8;i++)
3325 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3326 if (bestdist > dist)
3329 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);
3330 // if the nearest point is near or behind the plane, we want this
3331 // plane, otherwise the plane is useless as it won't cull anything
3332 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3334 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3335 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3342 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3344 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3346 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3348 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3349 if (mesh->sidetotals[r_shadow_shadowmapside])
3352 GL_CullFace(GL_NONE);
3353 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3354 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3355 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);
3359 else if (r_refdef.scene.worldentity->model)
3360 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);
3362 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3365 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3367 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3368 vec_t relativeshadowradius;
3369 RSurf_ActiveModelEntity(ent, false, false, false);
3370 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3371 // we need to re-init the shader for each entity because the matrix changed
3372 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3373 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3374 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3375 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3376 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3377 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3378 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3379 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3380 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3383 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3385 // set up properties for rendering light onto this entity
3386 RSurf_ActiveModelEntity(ent, true, true, false);
3387 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3388 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3389 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3390 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3393 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3395 if (!r_refdef.scene.worldmodel->DrawLight)
3398 // set up properties for rendering light onto this entity
3399 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3400 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3401 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3402 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3403 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3405 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3407 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3410 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3412 dp_model_t *model = ent->model;
3413 if (!model->DrawLight)
3416 R_Shadow_SetupEntityLight(ent);
3418 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3420 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3423 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3427 int numleafs, numsurfaces;
3428 int *leaflist, *surfacelist;
3429 unsigned char *leafpvs;
3430 unsigned char *shadowtrispvs;
3431 unsigned char *lighttrispvs;
3432 //unsigned char *surfacesides;
3433 int numlightentities;
3434 int numlightentities_noselfshadow;
3435 int numshadowentities;
3436 int numshadowentities_noselfshadow;
3437 // FIXME: bounds check lightentities and shadowentities, etc.
3438 static entity_render_t *lightentities[MAX_EDICTS];
3439 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3440 static entity_render_t *shadowentities[MAX_EDICTS];
3441 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3443 qboolean castshadows;
3445 rtlight->draw = false;
3446 rtlight->cached_numlightentities = 0;
3447 rtlight->cached_numlightentities_noselfshadow = 0;
3448 rtlight->cached_numshadowentities = 0;
3449 rtlight->cached_numshadowentities_noselfshadow = 0;
3450 rtlight->cached_numsurfaces = 0;
3451 rtlight->cached_lightentities = NULL;
3452 rtlight->cached_lightentities_noselfshadow = NULL;
3453 rtlight->cached_shadowentities = NULL;
3454 rtlight->cached_shadowentities_noselfshadow = NULL;
3455 rtlight->cached_shadowtrispvs = NULL;
3456 rtlight->cached_lighttrispvs = NULL;
3457 rtlight->cached_surfacelist = NULL;
3458 rtlight->shadowmapsidesize = 0;
3460 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3461 // skip lights that are basically invisible (color 0 0 0)
3462 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3464 // loading is done before visibility checks because loading should happen
3465 // all at once at the start of a level, not when it stalls gameplay.
3466 // (especially important to benchmarks)
3468 if (rtlight->isstatic && !nolight && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3469 R_RTLight_Compile(rtlight);
3472 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3474 // look up the light style value at this time
3475 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3476 VectorScale(rtlight->color, f, rtlight->currentcolor);
3478 if (rtlight->selected)
3480 f = 2 + sin(realtime * M_PI * 4.0);
3481 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3485 // skip if lightstyle is currently off
3486 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3489 // skip processing on corona-only lights
3493 // skip if the light box is not touching any visible leafs
3494 if (r_shadow_culllights_pvs.integer
3495 && r_refdef.scene.worldmodel
3496 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3497 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3500 // skip if the light box is not visible to traceline
3501 if (r_shadow_culllights_trace.integer)
3503 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
3504 rtlight->trace_timer = realtime;
3505 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3509 // skip if the light box is off screen
3510 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3513 // in the typical case this will be quickly replaced by GetLightInfo
3514 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3515 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3517 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3519 // don't allow lights to be drawn if using r_shadow_bouncegrid 2, except if we're using static bouncegrid where dynamic lights still need to draw
3520 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3523 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3525 // compiled light, world available and can receive realtime lighting
3526 // retrieve leaf information
3527 numleafs = rtlight->static_numleafs;
3528 leaflist = rtlight->static_leaflist;
3529 leafpvs = rtlight->static_leafpvs;
3530 numsurfaces = rtlight->static_numsurfaces;
3531 surfacelist = rtlight->static_surfacelist;
3532 //surfacesides = NULL;
3533 shadowtrispvs = rtlight->static_shadowtrispvs;
3534 lighttrispvs = rtlight->static_lighttrispvs;
3536 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3538 // dynamic light, world available and can receive realtime lighting
3539 // calculate lit surfaces and leafs
3540 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes, rtlight->shadow == 0);
3541 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3542 leaflist = r_shadow_buffer_leaflist;
3543 leafpvs = r_shadow_buffer_leafpvs;
3544 surfacelist = r_shadow_buffer_surfacelist;
3545 //surfacesides = r_shadow_buffer_surfacesides;
3546 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3547 lighttrispvs = r_shadow_buffer_lighttrispvs;
3548 // if the reduced leaf bounds are offscreen, skip it
3549 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3560 //surfacesides = NULL;
3561 shadowtrispvs = NULL;
3562 lighttrispvs = NULL;
3564 // check if light is illuminating any visible leafs
3567 for (i = 0; i < numleafs; i++)
3568 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3574 // make a list of lit entities and shadow casting entities
3575 numlightentities = 0;
3576 numlightentities_noselfshadow = 0;
3577 numshadowentities = 0;
3578 numshadowentities_noselfshadow = 0;
3580 // add dynamic entities that are lit by the light
3581 for (i = 0; i < r_refdef.scene.numentities; i++)
3584 entity_render_t *ent = r_refdef.scene.entities[i];
3586 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3588 // skip the object entirely if it is not within the valid
3589 // shadow-casting region (which includes the lit region)
3590 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3592 if (!(model = ent->model))
3594 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3596 // this entity wants to receive light, is visible, and is
3597 // inside the light box
3598 // TODO: check if the surfaces in the model can receive light
3599 // so now check if it's in a leaf seen by the light
3600 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3602 if (ent->flags & RENDER_NOSELFSHADOW)
3603 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3605 lightentities[numlightentities++] = ent;
3606 // since it is lit, it probably also casts a shadow...
3607 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3608 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3609 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3611 // note: exterior models without the RENDER_NOSELFSHADOW
3612 // flag still create a RENDER_NOSELFSHADOW shadow but
3613 // are lit normally, this means that they are
3614 // self-shadowing but do not shadow other
3615 // RENDER_NOSELFSHADOW entities such as the gun
3616 // (very weird, but keeps the player shadow off the gun)
3617 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3618 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3620 shadowentities[numshadowentities++] = ent;
3623 else if (ent->flags & RENDER_SHADOW)
3625 // this entity is not receiving light, but may still need to
3627 // TODO: check if the surfaces in the model can cast shadow
3628 // now check if it is in a leaf seen by the light
3629 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3631 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3632 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3633 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3635 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3636 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3638 shadowentities[numshadowentities++] = ent;
3643 // return if there's nothing at all to light
3644 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3647 // count this light in the r_speeds
3648 r_refdef.stats[r_stat_lights]++;
3650 // flag it as worth drawing later
3651 rtlight->draw = true;
3653 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3654 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3656 numshadowentities = numshadowentities_noselfshadow = 0;
3657 rtlight->castshadows = castshadows;
3659 // cache all the animated entities that cast a shadow but are not visible
3660 for (i = 0; i < numshadowentities; i++)
3661 R_AnimCache_GetEntity(shadowentities[i], false, false);
3662 for (i = 0; i < numshadowentities_noselfshadow; i++)
3663 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3665 // we can convert noselfshadow to regular if there are no receivers of that type (or we're using r_shadow_deferred which doesn't support noselfshadow anyway)
3666 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3668 for (i = 0; i < numshadowentities_noselfshadow; i++)
3669 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3670 numshadowentities_noselfshadow = 0;
3673 // we can convert noselfshadow to regular if there are no casters of that type
3674 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3676 for (i = 0; i < numlightentities_noselfshadow; i++)
3677 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3678 numlightentities_noselfshadow = 0;
3681 // allocate some temporary memory for rendering this light later in the frame
3682 // reusable buffers need to be copied, static data can be used as-is
3683 rtlight->cached_numlightentities = numlightentities;
3684 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3685 rtlight->cached_numshadowentities = numshadowentities;
3686 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3687 rtlight->cached_numsurfaces = numsurfaces;
3688 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3689 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3690 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3691 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3692 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3694 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3695 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3696 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3697 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3698 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3702 // compiled light data
3703 rtlight->cached_shadowtrispvs = shadowtrispvs;
3704 rtlight->cached_lighttrispvs = lighttrispvs;
3705 rtlight->cached_surfacelist = surfacelist;
3708 if (R_Shadow_ShadowMappingEnabled())
3710 // figure out the shadowmapping parameters for this light
3711 vec3_t nearestpoint;
3714 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3715 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3716 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3717 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3718 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3719 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3720 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3721 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3722 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3726 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3730 unsigned char *shadowtrispvs, *surfacesides;
3731 int numlightentities;
3732 int numlightentities_noselfshadow;
3733 int numshadowentities;
3734 int numshadowentities_noselfshadow;
3735 entity_render_t **lightentities;
3736 entity_render_t **lightentities_noselfshadow;
3737 entity_render_t **shadowentities;
3738 entity_render_t **shadowentities_noselfshadow;
3740 static unsigned char entitysides[MAX_EDICTS];
3741 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3747 matrix4x4_t radiustolight;
3749 // check if we cached this light this frame (meaning it is worth drawing)
3750 if (!rtlight->draw || !rtlight->castshadows)
3753 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3754 if (rtlight->shadowmapatlassidesize == 0)
3756 rtlight->castshadows = false;
3760 // set up a scissor rectangle for this light
3761 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3764 // don't let sound skip if going slow
3765 if (r_refdef.scene.extraupdate)
3768 numlightentities = rtlight->cached_numlightentities;
3769 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3770 numshadowentities = rtlight->cached_numshadowentities;
3771 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3772 numsurfaces = rtlight->cached_numsurfaces;
3773 lightentities = rtlight->cached_lightentities;
3774 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3775 shadowentities = rtlight->cached_shadowentities;
3776 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3777 shadowtrispvs = rtlight->cached_shadowtrispvs;
3778 surfacelist = rtlight->cached_surfacelist;
3780 // make this the active rtlight for rendering purposes
3781 R_Shadow_RenderMode_ActiveLight(rtlight);
3783 radiustolight = rtlight->matrix_worldtolight;
3784 Matrix4x4_Abs(&radiustolight);
3786 size = rtlight->shadowmapatlassidesize;
3787 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3789 surfacesides = NULL;
3794 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3796 castermask = rtlight->static_shadowmap_casters;
3797 receivermask = rtlight->static_shadowmap_receivers;
3801 surfacesides = r_shadow_buffer_surfacesides;
3802 for (i = 0; i < numsurfaces; i++)
3804 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3805 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3806 castermask |= surfacesides[i];
3807 receivermask |= surfacesides[i];
3812 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3813 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3814 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3815 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3817 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3821 for (i = 0; i < numshadowentities; i++)
3822 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3823 for (i = 0; i < numshadowentities_noselfshadow; i++)
3824 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3827 // there is no need to render shadows for sides that have no receivers...
3828 castermask &= receivermask;
3830 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3832 // render shadow casters into shadowmaps for this light
3833 for (side = 0; side < 6; side++)
3835 int bit = 1 << side;
3836 if (castermask & bit)
3838 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3840 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3841 for (i = 0; i < numshadowentities; i++)
3842 if (entitysides[i] & bit)
3843 R_Shadow_DrawEntityShadow(shadowentities[i]);
3844 for (i = 0; i < numshadowentities_noselfshadow; i++)
3845 if (entitysides_noselfshadow[i] & bit)
3846 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3849 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3850 if (numshadowentities_noselfshadow)
3852 for (side = 0; side < 6; side++)
3854 int bit = 1 << side;
3855 if (castermask & bit)
3857 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3859 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3860 for (i = 0; i < numshadowentities; i++)
3861 if (entitysides[i] & bit)
3862 R_Shadow_DrawEntityShadow(shadowentities[i]);
3868 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3872 unsigned char *lighttrispvs;
3873 int numlightentities;
3874 int numlightentities_noselfshadow;
3875 entity_render_t **lightentities;
3876 entity_render_t **lightentities_noselfshadow;
3878 qboolean castshadows;
3880 // check if we cached this light this frame (meaning it is worth drawing)
3884 // set up a scissor rectangle for this light
3885 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3888 // don't let sound skip if going slow
3889 if (r_refdef.scene.extraupdate)
3892 numlightentities = rtlight->cached_numlightentities;
3893 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3894 numsurfaces = rtlight->cached_numsurfaces;
3895 lightentities = rtlight->cached_lightentities;
3896 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3897 lighttrispvs = rtlight->cached_lighttrispvs;
3898 surfacelist = rtlight->cached_surfacelist;
3899 castshadows = rtlight->castshadows;
3901 // make this the active rtlight for rendering purposes
3902 R_Shadow_RenderMode_ActiveLight(rtlight);
3904 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3906 // optionally draw the illuminated areas
3907 // for performance analysis by level designers
3908 R_Shadow_RenderMode_VisibleLighting(false);
3910 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3911 for (i = 0;i < numlightentities;i++)
3912 R_Shadow_DrawEntityLight(lightentities[i]);
3913 for (i = 0;i < numlightentities_noselfshadow;i++)
3914 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3917 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3919 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3920 Matrix4x4_Abs(&radiustolight);
3922 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3924 // render lighting using the depth texture as shadowmap
3925 // draw lighting in the unmasked areas
3926 if (numsurfaces + numlightentities)
3928 R_Shadow_RenderMode_Lighting(false, true, false);
3929 // draw lighting in the unmasked areas
3931 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3932 for (i = 0; i < numlightentities; i++)
3933 R_Shadow_DrawEntityLight(lightentities[i]);
3935 // offset to the noselfshadow part of the atlas and draw those too
3936 if (numlightentities_noselfshadow)
3938 R_Shadow_RenderMode_Lighting(false, true, true);
3939 for (i = 0; i < numlightentities_noselfshadow; i++)
3940 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3943 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3944 if (r_shadow_usingdeferredprepass)
3945 R_Shadow_RenderMode_DrawDeferredLight(true);
3949 // draw lighting in the unmasked areas
3950 R_Shadow_RenderMode_Lighting(false, false, false);
3952 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3953 for (i = 0;i < numlightentities;i++)
3954 R_Shadow_DrawEntityLight(lightentities[i]);
3955 for (i = 0;i < numlightentities_noselfshadow;i++)
3956 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3958 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3959 if (r_shadow_usingdeferredprepass)
3960 R_Shadow_RenderMode_DrawDeferredLight(false);
3964 static void R_Shadow_FreeDeferred(void)
3966 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3967 r_shadow_prepassgeometryfbo = 0;
3969 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3970 r_shadow_prepasslightingdiffusespecularfbo = 0;
3972 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3973 r_shadow_prepasslightingdiffusefbo = 0;
3975 if (r_shadow_prepassgeometrydepthbuffer)
3976 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3977 r_shadow_prepassgeometrydepthbuffer = NULL;
3979 if (r_shadow_prepassgeometrynormalmaptexture)
3980 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3981 r_shadow_prepassgeometrynormalmaptexture = NULL;
3983 if (r_shadow_prepasslightingdiffusetexture)
3984 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3985 r_shadow_prepasslightingdiffusetexture = NULL;
3987 if (r_shadow_prepasslightingspeculartexture)
3988 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3989 r_shadow_prepasslightingspeculartexture = NULL;
3992 void R_Shadow_DrawPrepass(void)
3996 entity_render_t *ent;
3997 float clearcolor[4];
3999 R_Mesh_ResetTextureState();
4001 GL_ColorMask(1,1,1,1);
4002 GL_BlendFunc(GL_ONE, GL_ZERO);
4005 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4006 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4007 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4008 if (r_timereport_active)
4009 R_TimeReport("prepasscleargeom");
4011 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4012 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4013 if (r_timereport_active)
4014 R_TimeReport("prepassworld");
4016 for (i = 0;i < r_refdef.scene.numentities;i++)
4018 if (!r_refdef.viewcache.entityvisible[i])
4020 ent = r_refdef.scene.entities[i];
4021 if (ent->model && ent->model->DrawPrepass != NULL)
4022 ent->model->DrawPrepass(ent);
4025 if (r_timereport_active)
4026 R_TimeReport("prepassmodels");
4028 GL_DepthMask(false);
4029 GL_ColorMask(1,1,1,1);
4032 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4033 Vector4Set(clearcolor, 0, 0, 0, 0);
4034 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4035 if (r_timereport_active)
4036 R_TimeReport("prepassclearlit");
4038 R_Shadow_RenderMode_Begin();
4040 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4041 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4043 R_Shadow_RenderMode_End();
4045 if (r_timereport_active)
4046 R_TimeReport("prepasslights");
4049 #define MAX_SCENELIGHTS 65536
4050 static qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4052 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4054 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4056 r_shadow_scenemaxlights *= 2;
4057 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4058 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4060 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4064 void R_Shadow_DrawLightSprites(void);
4065 void R_Shadow_PrepareLights(void)
4074 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4075 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4076 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4078 if (r_shadow_shadowmode_shadowmapping != r_shadow_shadowmapping.integer ||
4079 r_shadow_shadowmode_deferred != r_shadow_deferred.integer ||
4080 r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4081 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4082 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4083 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4084 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4085 r_shadow_shadowmapborder != shadowmapborder ||
4086 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4087 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4088 R_Shadow_FreeShadowMaps();
4090 r_shadow_usingshadowmaportho = false;
4092 switch (vid.renderpath)
4094 case RENDERPATH_GL32:
4096 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4098 r_shadow_usingdeferredprepass = false;
4099 if (r_shadow_prepass_width)
4100 R_Shadow_FreeDeferred();
4101 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4105 if (r_shadow_prepass_width != r_fb.screentexturewidth || r_shadow_prepass_height != r_fb.screentextureheight)
4107 R_Shadow_FreeDeferred();
4109 r_shadow_usingdeferredprepass = true;
4110 r_shadow_prepass_width = r_fb.screentexturewidth;
4111 r_shadow_prepass_height = r_fb.screentextureheight;
4112 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", r_fb.screentexturewidth, r_fb.screentextureheight, TEXTYPE_DEPTHBUFFER24);
4113 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4114 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4115 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4117 // set up the geometry pass fbo (depth + normalmap)
4118 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4119 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4120 // render depth into a renderbuffer and other important properties into the normalmap texture
4122 // set up the lighting pass fbo (diffuse + specular)
4123 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4124 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4125 // render diffuse into one texture and specular into another,
4126 // with depth and normalmap bound as textures,
4127 // with depth bound as attachment as well
4129 // set up the lighting pass fbo (diffuse)
4130 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4131 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4132 // render diffuse into one texture,
4133 // with depth and normalmap bound as textures,
4134 // with depth bound as attachment as well
4138 case RENDERPATH_GLES2:
4139 r_shadow_usingdeferredprepass = false;
4143 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);
4145 r_shadow_scenenumlights = 0;
4146 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4147 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4148 for (lightindex = 0; lightindex < range; lightindex++)
4150 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4151 if (light && (light->flags & flag))
4153 R_Shadow_PrepareLight(&light->rtlight);
4154 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4157 if (r_refdef.scene.rtdlight)
4159 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4161 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4162 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4165 else if (gl_flashblend.integer)
4167 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4169 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4170 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4171 VectorScale(rtlight->color, f, rtlight->currentcolor);
4175 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4176 if (r_shadow_debuglight.integer >= 0)
4178 r_shadow_scenenumlights = 0;
4179 lightindex = r_shadow_debuglight.integer;
4180 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4183 R_Shadow_PrepareLight(&light->rtlight);
4184 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4188 // if we're doing shadowmaps we need to prepare the atlas layout now
4189 if (R_Shadow_ShadowMappingEnabled())
4193 // allocate shadowmaps in the atlas now
4194 // 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...
4195 for (lod = 0; lod < 16; lod++)
4197 int packing_success = 0;
4198 int packing_failure = 0;
4199 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4200 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4201 if (r_shadow_shadowmapatlas_modelshadows_size)
4202 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);
4203 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4205 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4206 int size = rtlight->shadowmapsidesize >> lod;
4208 if (!rtlight->castshadows)
4210 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4213 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4214 if (rtlight->cached_numshadowentities_noselfshadow)
4216 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4218 rtlight->shadowmapatlassidesize = size;
4223 // note down that we failed to pack this one, it will have to disable shadows
4224 rtlight->shadowmapatlassidesize = 0;
4228 // generally everything fits and we stop here on the first iteration
4229 if (packing_failure == 0)
4234 if (r_editlights.integer)
4235 R_Shadow_DrawLightSprites();
4238 void R_Shadow_DrawShadowMaps(void)
4240 R_Shadow_RenderMode_Begin();
4241 R_Shadow_RenderMode_ActiveLight(NULL);
4243 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4244 R_Shadow_ClearShadowMapTexture();
4246 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4247 if (r_shadow_shadowmapatlas_modelshadows_size)
4249 R_Shadow_DrawModelShadowMaps();
4250 // don't let sound skip if going slow
4251 if (r_refdef.scene.extraupdate)
4255 if (R_Shadow_ShadowMappingEnabled())
4258 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4259 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4262 R_Shadow_RenderMode_End();
4265 void R_Shadow_DrawLights(void)
4269 R_Shadow_RenderMode_Begin();
4271 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4272 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4274 R_Shadow_RenderMode_End();
4277 #define MAX_MODELSHADOWS 1024
4278 static int r_shadow_nummodelshadows;
4279 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4281 void R_Shadow_PrepareModelShadows(void)
4284 float scale, size, radius, dot1, dot2;
4285 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4286 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4287 entity_render_t *ent;
4289 r_shadow_nummodelshadows = 0;
4290 r_shadow_shadowmapatlas_modelshadows_size = 0;
4292 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4295 size = r_shadow_shadowmaptexturesize / 4;
4296 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4297 radius = 0.5f * size / scale;
4299 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4300 VectorCopy(prvmshadowdir, shadowdir);
4301 VectorNormalize(shadowdir);
4302 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4303 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4304 if (fabs(dot1) <= fabs(dot2))
4305 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4307 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4308 VectorNormalize(shadowforward);
4309 CrossProduct(shadowdir, shadowforward, shadowright);
4310 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4311 VectorCopy(prvmshadowfocus, shadowfocus);
4312 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4313 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4314 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4315 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4316 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4318 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4320 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4321 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4322 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4323 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4324 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4325 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4327 for (i = 0; i < r_refdef.scene.numentities; i++)
4329 ent = r_refdef.scene.entities[i];
4330 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4332 // cast shadows from anything of the map (submodels are optional)
4333 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4335 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4337 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4338 R_AnimCache_GetEntity(ent, false, false);
4342 if (r_shadow_nummodelshadows)
4344 r_shadow_shadowmapatlas_modelshadows_x = 0;
4345 r_shadow_shadowmapatlas_modelshadows_y = 0;
4346 r_shadow_shadowmapatlas_modelshadows_size = size;
4350 static void R_Shadow_DrawModelShadowMaps(void)
4353 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4354 entity_render_t *ent;
4355 vec3_t relativelightorigin;
4356 vec3_t relativelightdirection, relativeforward, relativeright;
4357 vec3_t relativeshadowmins, relativeshadowmaxs;
4358 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4359 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4361 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4362 r_viewport_t viewport;
4364 size = r_shadow_shadowmapatlas_modelshadows_size;
4365 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4366 radius = 0.5f / scale;
4367 nearclip = -r_shadows_throwdistance.value;
4368 farclip = r_shadows_throwdistance.value;
4369 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);
4371 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4372 r_shadow_modelshadowmap_parameters[0] = size;
4373 r_shadow_modelshadowmap_parameters[1] = size;
4374 r_shadow_modelshadowmap_parameters[2] = 1.0;
4375 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4376 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4377 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4378 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4379 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4380 r_shadow_usingshadowmaportho = true;
4382 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4383 VectorCopy(prvmshadowdir, shadowdir);
4384 VectorNormalize(shadowdir);
4385 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4386 VectorCopy(prvmshadowfocus, shadowfocus);
4387 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4388 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4389 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4390 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4391 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4392 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4393 if (fabs(dot1) <= fabs(dot2))
4394 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4396 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4397 VectorNormalize(shadowforward);
4398 VectorM(scale, shadowforward, &m[0]);
4399 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4401 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4402 CrossProduct(shadowdir, shadowforward, shadowright);
4403 VectorM(scale, shadowright, &m[4]);
4404 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4405 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4406 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4407 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4408 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4409 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);
4410 R_SetViewport(&viewport);
4412 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4414 // render into a slightly restricted region so that the borders of the
4415 // shadowmap area fade away, rather than streaking across everything
4416 // outside the usable area
4417 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4419 for (i = 0;i < r_shadow_nummodelshadows;i++)
4421 ent = r_shadow_modelshadows[i];
4422 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4423 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4424 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4425 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4426 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4427 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4428 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4429 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4430 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4431 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4432 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4433 RSurf_ActiveModelEntity(ent, false, false, false);
4434 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4435 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4441 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4443 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4445 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4446 Cvar_SetValueQuick(&r_test, 0);
4451 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4452 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4453 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4454 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4455 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4456 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4459 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4462 vec3_t centerorigin;
4466 // if it's too close, skip it
4467 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4469 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4472 if (usequery && r_numqueries + 2 <= r_maxqueries)
4474 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4475 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4476 // 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
4477 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4479 switch(vid.renderpath)
4481 case RENDERPATH_GL32:
4482 case RENDERPATH_GLES2:
4485 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4486 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4487 GL_DepthFunc(GL_ALWAYS);
4488 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4489 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4490 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4491 qglEndQuery(GL_SAMPLES_PASSED);
4492 GL_DepthFunc(GL_LEQUAL);
4493 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4494 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4495 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4496 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4497 qglEndQuery(GL_SAMPLES_PASSED);
4503 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4506 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4508 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4511 unsigned int occlude = 0;
4513 // now we have to check the query result
4514 if (rtlight->corona_queryindex_visiblepixels)
4516 switch(vid.renderpath)
4518 case RENDERPATH_GL32:
4519 case RENDERPATH_GLES2:
4521 // store the pixel counts into a uniform buffer for the shader to
4522 // use - we'll never know the results on the cpu without
4523 // synchronizing and we don't want that
4524 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4525 if (!r_shadow_occlusion_buf) {
4526 qglGenBuffers(1, &r_shadow_occlusion_buf);
4527 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4528 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4530 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4532 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4533 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4534 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4535 occlude = MATERIALFLAG_OCCLUDE;
4536 cscale *= rtlight->corona_visibility;
4546 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4549 VectorScale(rtlight->currentcolor, cscale, color);
4550 if (VectorLength(color) > (1.0f / 256.0f))
4553 qboolean negated = (color[0] + color[1] + color[2] < 0);
4556 VectorNegate(color, color);
4557 GL_BlendEquationSubtract(true);
4559 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4560 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);
4561 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4563 GL_BlendEquationSubtract(false);
4567 void R_Shadow_DrawCoronas(void)
4570 qboolean usequery = false;
4575 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4577 if (r_fb.water.renderingscene)
4579 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4580 R_EntityMatrix(&identitymatrix);
4582 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4584 // check occlusion of coronas, using occlusion queries or raytraces
4586 switch (vid.renderpath)
4588 case RENDERPATH_GL32:
4589 case RENDERPATH_GLES2:
4590 usequery = r_coronas_occlusionquery.integer;
4594 GL_ColorMask(0,0,0,0);
4595 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4596 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4599 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4600 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4602 qglGenQueries(r_maxqueries - i, r_queries + i);
4605 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4606 GL_BlendFunc(GL_ONE, GL_ZERO);
4607 GL_CullFace(GL_NONE);
4608 GL_DepthMask(false);
4609 GL_DepthRange(0, 1);
4610 GL_PolygonOffset(0, 0);
4612 R_Mesh_ResetTextureState();
4613 R_SetupShader_Generic_NoTexture(false, false);
4618 for (lightindex = 0;lightindex < range;lightindex++)
4620 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4623 rtlight = &light->rtlight;
4624 rtlight->corona_visibility = 0;
4625 rtlight->corona_queryindex_visiblepixels = 0;
4626 rtlight->corona_queryindex_allpixels = 0;
4627 if (!(rtlight->flags & flag))
4629 if (rtlight->corona <= 0)
4631 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4633 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4635 for (i = 0;i < r_refdef.scene.numlights;i++)
4637 rtlight = r_refdef.scene.lights[i];
4638 rtlight->corona_visibility = 0;
4639 rtlight->corona_queryindex_visiblepixels = 0;
4640 rtlight->corona_queryindex_allpixels = 0;
4641 if (!(rtlight->flags & flag))
4643 if (rtlight->corona <= 0)
4645 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4648 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4650 // now draw the coronas using the query data for intensity info
4651 for (lightindex = 0;lightindex < range;lightindex++)
4653 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4656 rtlight = &light->rtlight;
4657 if (rtlight->corona_visibility <= 0)
4659 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4661 for (i = 0;i < r_refdef.scene.numlights;i++)
4663 rtlight = r_refdef.scene.lights[i];
4664 if (rtlight->corona_visibility <= 0)
4666 if (gl_flashblend.integer)
4667 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4669 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4675 static dlight_t *R_Shadow_NewWorldLight(void)
4677 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4680 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)
4684 // 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
4686 // validate parameters
4690 // copy to light properties
4691 VectorCopy(origin, light->origin);
4692 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4693 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4694 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4696 light->color[0] = max(color[0], 0);
4697 light->color[1] = max(color[1], 0);
4698 light->color[2] = max(color[2], 0);
4700 light->color[0] = color[0];
4701 light->color[1] = color[1];
4702 light->color[2] = color[2];
4703 light->radius = max(radius, 0);
4704 light->style = style;
4705 light->shadow = shadowenable;
4706 light->corona = corona;
4707 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4708 light->coronasizescale = coronasizescale;
4709 light->ambientscale = ambientscale;
4710 light->diffusescale = diffusescale;
4711 light->specularscale = specularscale;
4712 light->flags = flags;
4714 // update renderable light data
4715 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4716 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);
4719 static void R_Shadow_FreeWorldLight(dlight_t *light)
4721 if (r_shadow_selectedlight == light)
4722 r_shadow_selectedlight = NULL;
4723 R_RTLight_Uncompile(&light->rtlight);
4724 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4727 void R_Shadow_ClearWorldLights(void)
4731 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4732 for (lightindex = 0;lightindex < range;lightindex++)
4734 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4736 R_Shadow_FreeWorldLight(light);
4738 r_shadow_selectedlight = NULL;
4741 static void R_Shadow_SelectLight(dlight_t *light)
4743 if (r_shadow_selectedlight)
4744 r_shadow_selectedlight->selected = false;
4745 r_shadow_selectedlight = light;
4746 if (r_shadow_selectedlight)
4747 r_shadow_selectedlight->selected = true;
4750 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4752 // this is never batched (there can be only one)
4754 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4755 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4756 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4759 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4764 skinframe_t *skinframe;
4767 // this is never batched (due to the ent parameter changing every time)
4768 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4769 const dlight_t *light = (dlight_t *)ent;
4772 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4775 VectorScale(light->color, intensity, spritecolor);
4776 if (VectorLength(spritecolor) < 0.1732f)
4777 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4778 if (VectorLength(spritecolor) > 1.0f)
4779 VectorNormalize(spritecolor);
4781 // draw light sprite
4782 if (light->cubemapname[0] && !light->shadow)
4783 skinframe = r_editlights_sprcubemapnoshadowlight;
4784 else if (light->cubemapname[0])
4785 skinframe = r_editlights_sprcubemaplight;
4786 else if (!light->shadow)
4787 skinframe = r_editlights_sprnoshadowlight;
4789 skinframe = r_editlights_sprlight;
4791 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);
4792 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4794 // draw selection sprite if light is selected
4795 if (light->selected)
4797 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4798 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4799 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4803 void R_Shadow_DrawLightSprites(void)
4807 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4808 for (lightindex = 0;lightindex < range;lightindex++)
4810 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4812 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4814 if (!r_editlights_lockcursor)
4815 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4818 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4823 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4824 if (lightindex >= range)
4826 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4829 rtlight = &light->rtlight;
4830 //if (!(rtlight->flags & flag))
4832 VectorCopy(rtlight->shadoworigin, origin);
4833 *radius = rtlight->radius;
4834 VectorCopy(rtlight->color, color);
4838 static void R_Shadow_SelectLightInView(void)
4840 float bestrating, rating, temp[3];
4844 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4848 if (r_editlights_lockcursor)
4850 for (lightindex = 0;lightindex < range;lightindex++)
4852 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4855 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4856 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4859 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4860 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)
4862 bestrating = rating;
4867 R_Shadow_SelectLight(best);
4870 void R_Shadow_LoadWorldLights(void)
4872 int n, a, style, shadow, flags;
4873 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4874 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4875 if (cl.worldmodel == NULL)
4877 Con_Print("No map loaded.\n");
4880 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4881 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4891 for (;COM_Parse(t, true) && strcmp(
4892 if (COM_Parse(t, true))
4894 if (com_token[0] == '!')
4897 origin[0] = atof(com_token+1);
4900 origin[0] = atof(com_token);
4905 while (*s && *s != '\n' && *s != '\r')
4911 // check for modifier flags
4918 #if _MSC_VER >= 1400
4919 #define sscanf sscanf_s
4921 cubemapname[sizeof(cubemapname)-1] = 0;
4922 #if MAX_QPATH != 128
4923 #error update this code if MAX_QPATH changes
4925 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
4926 #if _MSC_VER >= 1400
4927 , (unsigned int)sizeof(cubemapname)
4929 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4932 flags = LIGHTFLAG_REALTIMEMODE;
4940 coronasizescale = 0.25f;
4942 VectorClear(angles);
4945 if (a < 9 || !strcmp(cubemapname, "\"\""))
4947 // remove quotes on cubemapname
4948 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4951 namelen = strlen(cubemapname) - 2;
4952 memmove(cubemapname, cubemapname + 1, namelen);
4953 cubemapname[namelen] = '\0';
4957 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);
4960 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4968 Con_Printf("invalid rtlights file \"%s\"\n", name);
4969 Mem_Free(lightsstring);
4973 void R_Shadow_SaveWorldLights(void)
4977 size_t bufchars, bufmaxchars;
4979 char name[MAX_QPATH];
4980 char line[MAX_INPUTLINE];
4981 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4982 // I hate lines which are 3 times my screen size :( --blub
4985 if (cl.worldmodel == NULL)
4987 Con_Print("No map loaded.\n");
4990 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4991 bufchars = bufmaxchars = 0;
4993 for (lightindex = 0;lightindex < range;lightindex++)
4995 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4998 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4999 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);
5000 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5001 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]);
5003 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);
5004 if (bufchars + strlen(line) > bufmaxchars)
5006 bufmaxchars = bufchars + strlen(line) + 2048;
5008 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5012 memcpy(buf, oldbuf, bufchars);
5018 memcpy(buf + bufchars, line, strlen(line));
5019 bufchars += strlen(line);
5023 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5028 void R_Shadow_LoadLightsFile(void)
5031 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5032 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5033 if (cl.worldmodel == NULL)
5035 Con_Print("No map loaded.\n");
5038 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5039 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5047 while (*s && *s != '\n' && *s != '\r')
5053 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);
5057 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);
5060 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5061 radius = bound(15, radius, 4096);
5062 VectorScale(color, (2.0f / (8388608.0f)), color);
5063 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5071 Con_Printf("invalid lights file \"%s\"\n", name);
5072 Mem_Free(lightsstring);
5076 // tyrlite/hmap2 light types in the delay field
5077 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5079 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5091 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5092 char key[256], value[MAX_INPUTLINE];
5095 if (cl.worldmodel == NULL)
5097 Con_Print("No map loaded.\n");
5100 // try to load a .ent file first
5101 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5102 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5103 // and if that is not found, fall back to the bsp file entity string
5105 data = cl.worldmodel->brush.entities;
5108 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5110 type = LIGHTTYPE_MINUSX;
5111 origin[0] = origin[1] = origin[2] = 0;
5112 originhack[0] = originhack[1] = originhack[2] = 0;
5113 angles[0] = angles[1] = angles[2] = 0;
5114 color[0] = color[1] = color[2] = 1;
5115 light[0] = light[1] = light[2] = 1;light[3] = 300;
5116 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5126 if (!COM_ParseToken_Simple(&data, false, false, true))
5128 if (com_token[0] == '}')
5129 break; // end of entity
5130 if (com_token[0] == '_')
5131 strlcpy(key, com_token + 1, sizeof(key));
5133 strlcpy(key, com_token, sizeof(key));
5134 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5135 key[strlen(key)-1] = 0;
5136 if (!COM_ParseToken_Simple(&data, false, false, true))
5138 strlcpy(value, com_token, sizeof(value));
5140 // now that we have the key pair worked out...
5141 if (!strcmp("light", key))
5143 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5147 light[0] = vec[0] * (1.0f / 256.0f);
5148 light[1] = vec[0] * (1.0f / 256.0f);
5149 light[2] = vec[0] * (1.0f / 256.0f);
5155 light[0] = vec[0] * (1.0f / 255.0f);
5156 light[1] = vec[1] * (1.0f / 255.0f);
5157 light[2] = vec[2] * (1.0f / 255.0f);
5161 else if (!strcmp("delay", key))
5163 else if (!strcmp("origin", key))
5164 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5165 else if (!strcmp("angle", key))
5166 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5167 else if (!strcmp("angles", key))
5168 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5169 else if (!strcmp("color", key))
5170 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5171 else if (!strcmp("wait", key))
5172 fadescale = atof(value);
5173 else if (!strcmp("classname", key))
5175 if (!strncmp(value, "light", 5))
5178 if (!strcmp(value, "light_fluoro"))
5183 overridecolor[0] = 1;
5184 overridecolor[1] = 1;
5185 overridecolor[2] = 1;
5187 if (!strcmp(value, "light_fluorospark"))
5192 overridecolor[0] = 1;
5193 overridecolor[1] = 1;
5194 overridecolor[2] = 1;
5196 if (!strcmp(value, "light_globe"))
5201 overridecolor[0] = 1;
5202 overridecolor[1] = 0.8;
5203 overridecolor[2] = 0.4;
5205 if (!strcmp(value, "light_flame_large_yellow"))
5210 overridecolor[0] = 1;
5211 overridecolor[1] = 0.5;
5212 overridecolor[2] = 0.1;
5214 if (!strcmp(value, "light_flame_small_yellow"))
5219 overridecolor[0] = 1;
5220 overridecolor[1] = 0.5;
5221 overridecolor[2] = 0.1;
5223 if (!strcmp(value, "light_torch_small_white"))
5228 overridecolor[0] = 1;
5229 overridecolor[1] = 0.5;
5230 overridecolor[2] = 0.1;
5232 if (!strcmp(value, "light_torch_small_walltorch"))
5237 overridecolor[0] = 1;
5238 overridecolor[1] = 0.5;
5239 overridecolor[2] = 0.1;
5243 else if (!strcmp("style", key))
5244 style = atoi(value);
5245 else if (!strcmp("skin", key))
5246 skin = (int)atof(value);
5247 else if (!strcmp("pflags", key))
5248 pflags = (int)atof(value);
5249 //else if (!strcmp("effects", key))
5250 // effects = (int)atof(value);
5251 else if (cl.worldmodel->type == mod_brushq3)
5253 if (!strcmp("scale", key))
5254 lightscale = atof(value);
5255 if (!strcmp("fade", key))
5256 fadescale = atof(value);
5261 if (lightscale <= 0)
5265 if (color[0] == color[1] && color[0] == color[2])
5267 color[0] *= overridecolor[0];
5268 color[1] *= overridecolor[1];
5269 color[2] *= overridecolor[2];
5271 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5272 color[0] = color[0] * light[0];
5273 color[1] = color[1] * light[1];
5274 color[2] = color[2] * light[2];
5277 case LIGHTTYPE_MINUSX:
5279 case LIGHTTYPE_RECIPX:
5281 VectorScale(color, (1.0f / 16.0f), color);
5283 case LIGHTTYPE_RECIPXX:
5285 VectorScale(color, (1.0f / 16.0f), color);
5288 case LIGHTTYPE_NONE:
5292 case LIGHTTYPE_MINUSXX:
5295 VectorAdd(origin, originhack, origin);
5297 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);
5300 Mem_Free(entfiledata);
5304 static void R_Shadow_SetCursorLocationForView(void)
5307 vec3_t dest, endpos;
5309 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5310 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5311 if (trace.fraction < 1)
5313 dist = trace.fraction * r_editlights_cursordistance.value;
5314 push = r_editlights_cursorpushback.value;
5318 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5319 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5323 VectorClear( endpos );
5325 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5326 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5327 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5330 void R_Shadow_UpdateWorldLightSelection(void)
5332 if (r_editlights.integer)
5334 R_Shadow_SetCursorLocationForView();
5335 R_Shadow_SelectLightInView();
5338 R_Shadow_SelectLight(NULL);
5341 static void R_Shadow_EditLights_Clear_f(cmd_state_t *cmd)
5343 R_Shadow_ClearWorldLights();
5346 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd)
5350 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5351 R_Shadow_ClearWorldLights();
5352 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5354 R_Shadow_LoadWorldLights();
5355 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5356 R_Shadow_LoadLightsFile();
5358 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5360 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5361 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5365 static void R_Shadow_EditLights_Save_f(cmd_state_t *cmd)
5369 R_Shadow_SaveWorldLights();
5372 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(cmd_state_t *cmd)
5374 R_Shadow_ClearWorldLights();
5375 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5378 static void R_Shadow_EditLights_ImportLightsFile_f(cmd_state_t *cmd)
5380 R_Shadow_ClearWorldLights();
5381 R_Shadow_LoadLightsFile();
5384 static void R_Shadow_EditLights_Spawn_f(cmd_state_t *cmd)
5387 if (!r_editlights.integer)
5389 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5392 if (Cmd_Argc(cmd) != 1)
5394 Con_Print("r_editlights_spawn does not take parameters\n");
5397 color[0] = color[1] = color[2] = 1;
5398 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5401 static void R_Shadow_EditLights_Edit_f(cmd_state_t *cmd)
5403 vec3_t origin, angles, color;
5404 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5405 int style, shadows, flags, normalmode, realtimemode;
5406 char cubemapname[MAX_INPUTLINE];
5407 if (!r_editlights.integer)
5409 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5412 if (!r_shadow_selectedlight)
5414 Con_Print("No selected light.\n");
5417 VectorCopy(r_shadow_selectedlight->origin, origin);
5418 VectorCopy(r_shadow_selectedlight->angles, angles);
5419 VectorCopy(r_shadow_selectedlight->color, color);
5420 radius = r_shadow_selectedlight->radius;
5421 style = r_shadow_selectedlight->style;
5422 if (*r_shadow_selectedlight->cubemapname)
5423 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5426 shadows = r_shadow_selectedlight->shadow;
5427 corona = r_shadow_selectedlight->corona;
5428 coronasizescale = r_shadow_selectedlight->coronasizescale;
5429 ambientscale = r_shadow_selectedlight->ambientscale;
5430 diffusescale = r_shadow_selectedlight->diffusescale;
5431 specularscale = r_shadow_selectedlight->specularscale;
5432 flags = r_shadow_selectedlight->flags;
5433 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5434 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5435 if (!strcmp(Cmd_Argv(cmd, 1), "origin"))
5437 if (Cmd_Argc(cmd) != 5)
5439 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5442 origin[0] = atof(Cmd_Argv(cmd, 2));
5443 origin[1] = atof(Cmd_Argv(cmd, 3));
5444 origin[2] = atof(Cmd_Argv(cmd, 4));
5446 else if (!strcmp(Cmd_Argv(cmd, 1), "originscale"))
5448 if (Cmd_Argc(cmd) != 5)
5450 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5453 origin[0] *= atof(Cmd_Argv(cmd, 2));
5454 origin[1] *= atof(Cmd_Argv(cmd, 3));
5455 origin[2] *= atof(Cmd_Argv(cmd, 4));
5457 else if (!strcmp(Cmd_Argv(cmd, 1), "originx"))
5459 if (Cmd_Argc(cmd) != 3)
5461 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5464 origin[0] = atof(Cmd_Argv(cmd, 2));
5466 else if (!strcmp(Cmd_Argv(cmd, 1), "originy"))
5468 if (Cmd_Argc(cmd) != 3)
5470 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5473 origin[1] = atof(Cmd_Argv(cmd, 2));
5475 else if (!strcmp(Cmd_Argv(cmd, 1), "originz"))
5477 if (Cmd_Argc(cmd) != 3)
5479 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5482 origin[2] = atof(Cmd_Argv(cmd, 2));
5484 else if (!strcmp(Cmd_Argv(cmd, 1), "move"))
5486 if (Cmd_Argc(cmd) != 5)
5488 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5491 origin[0] += atof(Cmd_Argv(cmd, 2));
5492 origin[1] += atof(Cmd_Argv(cmd, 3));
5493 origin[2] += atof(Cmd_Argv(cmd, 4));
5495 else if (!strcmp(Cmd_Argv(cmd, 1), "movex"))
5497 if (Cmd_Argc(cmd) != 3)
5499 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5502 origin[0] += atof(Cmd_Argv(cmd, 2));
5504 else if (!strcmp(Cmd_Argv(cmd, 1), "movey"))
5506 if (Cmd_Argc(cmd) != 3)
5508 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5511 origin[1] += atof(Cmd_Argv(cmd, 2));
5513 else if (!strcmp(Cmd_Argv(cmd, 1), "movez"))
5515 if (Cmd_Argc(cmd) != 3)
5517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5520 origin[2] += atof(Cmd_Argv(cmd, 2));
5522 else if (!strcmp(Cmd_Argv(cmd, 1), "angles"))
5524 if (Cmd_Argc(cmd) != 5)
5526 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5529 angles[0] = atof(Cmd_Argv(cmd, 2));
5530 angles[1] = atof(Cmd_Argv(cmd, 3));
5531 angles[2] = atof(Cmd_Argv(cmd, 4));
5533 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesx"))
5535 if (Cmd_Argc(cmd) != 3)
5537 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5540 angles[0] = atof(Cmd_Argv(cmd, 2));
5542 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesy"))
5544 if (Cmd_Argc(cmd) != 3)
5546 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5549 angles[1] = atof(Cmd_Argv(cmd, 2));
5551 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesz"))
5553 if (Cmd_Argc(cmd) != 3)
5555 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5558 angles[2] = atof(Cmd_Argv(cmd, 2));
5560 else if (!strcmp(Cmd_Argv(cmd, 1), "color"))
5562 if (Cmd_Argc(cmd) != 5)
5564 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(cmd, 1));
5567 color[0] = atof(Cmd_Argv(cmd, 2));
5568 color[1] = atof(Cmd_Argv(cmd, 3));
5569 color[2] = atof(Cmd_Argv(cmd, 4));
5571 else if (!strcmp(Cmd_Argv(cmd, 1), "radius"))
5573 if (Cmd_Argc(cmd) != 3)
5575 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5578 radius = atof(Cmd_Argv(cmd, 2));
5580 else if (!strcmp(Cmd_Argv(cmd, 1), "colorscale"))
5582 if (Cmd_Argc(cmd) == 3)
5584 double scale = atof(Cmd_Argv(cmd, 2));
5591 if (Cmd_Argc(cmd) != 5)
5593 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(cmd, 1));
5596 color[0] *= atof(Cmd_Argv(cmd, 2));
5597 color[1] *= atof(Cmd_Argv(cmd, 3));
5598 color[2] *= atof(Cmd_Argv(cmd, 4));
5601 else if (!strcmp(Cmd_Argv(cmd, 1), "radiusscale") || !strcmp(Cmd_Argv(cmd, 1), "sizescale"))
5603 if (Cmd_Argc(cmd) != 3)
5605 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5608 radius *= atof(Cmd_Argv(cmd, 2));
5610 else if (!strcmp(Cmd_Argv(cmd, 1), "style"))
5612 if (Cmd_Argc(cmd) != 3)
5614 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5617 style = atoi(Cmd_Argv(cmd, 2));
5619 else if (!strcmp(Cmd_Argv(cmd, 1), "cubemap"))
5621 if (Cmd_Argc(cmd) > 3)
5623 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5626 if (Cmd_Argc(cmd) == 3)
5627 strlcpy(cubemapname, Cmd_Argv(cmd, 2), sizeof(cubemapname));
5631 else if (!strcmp(Cmd_Argv(cmd, 1), "shadows"))
5633 if (Cmd_Argc(cmd) != 3)
5635 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5638 shadows = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5640 else if (!strcmp(Cmd_Argv(cmd, 1), "corona"))
5642 if (Cmd_Argc(cmd) != 3)
5644 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5647 corona = atof(Cmd_Argv(cmd, 2));
5649 else if (!strcmp(Cmd_Argv(cmd, 1), "coronasize"))
5651 if (Cmd_Argc(cmd) != 3)
5653 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5656 coronasizescale = atof(Cmd_Argv(cmd, 2));
5658 else if (!strcmp(Cmd_Argv(cmd, 1), "ambient"))
5660 if (Cmd_Argc(cmd) != 3)
5662 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5665 ambientscale = atof(Cmd_Argv(cmd, 2));
5667 else if (!strcmp(Cmd_Argv(cmd, 1), "diffuse"))
5669 if (Cmd_Argc(cmd) != 3)
5671 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5674 diffusescale = atof(Cmd_Argv(cmd, 2));
5676 else if (!strcmp(Cmd_Argv(cmd, 1), "specular"))
5678 if (Cmd_Argc(cmd) != 3)
5680 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5683 specularscale = atof(Cmd_Argv(cmd, 2));
5685 else if (!strcmp(Cmd_Argv(cmd, 1), "normalmode"))
5687 if (Cmd_Argc(cmd) != 3)
5689 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5692 normalmode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5694 else if (!strcmp(Cmd_Argv(cmd, 1), "realtimemode"))
5696 if (Cmd_Argc(cmd) != 3)
5698 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5701 realtimemode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5705 Con_Print("usage: r_editlights_edit [property] [value]\n");
5706 Con_Print("Selected light's properties:\n");
5707 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5708 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5709 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5710 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5711 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5712 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5713 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5714 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5715 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5716 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5717 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5718 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5719 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5720 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5723 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5724 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5727 static void R_Shadow_EditLights_EditAll_f(cmd_state_t *cmd)
5730 dlight_t *light, *oldselected;
5733 if (!r_editlights.integer)
5735 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5739 oldselected = r_shadow_selectedlight;
5740 // EditLights doesn't seem to have a "remove" command or something so:
5741 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5742 for (lightindex = 0;lightindex < range;lightindex++)
5744 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5747 R_Shadow_SelectLight(light);
5748 R_Shadow_EditLights_Edit_f(&cmd_client);
5750 // return to old selected (to not mess editing once selection is locked)
5751 R_Shadow_SelectLight(oldselected);
5754 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5756 int lightnumber, lightcount;
5757 size_t lightindex, range;
5762 if (!r_editlights.integer)
5765 // update cvars so QC can query them
5766 if (r_shadow_selectedlight)
5768 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5769 Cvar_SetQuick(&r_editlights_current_origin, temp);
5770 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5771 Cvar_SetQuick(&r_editlights_current_angles, temp);
5772 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5773 Cvar_SetQuick(&r_editlights_current_color, temp);
5774 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5775 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5776 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5777 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5778 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5779 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5780 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5781 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5782 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5783 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5784 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5787 // draw properties on screen
5788 if (!r_editlights_drawproperties.integer)
5790 x = vid_conwidth.value - 320;
5792 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5795 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5796 for (lightindex = 0;lightindex < range;lightindex++)
5798 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5801 if (light == r_shadow_selectedlight)
5802 lightnumber = (int)lightindex;
5805 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;
5806 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;
5808 if (r_shadow_selectedlight == NULL)
5810 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;
5811 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;
5812 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;
5813 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;
5814 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;
5815 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;
5816 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;
5817 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;
5818 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;
5819 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;
5820 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;
5821 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;
5822 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;
5823 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;
5824 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;
5826 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;
5827 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;
5828 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;
5829 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;
5830 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;
5831 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;
5832 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;
5833 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;
5834 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;
5835 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;
5838 static void R_Shadow_EditLights_ToggleShadow_f(cmd_state_t *cmd)
5840 if (!r_editlights.integer)
5842 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5845 if (!r_shadow_selectedlight)
5847 Con_Print("No selected light.\n");
5850 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);
5853 static void R_Shadow_EditLights_ToggleCorona_f(cmd_state_t *cmd)
5855 if (!r_editlights.integer)
5857 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5860 if (!r_shadow_selectedlight)
5862 Con_Print("No selected light.\n");
5865 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);
5868 static void R_Shadow_EditLights_Remove_f(cmd_state_t *cmd)
5870 if (!r_editlights.integer)
5872 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5875 if (!r_shadow_selectedlight)
5877 Con_Print("No selected light.\n");
5880 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5881 r_shadow_selectedlight = NULL;
5884 static void R_Shadow_EditLights_Help_f(cmd_state_t *cmd)
5887 "Documentation on r_editlights system:\n"
5889 "r_editlights : enable/disable editing mode\n"
5890 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5891 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5892 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5893 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5894 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5896 "r_editlights_help : this help\n"
5897 "r_editlights_clear : remove all lights\n"
5898 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5899 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5900 "r_editlights_save : save to .rtlights file\n"
5901 "r_editlights_spawn : create a light with default settings\n"
5902 "r_editlights_edit command : edit selected light - more documentation below\n"
5903 "r_editlights_remove : remove selected light\n"
5904 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5905 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5906 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5908 "origin x y z : set light location\n"
5909 "originx x: set x component of light location\n"
5910 "originy y: set y component of light location\n"
5911 "originz z: set z component of light location\n"
5912 "move x y z : adjust light location\n"
5913 "movex x: adjust x component of light location\n"
5914 "movey y: adjust y component of light location\n"
5915 "movez z: adjust z component of light location\n"
5916 "angles x y z : set light angles\n"
5917 "anglesx x: set x component of light angles\n"
5918 "anglesy y: set y component of light angles\n"
5919 "anglesz z: set z component of light angles\n"
5920 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5921 "radius radius : set radius (size) of light\n"
5922 "colorscale grey : multiply color of light (1 does nothing)\n"
5923 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5924 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5925 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5926 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5927 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5928 "cubemap basename : set filter cubemap of light\n"
5929 "shadows 1/0 : turn on/off shadows\n"
5930 "corona n : set corona intensity\n"
5931 "coronasize n : set corona size (0-1)\n"
5932 "ambient n : set ambient intensity (0-1)\n"
5933 "diffuse n : set diffuse intensity (0-1)\n"
5934 "specular n : set specular intensity (0-1)\n"
5935 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5936 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5937 "<nothing> : print light properties to console\n"
5941 static void R_Shadow_EditLights_CopyInfo_f(cmd_state_t *cmd)
5943 if (!r_editlights.integer)
5945 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5948 if (!r_shadow_selectedlight)
5950 Con_Print("No selected light.\n");
5953 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5954 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5955 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5956 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5957 if (*r_shadow_selectedlight->cubemapname)
5958 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5960 r_shadow_bufferlight.cubemapname[0] = 0;
5961 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5962 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5963 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5964 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5965 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5966 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5967 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5970 static void R_Shadow_EditLights_PasteInfo_f(cmd_state_t *cmd)
5972 if (!r_editlights.integer)
5974 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5977 if (!r_shadow_selectedlight)
5979 Con_Print("No selected light.\n");
5982 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);
5985 static void R_Shadow_EditLights_Lock_f(cmd_state_t *cmd)
5987 if (!r_editlights.integer)
5989 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5992 if (r_editlights_lockcursor)
5994 r_editlights_lockcursor = false;
5997 if (!r_shadow_selectedlight)
5999 Con_Print("No selected light to lock on.\n");
6002 r_editlights_lockcursor = true;
6005 static void R_Shadow_EditLights_Init(void)
6007 Cvar_RegisterVariable(&r_editlights);
6008 Cvar_RegisterVariable(&r_editlights_cursordistance);
6009 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6010 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6011 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6012 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6013 Cvar_RegisterVariable(&r_editlights_drawproperties);
6014 Cvar_RegisterVariable(&r_editlights_current_origin);
6015 Cvar_RegisterVariable(&r_editlights_current_angles);
6016 Cvar_RegisterVariable(&r_editlights_current_color);
6017 Cvar_RegisterVariable(&r_editlights_current_radius);
6018 Cvar_RegisterVariable(&r_editlights_current_corona);
6019 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6020 Cvar_RegisterVariable(&r_editlights_current_style);
6021 Cvar_RegisterVariable(&r_editlights_current_shadows);
6022 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6023 Cvar_RegisterVariable(&r_editlights_current_ambient);
6024 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6025 Cvar_RegisterVariable(&r_editlights_current_specular);
6026 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6027 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6028 Cmd_AddCommand(&cmd_client, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6029 Cmd_AddCommand(&cmd_client, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6030 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)");
6031 Cmd_AddCommand(&cmd_client, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6032 Cmd_AddCommand(&cmd_client, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6033 Cmd_AddCommand(&cmd_client, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6034 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)");
6035 Cmd_AddCommand(&cmd_client, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6036 Cmd_AddCommand(&cmd_client, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6037 Cmd_AddCommand(&cmd_client, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6038 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)");
6039 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)");
6040 Cmd_AddCommand(&cmd_client, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6041 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)");
6042 Cmd_AddCommand(&cmd_client, "r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6048 =============================================================================
6052 =============================================================================
6055 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6057 int i, numlights, flag, q;
6060 float relativepoint[3];
6065 float sa[3], sx[3], sy[3], sz[3], sd[3];
6068 // use first order spherical harmonics to combine directional lights
6069 for (q = 0; q < 3; q++)
6070 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6072 if (flags & LP_LIGHTMAP)
6074 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6076 float tempambient[3];
6077 for (q = 0; q < 3; q++)
6078 tempambient[q] = color[q] = relativepoint[q] = 0;
6079 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6080 // calculate a weighted average light direction as well
6081 intensity = VectorLength(color);
6082 for (q = 0; q < 3; q++)
6084 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6085 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6086 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6087 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6088 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6093 // unlit map - fullbright but scaled by lightmapintensity
6094 for (q = 0; q < 3; q++)
6095 sa[q] += lightmapintensity;
6099 if (flags & LP_RTWORLD)
6101 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6102 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6103 for (i = 0; i < numlights; i++)
6105 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6108 light = &dlight->rtlight;
6109 if (!(light->flags & flag))
6112 lightradius2 = light->radius * light->radius;
6113 VectorSubtract(light->shadoworigin, p, relativepoint);
6114 dist2 = VectorLength2(relativepoint);
6115 if (dist2 >= lightradius2)
6117 dist = sqrt(dist2) / light->radius;
6118 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6119 if (intensity <= 0.0f)
6121 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)
6123 for (q = 0; q < 3; q++)
6124 color[q] = light->currentcolor[q] * intensity;
6125 intensity = VectorLength(color);
6126 VectorNormalize(relativepoint);
6127 for (q = 0; q < 3; q++)
6129 sa[q] += 0.5f * color[q];
6130 sx[q] += relativepoint[0] * color[q];
6131 sy[q] += relativepoint[1] * color[q];
6132 sz[q] += relativepoint[2] * color[q];
6133 sd[q] += intensity * relativepoint[q];
6136 // FIXME: sample bouncegrid too!
6139 if (flags & LP_DYNLIGHT)
6142 for (i = 0;i < r_refdef.scene.numlights;i++)
6144 light = r_refdef.scene.lights[i];
6146 lightradius2 = light->radius * light->radius;
6147 VectorSubtract(light->shadoworigin, p, relativepoint);
6148 dist2 = VectorLength2(relativepoint);
6149 if (dist2 >= lightradius2)
6151 dist = sqrt(dist2) / light->radius;
6152 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6153 if (intensity <= 0.0f)
6155 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)
6157 for (q = 0; q < 3; q++)
6158 color[q] = light->currentcolor[q] * intensity;
6159 intensity = VectorLength(color);
6160 VectorNormalize(relativepoint);
6161 for (q = 0; q < 3; q++)
6163 sa[q] += 0.5f * color[q];
6164 sx[q] += relativepoint[0] * color[q];
6165 sy[q] += relativepoint[1] * color[q];
6166 sz[q] += relativepoint[2] * color[q];
6167 sd[q] += intensity * relativepoint[q];
6172 // calculate the weighted-average light direction (bentnormal)
6173 for (q = 0; q < 3; q++)
6174 lightdir[q] = sd[q];
6175 VectorNormalize(lightdir);
6176 for (q = 0; q < 3; q++)
6178 // extract the diffuse color along the chosen direction and scale it
6179 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6180 // subtract some of diffuse from ambient
6181 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;