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, bias;
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;
1575 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1577 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1578 R_SetViewport(&viewport);
1579 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1580 flipped = (side & 1) ^ (side >> 2);
1581 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1582 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1584 if (r_shadow_shadowmap2ddepthbuffer)
1585 GL_ColorMask(1,1,1,1);
1587 GL_ColorMask(0,0,0,0);
1588 switch(vid.renderpath)
1590 case RENDERPATH_GL32:
1591 case RENDERPATH_GLES2:
1592 GL_CullFace(r_refdef.view.cullface_back);
1596 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1597 r_shadow_shadowmapside = side;
1600 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1602 R_Mesh_ResetTextureState();
1605 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1606 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1607 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1608 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1611 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1612 R_Shadow_RenderMode_Reset();
1613 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1615 GL_DepthFunc(GL_EQUAL);
1616 // do global setup needed for the chosen lighting mode
1617 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1618 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1619 r_shadow_usingshadowmap2d = shadowmapping;
1620 r_shadow_rendermode = r_shadow_lightingrendermode;
1623 static const unsigned short bboxelements[36] =
1633 static const float bboxpoints[8][3] =
1645 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1648 float vertex3f[8*3];
1649 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1650 // do global setup needed for the chosen lighting mode
1651 R_Shadow_RenderMode_Reset();
1652 r_shadow_rendermode = r_shadow_lightingrendermode;
1653 R_EntityMatrix(&identitymatrix);
1654 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1655 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1656 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1658 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1660 r_shadow_usingshadowmap2d = shadowmapping;
1662 // render the lighting
1663 R_SetupShader_DeferredLight(rsurface.rtlight);
1664 for (i = 0;i < 8;i++)
1665 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1666 GL_ColorMask(1,1,1,1);
1667 GL_DepthMask(false);
1668 GL_DepthRange(0, 1);
1669 GL_PolygonOffset(0, 0);
1671 GL_DepthFunc(GL_GREATER);
1672 GL_CullFace(r_refdef.view.cullface_back);
1673 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1674 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1677 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1679 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1686 // see if there are really any lights to render...
1687 if (enable && r_shadow_bouncegrid_static.integer)
1690 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1691 for (lightindex = 0;lightindex < range;lightindex++)
1693 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1694 if (!light || !(light->flags & flag))
1696 rtlight = &light->rtlight;
1697 // when static, we skip styled lights because they tend to change...
1698 if (rtlight->style > 0)
1700 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1701 if (!VectorLength2(lightcolor))
1711 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1713 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1714 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1715 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1716 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1718 // prevent any garbage in alignment padded areas as we'll be using memcmp
1719 memset(settings, 0, sizeof(*settings));
1721 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1722 settings->staticmode = s;
1723 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1724 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1725 settings->lightpathsize = bound(0.0f, r_shadow_bouncegrid_lightpathsize.value, 1024.0f);
1726 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1727 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1728 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1729 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1730 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1731 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1732 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1733 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) / 65536.0f;
1734 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1735 settings->energyperphoton = 4096.0f / quality;
1736 settings->spacing[0] = spacing;
1737 settings->spacing[1] = spacing;
1738 settings->spacing[2] = spacing;
1739 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1740 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1741 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1742 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1743 settings->subsamples = bound(1, r_shadow_bouncegrid_subsamples.integer, 4);
1745 // bound the values for sanity
1746 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1747 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1748 settings->maxbounce = bound(0, settings->maxbounce, 16);
1749 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1750 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1751 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1754 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1765 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1767 // get the spacing values
1768 spacing[0] = settings->spacing[0];
1769 spacing[1] = settings->spacing[1];
1770 spacing[2] = settings->spacing[2];
1771 ispacing[0] = 1.0f / spacing[0];
1772 ispacing[1] = 1.0f / spacing[1];
1773 ispacing[2] = 1.0f / spacing[2];
1775 // calculate texture size enclosing entire world bounds at the spacing
1776 if (r_refdef.scene.worldmodel)
1780 qboolean bounds_set = false;
1784 // calculate bounds enclosing world lights as they should be noticably tighter
1785 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1786 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1787 for (lightindex = 0;lightindex < range;lightindex++)
1789 const vec_t *rtlmins, *rtlmaxs;
1791 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1795 rtlight = &light->rtlight;
1796 rtlmins = rtlight->cullmins;
1797 rtlmaxs = rtlight->cullmaxs;
1801 VectorCopy(rtlmins, mins);
1802 VectorCopy(rtlmaxs, maxs);
1807 mins[0] = min(mins[0], rtlmins[0]);
1808 mins[1] = min(mins[1], rtlmins[1]);
1809 mins[2] = min(mins[2], rtlmins[2]);
1810 maxs[0] = max(maxs[0], rtlmaxs[0]);
1811 maxs[1] = max(maxs[1], rtlmaxs[1]);
1812 maxs[2] = max(maxs[2], rtlmaxs[2]);
1816 // limit to no larger than the world bounds
1817 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1818 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1819 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1820 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1821 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1822 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1824 VectorMA(mins, -2.0f, spacing, mins);
1825 VectorMA(maxs, 2.0f, spacing, maxs);
1829 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1830 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1832 VectorSubtract(maxs, mins, size);
1833 // now we can calculate the resolution we want
1834 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1835 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1836 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1837 // figure out the exact texture size (honoring power of 2 if required)
1838 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1839 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1840 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1841 size[0] = spacing[0] * resolution[0];
1842 size[1] = spacing[1] * resolution[1];
1843 size[2] = spacing[2] * resolution[2];
1845 // if dynamic we may or may not want to use the world bounds
1846 // if the dynamic size is smaller than the world bounds, use it instead
1847 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]))
1849 // we know the resolution we want
1850 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1851 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1852 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1853 // now we can calculate the texture size
1854 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1855 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1856 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1857 size[0] = spacing[0] * resolution[0];
1858 size[1] = spacing[1] * resolution[1];
1859 size[2] = spacing[2] * resolution[2];
1860 // center the rendering on the view
1861 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1862 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1863 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1866 // recalculate the maxs in case the resolution was not satisfactory
1867 VectorAdd(mins, size, maxs);
1869 // check if this changed the texture size
1870 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);
1871 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1872 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1873 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1874 VectorCopy(size, r_shadow_bouncegrid_state.size);
1875 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1876 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1877 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1879 // reallocate pixels for this update if needed...
1880 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1881 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1882 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1883 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1884 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1886 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1888 r_shadow_bouncegrid_state.highpixels = NULL;
1890 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1891 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1892 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1893 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1894 if (r_shadow_bouncegrid_state.photons) { Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL; }
1895 if (r_shadow_bouncegrid_state.photons_tasks) { Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL; }
1896 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
1898 r_shadow_bouncegrid_state.numpixels = numpixels;
1901 // update the bouncegrid matrix to put it in the world properly
1902 memset(m, 0, sizeof(m));
1903 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1904 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1905 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1906 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1907 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1908 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1910 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1913 static float R_Shadow_BounceGrid_RefractiveIndexAtPoint(vec3_t point)
1915 // check material at shadoworigin to see what the initial refractive index should be
1916 int hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
1917 int skipsupercontentsmask = 0;
1918 int skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
1919 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);
1920 if (trace.starttexture && (trace.starttexture->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)))
1921 return trace.starttexture->refractive_index;
1922 else if (trace.startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
1923 return 1.333f; // water
1925 return 1.0003f; // air
1928 // enumerate world rtlights and sum the overall amount of light in the world,
1929 // from that we can calculate a scaling factor to fairly distribute photons
1930 // to all the lights
1932 // this modifies rtlight->photoncolor and rtlight->photons
1933 static void R_Shadow_BounceGrid_AssignPhotons_Task(taskqueue_task_t *t)
1935 // get the range of light numbers we'll be looping over:
1936 // range = static lights
1937 // range1 = dynamic lights (optional)
1938 // range2 = range + range1
1939 unsigned int range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1940 unsigned int range1 = r_shadow_bouncegrid_state.settings.staticmode ? 0 : r_refdef.scene.numlights;
1941 unsigned int range2 = range + range1;
1942 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
1944 float normalphotonscaling;
1945 float photonscaling;
1946 float photonintensity;
1947 float photoncount = 0.0f;
1948 float lightintensity;
1954 unsigned int lightindex;
1959 float bounceminimumintensity2;
1960 float startrefractiveindex;
1962 randomseed_t randomseed;
1963 vec3_t baseshotcolor;
1965 normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1966 for (lightindex = 0;lightindex < range2;lightindex++)
1968 if (lightindex < range)
1970 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1973 rtlight = &light->rtlight;
1974 VectorClear(rtlight->bouncegrid_photoncolor);
1975 rtlight->bouncegrid_photons = 0;
1976 rtlight->bouncegrid_hits = 0;
1977 rtlight->bouncegrid_traces = 0;
1978 rtlight->bouncegrid_effectiveradius = 0;
1979 if (!(light->flags & flag))
1981 if (r_shadow_bouncegrid_state.settings.staticmode)
1983 // when static, we skip styled lights because they tend to change...
1984 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
1987 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
1992 rtlight = r_refdef.scene.lights[lightindex - range];
1993 VectorClear(rtlight->bouncegrid_photoncolor);
1994 rtlight->bouncegrid_photons = 0;
1995 rtlight->bouncegrid_hits = 0;
1996 rtlight->bouncegrid_traces = 0;
1997 rtlight->bouncegrid_effectiveradius = 0;
1999 // draw only visible lights (major speedup)
2000 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2001 cullmins[0] = rtlight->shadoworigin[0] - radius;
2002 cullmins[1] = rtlight->shadoworigin[1] - radius;
2003 cullmins[2] = rtlight->shadoworigin[2] - radius;
2004 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2005 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2006 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2007 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2008 if (!r_shadow_bouncegrid_state.settings.staticmode)
2010 // skip if the expanded light box does not touch any visible leafs
2011 if (r_refdef.scene.worldmodel
2012 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2013 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2015 // skip if the expanded light box is not visible to traceline
2016 // note that PrepareLight already did this check but for a smaller box, so we
2017 // end up casting more traces per frame per light when using bouncegrid, which
2018 // is probably fine (and they use the same timer)
2019 if (r_shadow_culllights_trace.integer)
2021 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))
2022 rtlight->trace_timer = realtime;
2023 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2026 // skip if expanded light box is offscreen
2027 if (R_CullBox(cullmins, cullmaxs))
2029 // skip if overall light intensity is zero
2030 if (w * VectorLength2(rtlight->color) == 0.0f)
2033 // a light that does not emit any light before style is applied, can be
2034 // skipped entirely (it may just be a corona)
2035 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2037 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2038 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2039 // skip lights that will emit no photons
2040 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2042 // shoot particles from this light
2043 // use a calculation for the number of particles that will not
2044 // vary with lightstyle, otherwise we get randomized particle
2045 // distribution, the seeded random is only consistent for a
2046 // consistent number of particles on this light...
2047 s = rtlight->radius;
2048 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2049 if (lightindex >= range)
2050 lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2051 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2052 photoncount += rtlight->bouncegrid_photons;
2053 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2054 // if the lightstyle happens to be off right now, we can skip actually
2055 // firing the photons, but we did have to count them in the total.
2056 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2057 // rtlight->bouncegrid_photons = 0;
2059 // the user provided an energyperphoton value which we try to use
2060 // if that results in too many photons to shoot this frame, then we cap it
2061 // which causes photons to appear/disappear from frame to frame, so we don't
2062 // like doing that in the typical case
2063 photonscaling = 1.0f;
2064 photonintensity = 1.0f;
2065 if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2067 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2068 photonintensity = 1.0f / photonscaling;
2071 // modify the lights to reflect our computed scaling
2072 for (lightindex = 0; lightindex < range2; lightindex++)
2074 if (lightindex < range)
2076 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2079 rtlight = &light->rtlight;
2082 rtlight = r_refdef.scene.lights[lightindex - range];
2083 rtlight->bouncegrid_photons *= photonscaling;
2084 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2087 // compute a seed for the unstable random modes
2088 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2089 seed = realtime * 1000.0;
2091 for (lightindex = 0; lightindex < range2; lightindex++)
2093 if (lightindex < range)
2095 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2098 rtlight = &light->rtlight;
2101 rtlight = r_refdef.scene.lights[lightindex - range];
2102 // note that this code used to keep track of residual photons and
2103 // distribute them evenly to achieve exactly a desired photon count,
2104 // but that caused unwanted flickering in dynamic mode
2105 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2106 // skip if we won't be shooting any photons
2107 if (!shootparticles)
2109 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2110 //s = settings.particleintensity / shootparticles;
2111 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2112 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2113 if (VectorLength2(baseshotcolor) <= 0.0f)
2115 r_refdef.stats[r_stat_bouncegrid_lights]++;
2116 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2117 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2118 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2120 // check material at shadoworigin to see what the initial refractive index should be
2121 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2123 // for seeded random we start the RNG with the position of the light
2124 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2132 u.f[0] = rtlight->shadoworigin[0];
2133 u.f[1] = rtlight->shadoworigin[1];
2134 u.f[2] = rtlight->shadoworigin[2];
2136 switch (r_shadow_bouncegrid_state.settings.rng_type)
2140 // we have to shift the seed provided by the user because the result must be odd
2141 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2144 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2149 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2151 r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2152 VectorCopy(baseshotcolor, p->color);
2153 VectorCopy(rtlight->shadoworigin, p->start);
2154 switch (r_shadow_bouncegrid_state.settings.rng_type)
2158 // figure out a random direction for the initial photon to go
2159 VectorLehmerRandom(&randomseed, p->end);
2162 // figure out a random direction for the initial photon to go
2163 VectorCheeseRandom(seed, p->end);
2167 // we want a uniform distribution spherically, not merely within the sphere
2168 if (r_shadow_bouncegrid_state.settings.normalizevectors)
2169 VectorNormalize(p->end);
2171 VectorMA(p->start, radius, p->end, p->end);
2172 p->bounceminimumintensity2 = bounceminimumintensity2;
2173 p->startrefractiveindex = startrefractiveindex;
2181 static void R_Shadow_BounceGrid_Slice(int zi)
2183 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2184 int xi, yi; // pixel increments
2185 float color[32] = { 0 };
2186 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2187 float iradius = 1.0f / radius;
2188 int slicemins[3], slicemaxs[3];
2190 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2191 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2193 int samples = r_shadow_bouncegrid_state.settings.subsamples;
2194 float isamples = 1.0f / samples;
2195 float samplescolorscale = isamples * isamples * isamples;
2197 // we use these a lot, so get a local copy
2198 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2200 for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2202 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2204 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2206 r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2207 float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2209 VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2210 VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2212 pathmins[2] = min(pathstart[2], pathend[2]);
2213 slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2214 pathmaxs[2] = max(pathstart[2], pathend[2]);
2215 slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2217 // skip if the path doesn't touch this slice
2218 if (zi < slicemins[2] || zi >= slicemaxs[2])
2221 pathmins[0] = min(pathstart[0], pathend[0]);
2222 slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2223 slicemins[0] = max(slicemins[0], 1);
2224 pathmaxs[0] = max(pathstart[0], pathend[0]);
2225 slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2226 slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2228 pathmins[1] = min(pathstart[1], pathend[1]);
2229 slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2230 slicemins[1] = max(slicemins[1], 1);
2231 pathmaxs[1] = max(pathstart[1], pathend[1]);
2232 slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2233 slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2235 // skip if the path is out of bounds on X or Y
2236 if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2239 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2240 // accumulate average shotcolor
2241 VectorSubtract(pathend, pathstart, pathdelta);
2242 pathlength2 = VectorLength2(pathdelta);
2243 pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2244 VectorScale(pathdelta, pathilength, pathdir);
2245 // the color is scaled by the number of subsamples
2246 color[0] = path->color[0] * samplescolorscale;
2247 color[1] = path->color[1] * samplescolorscale;
2248 color[2] = path->color[2] * samplescolorscale;
2252 // store bentnormal in case the shader has a use for it,
2253 // bentnormal is an intensity-weighted average of the directions,
2254 // and will be normalized on conversion to texture pixels.
2255 float intensity = VectorLength(color);
2256 color[4] = pathdir[0] * intensity;
2257 color[5] = pathdir[1] * intensity;
2258 color[6] = pathdir[2] * intensity;
2259 color[7] = intensity;
2260 // for each color component (R, G, B) calculate the amount that a
2261 // direction contributes
2262 color[8] = color[0] * max(0.0f, pathdir[0]);
2263 color[9] = color[0] * max(0.0f, pathdir[1]);
2264 color[10] = color[0] * max(0.0f, pathdir[2]);
2266 color[12] = color[1] * max(0.0f, pathdir[0]);
2267 color[13] = color[1] * max(0.0f, pathdir[1]);
2268 color[14] = color[1] * max(0.0f, pathdir[2]);
2270 color[16] = color[2] * max(0.0f, pathdir[0]);
2271 color[17] = color[2] * max(0.0f, pathdir[1]);
2272 color[18] = color[2] * max(0.0f, pathdir[2]);
2274 // and do the same for negative directions
2275 color[20] = color[0] * max(0.0f, -pathdir[0]);
2276 color[21] = color[0] * max(0.0f, -pathdir[1]);
2277 color[22] = color[0] * max(0.0f, -pathdir[2]);
2279 color[24] = color[1] * max(0.0f, -pathdir[0]);
2280 color[25] = color[1] * max(0.0f, -pathdir[1]);
2281 color[26] = color[1] * max(0.0f, -pathdir[2]);
2283 color[28] = color[2] * max(0.0f, -pathdir[0]);
2284 color[29] = color[2] * max(0.0f, -pathdir[1]);
2285 color[30] = color[2] * max(0.0f, -pathdir[2]);
2289 for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2291 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2293 float sample[3], diff[3], nearest[3], along, distance2;
2294 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2296 // loop over the subsamples
2297 for (zs = 0; zs < samples; zs++)
2299 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2300 for (ys = 0; ys < samples; ys++)
2302 sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2303 for (xs = 0; xs < samples; xs++)
2305 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2307 // measure distance from subsample to line segment and see if it is within radius
2308 along = DotProduct(sample, pathdir) * pathilength;
2310 VectorCopy(pathstart, nearest);
2311 else if (along >= 1)
2312 VectorCopy(pathend, nearest);
2314 VectorLerp(pathstart, along, pathend, nearest);
2315 VectorSubtract(sample, nearest, diff);
2316 VectorScale(diff, iradius, diff);
2317 distance2 = VectorLength2(diff);
2318 if (distance2 < 1.0f)
2320 // contribute some color to this pixel, across all bands
2321 float w = 1.0f - sqrt(distance2);
2326 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2327 p[pixelsperband * 4 + 3] += color[7] * w;
2329 for (band = 0; band < pixelbands; band++)
2331 // add to the pixel color (RGB only - see above)
2332 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2333 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2334 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2346 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2348 R_Shadow_BounceGrid_Slice((int)t->i[0]);
2352 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2355 // we need to wait for the texture clear to finish before we start adding light to it
2356 if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2361 slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2362 for (i = 0; i < slices; i++)
2363 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2364 TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2365 TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2366 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2370 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2372 const float *inpixel;
2374 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2377 unsigned int x, y, z;
2378 unsigned int resolution[3];
2379 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2380 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2382 for (z = 1;z < resolution[2]-1;z++)
2384 for (y = 1;y < resolution[1]-1;y++)
2387 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2388 inpixel = inpixels + 4*index;
2389 outpixel = outpixels + 4*index;
2390 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2392 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2393 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2394 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2395 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2402 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2405 unsigned int resolution[3];
2406 if (r_shadow_bouncegrid_state.settings.blur)
2408 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2410 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2411 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2412 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2413 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2416 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2418 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2420 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2422 // toggle the state, highpixels now points to pixels[3] result
2423 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2424 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2429 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2431 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2432 unsigned char *pixelsbgra8 = NULL;
2433 unsigned char *pixelbgra8;
2434 unsigned short *pixelsrgba16f = NULL;
2435 unsigned short *pixelrgba16f;
2436 float *pixelsrgba32f = NULL;
2437 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2440 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2441 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2442 unsigned int pixelband;
2443 unsigned int x, y, z;
2444 unsigned int index, bandindex;
2445 unsigned int resolution[3];
2447 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2449 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2451 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2452 r_shadow_bouncegrid_state.texture = NULL;
2455 // if bentnormals exist, we need to normalize and bias them for the shader
2459 for (z = 0;z < resolution[2]-1;z++)
2461 for (y = 0;y < resolution[1]-1;y++)
2464 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2465 highpixel = highpixels + 4*index;
2466 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2468 // only convert pixels that were hit by photons
2469 if (highpixel[3] != 0.0f)
2470 VectorNormalize(highpixel);
2471 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2472 highpixel[pixelsperband * 4 + 3] = 1.0f;
2478 // start by clearing the pixels array - we won't be writing to all of it
2480 // then process only the pixels that have at least some color, skipping
2481 // the higher bands for speed on pixels that are black
2482 switch (floatcolors)
2485 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2486 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2487 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2488 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2491 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2493 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2495 for (z = 1;z < resolution[2]-1;z++)
2497 for (y = 1;y < resolution[1]-1;y++)
2501 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2502 highpixel = highpixels + 4*index;
2503 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2505 // only convert pixels that were hit by photons
2506 if (VectorLength2(highpixel))
2508 // normalize the bentnormal now
2511 VectorNormalize(highpixel + pixelsperband * 4);
2512 highpixel[pixelsperband * 4 + 3] = 1.0f;
2514 // process all of the pixelbands for this pixel
2515 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2517 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2518 bandpixel = highpixels + 4*bandindex;
2519 c[0] = (int)(bandpixel[0]*256.0f);
2520 c[1] = (int)(bandpixel[1]*256.0f);
2521 c[2] = (int)(bandpixel[2]*256.0f);
2522 c[3] = (int)(bandpixel[3]*256.0f);
2523 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2524 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2525 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2526 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2533 if (!r_shadow_bouncegrid_state.createtexture)
2534 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2536 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);
2539 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2540 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2541 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2542 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2543 for (z = 1;z < resolution[2]-1;z++)
2545 for (y = 1;y < resolution[1]-1;y++)
2549 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2550 highpixel = highpixels + 4*index;
2551 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2553 // only convert pixels that were hit by photons
2554 if (VectorLength2(highpixel))
2556 // process all of the pixelbands for this pixel
2557 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2559 // time to have fun with IEEE 754 bit hacking...
2562 unsigned int raw[4];
2564 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2565 bandpixel = highpixels + 4*bandindex;
2566 VectorCopy4(bandpixel, u.f);
2567 VectorCopy4(u.raw, c);
2568 // this math supports negative numbers, snaps denormals to zero
2569 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2570 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2571 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2572 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2573 // this math does not support negative
2574 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2575 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2576 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2577 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2584 if (!r_shadow_bouncegrid_state.createtexture)
2585 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2587 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, (const unsigned char *)pixelsrgba16f, TEXTYPE_COLORBUFFER16F, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2590 // our native format happens to match, so this is easy.
2591 pixelsrgba32f = highpixels;
2593 if (!r_shadow_bouncegrid_state.createtexture)
2594 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2596 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);
2600 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2603 void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2605 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2609 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)
2611 int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2613 vec3_t surfacenormal;
2614 vec3_t reflectstart, reflectend, reflectcolor;
2615 vec3_t refractstart, refractend, refractcolor;
2617 float reflectamount = 1.0f;
2619 // figure out what we want to interact with
2620 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2621 skipsupercontentsmask = 0;
2622 skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2623 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2624 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2625 if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2627 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2628 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2629 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);
2633 // dynamic mode fires many rays and most will match the cache from the previous frame
2634 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);
2636 VectorCopy(cliptrace.endpos, shothit);
2637 if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2639 qboolean notculled = true;
2640 // cull paths that fail R_CullBox in dynamic mode
2641 if (!r_shadow_bouncegrid_state.settings.staticmode
2642 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2644 vec3_t cullmins, cullmaxs;
2645 cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2646 cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2647 cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2648 cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2649 cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2650 cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2651 if (R_CullBox(cullmins, cullmaxs))
2656 r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2657 VectorCopy(shotstart, path->start);
2658 VectorCopy(shothit, path->end);
2659 VectorCopy(shotcolor, path->color);
2662 if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2664 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2665 // also clamp the resulting color to never add energy, even if the user requests extreme values
2666 VectorCopy(cliptrace.plane.normal, surfacenormal);
2667 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2668 VectorClear(refractcolor);
2669 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2670 if (cliptrace.hittexture)
2672 if (cliptrace.hittexture->currentskinframe)
2673 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2674 if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2676 reflectamount *= cliptrace.hittexture->currentalpha;
2677 if (cliptrace.hittexture->currentskinframe)
2678 reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2680 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2684 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2685 VectorSubtract(shotstart, shotend, lightdir);
2686 VectorNormalize(lightdir);
2687 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2688 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2689 reflectamount *= Fresnel;
2690 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2692 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2693 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2694 // make sure we do not gain energy even if surface colors are out of bounds
2695 reflectcolor[0] = min(reflectcolor[0], 1.0f);
2696 reflectcolor[1] = min(reflectcolor[1], 1.0f);
2697 reflectcolor[2] = min(reflectcolor[2], 1.0f);
2698 refractcolor[0] = min(refractcolor[0], 1.0f);
2699 refractcolor[1] = min(refractcolor[1], 1.0f);
2700 refractcolor[2] = min(refractcolor[2], 1.0f);
2702 // reflected and refracted shots
2703 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2704 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2705 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2706 VectorMultiply(refractcolor, shotcolor, refractcolor);
2708 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2710 // reflect the remaining portion of the line across plane normal
2711 VectorSubtract(shotend, shothit, reflectend);
2712 VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2713 // calculate the new line start and end
2714 VectorCopy(shothit, reflectstart);
2715 VectorAdd(reflectstart, reflectend, reflectend);
2716 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2719 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2721 // Check what refractive index is on the other side
2722 float refractiveindex;
2723 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2724 refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2725 // reflect the remaining portion of the line across plane normal
2726 VectorSubtract(shotend, shothit, refractend);
2727 s = refractiveindex / previousrefractiveindex;
2728 VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2729 // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2730 // calculate the new line start and end
2731 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2732 VectorAdd(refractstart, refractend, refractend);
2733 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2738 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2740 r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2741 R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2745 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2748 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2749 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2750 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);
2751 if (r_shadow_bouncegrid_threaded.integer)
2753 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2754 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2758 // when not threaded we still have to report task status
2759 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2760 r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2761 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2766 void R_Shadow_UpdateBounceGridTexture(void)
2768 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2769 r_shadow_bouncegrid_settings_t settings;
2770 qboolean enable = false;
2771 qboolean settingschanged;
2773 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2775 R_Shadow_BounceGrid_GenerateSettings(&settings);
2777 // changing intensity does not require an update
2778 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2780 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2782 // when settings change, we free everything as it is just simpler that way.
2783 if (settingschanged || !enable)
2785 // not enabled, make sure we free anything we don't need anymore.
2786 if (r_shadow_bouncegrid_state.texture)
2788 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2789 r_shadow_bouncegrid_state.texture = NULL;
2791 r_shadow_bouncegrid_state.highpixels = NULL;
2792 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2793 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2794 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2795 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2796 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2797 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2798 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2799 r_shadow_bouncegrid_state.numpixels = 0;
2800 r_shadow_bouncegrid_state.numphotons = 0;
2801 r_shadow_bouncegrid_state.directional = false;
2807 // if all the settings seem identical to the previous update, return
2808 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2811 // store the new settings
2812 r_shadow_bouncegrid_state.settings = settings;
2814 R_Shadow_BounceGrid_UpdateSpacing();
2816 // allocate the highpixels array we'll be accumulating light into
2817 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2818 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2819 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2820 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2821 r_shadow_bouncegrid_state.highpixels_index = 0;
2822 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2824 // set up the tracking of photon data
2825 if (r_shadow_bouncegrid_state.photons == NULL)
2826 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));
2827 if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2828 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2829 r_shadow_bouncegrid_state.numphotons = 0;
2831 // set up the tracking of slice tasks
2832 if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2833 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2835 memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2836 memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2837 memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2838 memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2839 memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2840 memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2841 memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2842 memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2843 memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2845 // clear the texture
2846 TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2847 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2849 // calculate weighting factors for distributing photons among the lights
2850 TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2851 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2853 // enqueue tasks to trace the photons from lights
2854 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2855 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2857 // accumulate the light paths into texture
2858 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);
2859 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2861 // apply a mild blur filter to the texture
2862 TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2863 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2865 TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2866 R_TimeReport("bouncegrid_gen");
2868 // convert the pixels to lower precision and upload the texture
2869 // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2870 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2871 R_TimeReport("bouncegrid_tex");
2873 // after we compute the static lighting we don't need to keep the highpixels array around
2874 if (settings.staticmode)
2876 r_shadow_bouncegrid_state.highpixels = NULL;
2877 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2878 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2879 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2880 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2881 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2882 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2883 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2887 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2889 R_Shadow_RenderMode_Reset();
2890 GL_BlendFunc(GL_ONE, GL_ONE);
2891 GL_DepthRange(0, 1);
2892 GL_DepthTest(r_showlighting.integer < 2);
2893 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2895 GL_DepthFunc(GL_EQUAL);
2896 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2899 void R_Shadow_RenderMode_End(void)
2901 R_Shadow_RenderMode_Reset();
2902 R_Shadow_RenderMode_ActiveLight(NULL);
2904 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2905 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2908 int bboxedges[12][2] =
2927 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2929 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2931 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2932 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2933 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2934 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2937 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2938 return true; // invisible
2939 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2940 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2941 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2942 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2943 r_refdef.stats[r_stat_lights_scissored]++;
2947 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2949 // used to display how many times a surface is lit for level design purposes
2950 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2951 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2955 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])
2957 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2958 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2962 extern cvar_t gl_lightmaps;
2963 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2966 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2967 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2968 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2969 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2970 if (!r_shadow_usenormalmap.integer)
2972 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2973 VectorClear(diffusecolor);
2974 VectorClear(specularcolor);
2976 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2977 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2978 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2979 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2981 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2984 VectorNegate(ambientcolor, ambientcolor);
2985 VectorNegate(diffusecolor, diffusecolor);
2986 VectorNegate(specularcolor, specularcolor);
2987 GL_BlendEquationSubtract(true);
2989 RSurf_SetupDepthAndCulling();
2990 switch (r_shadow_rendermode)
2992 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2993 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2994 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2996 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2997 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
3000 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3004 GL_BlendEquationSubtract(false);
3007 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)
3009 matrix4x4_t tempmatrix = *matrix;
3010 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3012 // if this light has been compiled before, free the associated data
3013 R_RTLight_Uncompile(rtlight);
3015 // clear it completely to avoid any lingering data
3016 memset(rtlight, 0, sizeof(*rtlight));
3018 // copy the properties
3019 rtlight->matrix_lighttoworld = tempmatrix;
3020 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3021 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3022 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3023 VectorCopy(color, rtlight->color);
3024 rtlight->cubemapname[0] = 0;
3025 if (cubemapname && cubemapname[0])
3026 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3027 rtlight->shadow = shadow;
3028 rtlight->corona = corona;
3029 rtlight->style = style;
3030 rtlight->isstatic = isstatic;
3031 rtlight->coronasizescale = coronasizescale;
3032 rtlight->ambientscale = ambientscale;
3033 rtlight->diffusescale = diffusescale;
3034 rtlight->specularscale = specularscale;
3035 rtlight->flags = flags;
3037 // compute derived data
3038 //rtlight->cullradius = rtlight->radius;
3039 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3040 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3041 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3042 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3043 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3044 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3045 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3048 // compiles rtlight geometry
3049 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3050 void R_RTLight_Compile(rtlight_t *rtlight)
3053 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3054 int lighttris, shadowtris;
3055 entity_render_t *ent = r_refdef.scene.worldentity;
3056 dp_model_t *model = r_refdef.scene.worldmodel;
3057 unsigned char *data;
3059 // compile the light
3060 rtlight->compiled = true;
3061 rtlight->static_numleafs = 0;
3062 rtlight->static_numleafpvsbytes = 0;
3063 rtlight->static_leaflist = NULL;
3064 rtlight->static_leafpvs = NULL;
3065 rtlight->static_numsurfaces = 0;
3066 rtlight->static_surfacelist = NULL;
3067 rtlight->static_shadowmap_receivers = 0x3F;
3068 rtlight->static_shadowmap_casters = 0x3F;
3069 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3070 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3071 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3072 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3073 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3074 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3076 if (model && model->GetLightInfo)
3078 // this variable must be set for the CompileShadowMap code
3079 r_shadow_compilingrtlight = rtlight;
3080 R_FrameData_SetMark();
3081 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);
3082 R_FrameData_ReturnToMark();
3083 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3084 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3085 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3086 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3087 rtlight->static_numsurfaces = numsurfaces;
3088 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3089 rtlight->static_numleafs = numleafs;
3090 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3091 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3092 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3093 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3094 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3095 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3096 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3097 if (rtlight->static_numsurfaces)
3098 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3099 if (rtlight->static_numleafs)
3100 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3101 if (rtlight->static_numleafpvsbytes)
3102 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3103 if (rtlight->static_numshadowtrispvsbytes)
3104 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3105 if (rtlight->static_numlighttrispvsbytes)
3106 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3107 R_FrameData_SetMark();
3108 if (model->CompileShadowMap && rtlight->shadow)
3109 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3110 R_FrameData_ReturnToMark();
3111 // now we're done compiling the rtlight
3112 r_shadow_compilingrtlight = NULL;
3116 // use smallest available cullradius - box radius or light radius
3117 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3118 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3121 if (rtlight->static_numlighttrispvsbytes)
3122 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3123 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3127 if (rtlight->static_numshadowtrispvsbytes)
3128 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3129 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3132 if (developer_extra.integer)
3133 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);
3136 void R_RTLight_Uncompile(rtlight_t *rtlight)
3138 if (rtlight->compiled)
3140 if (rtlight->static_meshchain_shadow_shadowmap)
3141 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3142 rtlight->static_meshchain_shadow_shadowmap = NULL;
3143 // these allocations are grouped
3144 if (rtlight->static_surfacelist)
3145 Mem_Free(rtlight->static_surfacelist);
3146 rtlight->static_numleafs = 0;
3147 rtlight->static_numleafpvsbytes = 0;
3148 rtlight->static_leaflist = NULL;
3149 rtlight->static_leafpvs = NULL;
3150 rtlight->static_numsurfaces = 0;
3151 rtlight->static_surfacelist = NULL;
3152 rtlight->static_numshadowtrispvsbytes = 0;
3153 rtlight->static_shadowtrispvs = NULL;
3154 rtlight->static_numlighttrispvsbytes = 0;
3155 rtlight->static_lighttrispvs = NULL;
3156 rtlight->compiled = false;
3160 void R_Shadow_UncompileWorldLights(void)
3164 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3165 for (lightindex = 0;lightindex < range;lightindex++)
3167 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3170 R_RTLight_Uncompile(&light->rtlight);
3174 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3178 // reset the count of frustum planes
3179 // see rtlight->cached_frustumplanes definition for how much this array
3181 rtlight->cached_numfrustumplanes = 0;
3183 if (r_trippy.integer)
3186 // haven't implemented a culling path for ortho rendering
3187 if (!r_refdef.view.useperspective)
3189 // check if the light is on screen and copy the 4 planes if it is
3190 for (i = 0;i < 4;i++)
3191 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3194 for (i = 0;i < 4;i++)
3195 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3200 // generate a deformed frustum that includes the light origin, this is
3201 // used to cull shadow casting surfaces that can not possibly cast a
3202 // shadow onto the visible light-receiving surfaces, which can be a
3205 // if the light origin is onscreen the result will be 4 planes exactly
3206 // if the light origin is offscreen on only one axis the result will
3207 // be exactly 5 planes (split-side case)
3208 // if the light origin is offscreen on two axes the result will be
3209 // exactly 4 planes (stretched corner case)
3210 for (i = 0;i < 4;i++)
3212 // quickly reject standard frustum planes that put the light
3213 // origin outside the frustum
3214 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3217 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3219 // if all the standard frustum planes were accepted, the light is onscreen
3220 // otherwise we need to generate some more planes below...
3221 if (rtlight->cached_numfrustumplanes < 4)
3223 // at least one of the stock frustum planes failed, so we need to
3224 // create one or two custom planes to enclose the light origin
3225 for (i = 0;i < 4;i++)
3227 // create a plane using the view origin and light origin, and a
3228 // single point from the frustum corner set
3229 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3230 VectorNormalize(plane.normal);
3231 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3232 // see if this plane is backwards and flip it if so
3233 for (j = 0;j < 4;j++)
3234 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3238 VectorNegate(plane.normal, plane.normal);
3240 // flipped plane, test again to see if it is now valid
3241 for (j = 0;j < 4;j++)
3242 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3244 // if the plane is still not valid, then it is dividing the
3245 // frustum and has to be rejected
3249 // we have created a valid plane, compute extra info
3250 PlaneClassify(&plane);
3252 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3254 // if we've found 5 frustum planes then we have constructed a
3255 // proper split-side case and do not need to keep searching for
3256 // planes to enclose the light origin
3257 if (rtlight->cached_numfrustumplanes == 5)
3265 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3267 plane = rtlight->cached_frustumplanes[i];
3268 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));
3273 // now add the light-space box planes if the light box is rotated, as any
3274 // caster outside the oriented light box is irrelevant (even if it passed
3275 // the worldspace light box, which is axial)
3276 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3278 for (i = 0;i < 6;i++)
3282 v[i >> 1] = (i & 1) ? -1 : 1;
3283 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3284 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3285 plane.dist = VectorNormalizeLength(plane.normal);
3286 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3287 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3293 // add the world-space reduced box planes
3294 for (i = 0;i < 6;i++)
3296 VectorClear(plane.normal);
3297 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3298 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3299 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3308 // reduce all plane distances to tightly fit the rtlight cull box, which
3310 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3311 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3312 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3313 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3314 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3315 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3316 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3317 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3318 oldnum = rtlight->cached_numfrustumplanes;
3319 rtlight->cached_numfrustumplanes = 0;
3320 for (j = 0;j < oldnum;j++)
3322 // find the nearest point on the box to this plane
3323 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3324 for (i = 1;i < 8;i++)
3326 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3327 if (bestdist > dist)
3330 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);
3331 // if the nearest point is near or behind the plane, we want this
3332 // plane, otherwise the plane is useless as it won't cull anything
3333 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3335 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3336 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3343 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3345 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3347 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3349 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3350 if (mesh->sidetotals[r_shadow_shadowmapside])
3353 GL_CullFace(GL_NONE);
3354 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3355 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3356 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);
3360 else if (r_refdef.scene.worldentity->model)
3361 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);
3363 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3366 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3368 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3369 vec_t relativeshadowradius;
3370 RSurf_ActiveModelEntity(ent, false, false, false);
3371 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3372 // we need to re-init the shader for each entity because the matrix changed
3373 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3374 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3375 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3376 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3377 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3378 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3379 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3380 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3381 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3384 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3386 // set up properties for rendering light onto this entity
3387 RSurf_ActiveModelEntity(ent, true, true, false);
3388 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3389 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3390 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3391 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3394 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3396 if (!r_refdef.scene.worldmodel->DrawLight)
3399 // set up properties for rendering light onto this entity
3400 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3401 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3402 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3403 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3404 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3406 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3408 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3411 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3413 dp_model_t *model = ent->model;
3414 if (!model->DrawLight)
3417 R_Shadow_SetupEntityLight(ent);
3419 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3421 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3424 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3428 int numleafs, numsurfaces;
3429 int *leaflist, *surfacelist;
3430 unsigned char *leafpvs;
3431 unsigned char *shadowtrispvs;
3432 unsigned char *lighttrispvs;
3433 //unsigned char *surfacesides;
3434 int numlightentities;
3435 int numlightentities_noselfshadow;
3436 int numshadowentities;
3437 int numshadowentities_noselfshadow;
3438 // FIXME: bounds check lightentities and shadowentities, etc.
3439 static entity_render_t *lightentities[MAX_EDICTS];
3440 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3441 static entity_render_t *shadowentities[MAX_EDICTS];
3442 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3444 qboolean castshadows;
3446 rtlight->draw = false;
3447 rtlight->cached_numlightentities = 0;
3448 rtlight->cached_numlightentities_noselfshadow = 0;
3449 rtlight->cached_numshadowentities = 0;
3450 rtlight->cached_numshadowentities_noselfshadow = 0;
3451 rtlight->cached_numsurfaces = 0;
3452 rtlight->cached_lightentities = NULL;
3453 rtlight->cached_lightentities_noselfshadow = NULL;
3454 rtlight->cached_shadowentities = NULL;
3455 rtlight->cached_shadowentities_noselfshadow = NULL;
3456 rtlight->cached_shadowtrispvs = NULL;
3457 rtlight->cached_lighttrispvs = NULL;
3458 rtlight->cached_surfacelist = NULL;
3459 rtlight->shadowmapsidesize = 0;
3461 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3462 // skip lights that are basically invisible (color 0 0 0)
3463 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3465 // loading is done before visibility checks because loading should happen
3466 // all at once at the start of a level, not when it stalls gameplay.
3467 // (especially important to benchmarks)
3469 if (rtlight->isstatic && !nolight && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3470 R_RTLight_Compile(rtlight);
3473 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3475 // look up the light style value at this time
3476 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3477 VectorScale(rtlight->color, f, rtlight->currentcolor);
3479 if (rtlight->selected)
3481 f = 2 + sin(realtime * M_PI * 4.0);
3482 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3486 // skip if lightstyle is currently off
3487 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3490 // skip processing on corona-only lights
3494 // skip if the light box is not touching any visible leafs
3495 if (r_shadow_culllights_pvs.integer
3496 && r_refdef.scene.worldmodel
3497 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3498 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3501 // skip if the light box is not visible to traceline
3502 if (r_shadow_culllights_trace.integer)
3504 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))
3505 rtlight->trace_timer = realtime;
3506 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3510 // skip if the light box is off screen
3511 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3514 // in the typical case this will be quickly replaced by GetLightInfo
3515 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3516 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3518 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3520 // 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
3521 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3524 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3526 // compiled light, world available and can receive realtime lighting
3527 // retrieve leaf information
3528 numleafs = rtlight->static_numleafs;
3529 leaflist = rtlight->static_leaflist;
3530 leafpvs = rtlight->static_leafpvs;
3531 numsurfaces = rtlight->static_numsurfaces;
3532 surfacelist = rtlight->static_surfacelist;
3533 //surfacesides = NULL;
3534 shadowtrispvs = rtlight->static_shadowtrispvs;
3535 lighttrispvs = rtlight->static_lighttrispvs;
3537 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3539 // dynamic light, world available and can receive realtime lighting
3540 // calculate lit surfaces and leafs
3541 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);
3542 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3543 leaflist = r_shadow_buffer_leaflist;
3544 leafpvs = r_shadow_buffer_leafpvs;
3545 surfacelist = r_shadow_buffer_surfacelist;
3546 //surfacesides = r_shadow_buffer_surfacesides;
3547 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3548 lighttrispvs = r_shadow_buffer_lighttrispvs;
3549 // if the reduced leaf bounds are offscreen, skip it
3550 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3561 //surfacesides = NULL;
3562 shadowtrispvs = NULL;
3563 lighttrispvs = NULL;
3565 // check if light is illuminating any visible leafs
3568 for (i = 0; i < numleafs; i++)
3569 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3575 // make a list of lit entities and shadow casting entities
3576 numlightentities = 0;
3577 numlightentities_noselfshadow = 0;
3578 numshadowentities = 0;
3579 numshadowentities_noselfshadow = 0;
3581 // add dynamic entities that are lit by the light
3582 for (i = 0; i < r_refdef.scene.numentities; i++)
3585 entity_render_t *ent = r_refdef.scene.entities[i];
3587 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3589 // skip the object entirely if it is not within the valid
3590 // shadow-casting region (which includes the lit region)
3591 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3593 if (!(model = ent->model))
3595 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3597 // this entity wants to receive light, is visible, and is
3598 // inside the light box
3599 // TODO: check if the surfaces in the model can receive light
3600 // so now check if it's in a leaf seen by the light
3601 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))
3603 if (ent->flags & RENDER_NOSELFSHADOW)
3604 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3606 lightentities[numlightentities++] = ent;
3607 // since it is lit, it probably also casts a shadow...
3608 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3609 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3610 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3612 // note: exterior models without the RENDER_NOSELFSHADOW
3613 // flag still create a RENDER_NOSELFSHADOW shadow but
3614 // are lit normally, this means that they are
3615 // self-shadowing but do not shadow other
3616 // RENDER_NOSELFSHADOW entities such as the gun
3617 // (very weird, but keeps the player shadow off the gun)
3618 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3619 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3621 shadowentities[numshadowentities++] = ent;
3624 else if (ent->flags & RENDER_SHADOW)
3626 // this entity is not receiving light, but may still need to
3628 // TODO: check if the surfaces in the model can cast shadow
3629 // now check if it is in a leaf seen by the light
3630 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))
3632 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3633 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3634 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3636 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3637 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3639 shadowentities[numshadowentities++] = ent;
3644 // return if there's nothing at all to light
3645 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3648 // count this light in the r_speeds
3649 r_refdef.stats[r_stat_lights]++;
3651 // flag it as worth drawing later
3652 rtlight->draw = true;
3654 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3655 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3657 numshadowentities = numshadowentities_noselfshadow = 0;
3658 rtlight->castshadows = castshadows;
3660 // cache all the animated entities that cast a shadow but are not visible
3661 for (i = 0; i < numshadowentities; i++)
3662 R_AnimCache_GetEntity(shadowentities[i], false, false);
3663 for (i = 0; i < numshadowentities_noselfshadow; i++)
3664 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3666 // 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)
3667 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3669 for (i = 0; i < numshadowentities_noselfshadow; i++)
3670 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3671 numshadowentities_noselfshadow = 0;
3674 // we can convert noselfshadow to regular if there are no casters of that type
3675 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3677 for (i = 0; i < numlightentities_noselfshadow; i++)
3678 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3679 numlightentities_noselfshadow = 0;
3682 // allocate some temporary memory for rendering this light later in the frame
3683 // reusable buffers need to be copied, static data can be used as-is
3684 rtlight->cached_numlightentities = numlightentities;
3685 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3686 rtlight->cached_numshadowentities = numshadowentities;
3687 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3688 rtlight->cached_numsurfaces = numsurfaces;
3689 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3690 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3691 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3692 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3693 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3695 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3696 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3697 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3698 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3699 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3703 // compiled light data
3704 rtlight->cached_shadowtrispvs = shadowtrispvs;
3705 rtlight->cached_lighttrispvs = lighttrispvs;
3706 rtlight->cached_surfacelist = surfacelist;
3709 if (R_Shadow_ShadowMappingEnabled())
3711 // figure out the shadowmapping parameters for this light
3712 vec3_t nearestpoint;
3715 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3716 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3717 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3718 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3719 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3720 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3721 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3722 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3723 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3727 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3731 unsigned char *shadowtrispvs, *surfacesides;
3732 int numlightentities;
3733 int numlightentities_noselfshadow;
3734 int numshadowentities;
3735 int numshadowentities_noselfshadow;
3736 entity_render_t **lightentities;
3737 entity_render_t **lightentities_noselfshadow;
3738 entity_render_t **shadowentities;
3739 entity_render_t **shadowentities_noselfshadow;
3741 static unsigned char entitysides[MAX_EDICTS];
3742 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3748 matrix4x4_t radiustolight;
3750 // check if we cached this light this frame (meaning it is worth drawing)
3751 if (!rtlight->draw || !rtlight->castshadows)
3754 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3755 if (rtlight->shadowmapatlassidesize == 0)
3757 rtlight->castshadows = false;
3761 // set up a scissor rectangle for this light
3762 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3765 // don't let sound skip if going slow
3766 if (r_refdef.scene.extraupdate)
3769 numlightentities = rtlight->cached_numlightentities;
3770 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3771 numshadowentities = rtlight->cached_numshadowentities;
3772 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3773 numsurfaces = rtlight->cached_numsurfaces;
3774 lightentities = rtlight->cached_lightentities;
3775 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3776 shadowentities = rtlight->cached_shadowentities;
3777 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3778 shadowtrispvs = rtlight->cached_shadowtrispvs;
3779 surfacelist = rtlight->cached_surfacelist;
3781 // make this the active rtlight for rendering purposes
3782 R_Shadow_RenderMode_ActiveLight(rtlight);
3784 radiustolight = rtlight->matrix_worldtolight;
3785 Matrix4x4_Abs(&radiustolight);
3787 size = rtlight->shadowmapatlassidesize;
3788 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3790 surfacesides = NULL;
3795 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3797 castermask = rtlight->static_shadowmap_casters;
3798 receivermask = rtlight->static_shadowmap_receivers;
3802 surfacesides = r_shadow_buffer_surfacesides;
3803 for (i = 0; i < numsurfaces; i++)
3805 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3806 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3807 castermask |= surfacesides[i];
3808 receivermask |= surfacesides[i];
3813 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3814 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3815 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3816 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3818 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3822 for (i = 0; i < numshadowentities; i++)
3823 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3824 for (i = 0; i < numshadowentities_noselfshadow; i++)
3825 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3828 // there is no need to render shadows for sides that have no receivers...
3829 castermask &= receivermask;
3831 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3833 // render shadow casters into shadowmaps for this light
3834 for (side = 0; side < 6; side++)
3836 int bit = 1 << side;
3837 if (castermask & bit)
3839 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3841 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3842 for (i = 0; i < numshadowentities; i++)
3843 if (entitysides[i] & bit)
3844 R_Shadow_DrawEntityShadow(shadowentities[i]);
3845 for (i = 0; i < numshadowentities_noselfshadow; i++)
3846 if (entitysides_noselfshadow[i] & bit)
3847 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3850 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3851 if (numshadowentities_noselfshadow)
3853 for (side = 0; side < 6; side++)
3855 int bit = 1 << side;
3856 if (castermask & bit)
3858 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3860 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3861 for (i = 0; i < numshadowentities; i++)
3862 if (entitysides[i] & bit)
3863 R_Shadow_DrawEntityShadow(shadowentities[i]);
3869 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3873 unsigned char *lighttrispvs;
3874 int numlightentities;
3875 int numlightentities_noselfshadow;
3876 entity_render_t **lightentities;
3877 entity_render_t **lightentities_noselfshadow;
3878 entity_render_t **shadowentities;
3879 entity_render_t **shadowentities_noselfshadow;
3881 qboolean castshadows;
3883 // check if we cached this light this frame (meaning it is worth drawing)
3887 // set up a scissor rectangle for this light
3888 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3891 // don't let sound skip if going slow
3892 if (r_refdef.scene.extraupdate)
3895 numlightentities = rtlight->cached_numlightentities;
3896 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3897 numsurfaces = rtlight->cached_numsurfaces;
3898 lightentities = rtlight->cached_lightentities;
3899 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3900 shadowentities = rtlight->cached_shadowentities;
3901 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3902 lighttrispvs = rtlight->cached_lighttrispvs;
3903 surfacelist = rtlight->cached_surfacelist;
3904 castshadows = rtlight->castshadows;
3906 // make this the active rtlight for rendering purposes
3907 R_Shadow_RenderMode_ActiveLight(rtlight);
3909 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3911 // optionally draw the illuminated areas
3912 // for performance analysis by level designers
3913 R_Shadow_RenderMode_VisibleLighting(false);
3915 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3916 for (i = 0;i < numlightentities;i++)
3917 R_Shadow_DrawEntityLight(lightentities[i]);
3918 for (i = 0;i < numlightentities_noselfshadow;i++)
3919 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3922 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3926 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3927 Matrix4x4_Abs(&radiustolight);
3929 size = rtlight->shadowmapatlassidesize;
3930 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3932 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3934 // render lighting using the depth texture as shadowmap
3935 // draw lighting in the unmasked areas
3936 if (numsurfaces + numlightentities)
3938 R_Shadow_RenderMode_Lighting(false, true, false);
3939 // draw lighting in the unmasked areas
3941 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3942 for (i = 0; i < numlightentities; i++)
3943 R_Shadow_DrawEntityLight(lightentities[i]);
3945 // offset to the noselfshadow part of the atlas and draw those too
3946 if (numlightentities_noselfshadow)
3948 R_Shadow_RenderMode_Lighting(false, true, true);
3949 for (i = 0; i < numlightentities_noselfshadow; i++)
3950 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3953 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3954 if (r_shadow_usingdeferredprepass)
3955 R_Shadow_RenderMode_DrawDeferredLight(true);
3959 // draw lighting in the unmasked areas
3960 R_Shadow_RenderMode_Lighting(false, false, false);
3962 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3963 for (i = 0;i < numlightentities;i++)
3964 R_Shadow_DrawEntityLight(lightentities[i]);
3965 for (i = 0;i < numlightentities_noselfshadow;i++)
3966 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3968 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3969 if (r_shadow_usingdeferredprepass)
3970 R_Shadow_RenderMode_DrawDeferredLight(false);
3974 static void R_Shadow_FreeDeferred(void)
3976 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3977 r_shadow_prepassgeometryfbo = 0;
3979 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3980 r_shadow_prepasslightingdiffusespecularfbo = 0;
3982 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3983 r_shadow_prepasslightingdiffusefbo = 0;
3985 if (r_shadow_prepassgeometrydepthbuffer)
3986 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3987 r_shadow_prepassgeometrydepthbuffer = NULL;
3989 if (r_shadow_prepassgeometrynormalmaptexture)
3990 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3991 r_shadow_prepassgeometrynormalmaptexture = NULL;
3993 if (r_shadow_prepasslightingdiffusetexture)
3994 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3995 r_shadow_prepasslightingdiffusetexture = NULL;
3997 if (r_shadow_prepasslightingspeculartexture)
3998 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3999 r_shadow_prepasslightingspeculartexture = NULL;
4002 void R_Shadow_DrawPrepass(void)
4006 entity_render_t *ent;
4007 float clearcolor[4];
4009 R_Mesh_ResetTextureState();
4011 GL_ColorMask(1,1,1,1);
4012 GL_BlendFunc(GL_ONE, GL_ZERO);
4015 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4016 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4017 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4018 if (r_timereport_active)
4019 R_TimeReport("prepasscleargeom");
4021 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4022 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4023 if (r_timereport_active)
4024 R_TimeReport("prepassworld");
4026 for (i = 0;i < r_refdef.scene.numentities;i++)
4028 if (!r_refdef.viewcache.entityvisible[i])
4030 ent = r_refdef.scene.entities[i];
4031 if (ent->model && ent->model->DrawPrepass != NULL)
4032 ent->model->DrawPrepass(ent);
4035 if (r_timereport_active)
4036 R_TimeReport("prepassmodels");
4038 GL_DepthMask(false);
4039 GL_ColorMask(1,1,1,1);
4042 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4043 Vector4Set(clearcolor, 0, 0, 0, 0);
4044 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4045 if (r_timereport_active)
4046 R_TimeReport("prepassclearlit");
4048 R_Shadow_RenderMode_Begin();
4050 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4051 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4053 R_Shadow_RenderMode_End();
4055 if (r_timereport_active)
4056 R_TimeReport("prepasslights");
4059 #define MAX_SCENELIGHTS 65536
4060 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4062 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4064 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4066 r_shadow_scenemaxlights *= 2;
4067 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4068 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4070 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4074 void R_Shadow_DrawLightSprites(void);
4075 void R_Shadow_PrepareLights(void)
4084 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4085 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4086 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4088 if (r_shadow_shadowmode_shadowmapping != r_shadow_shadowmapping.integer ||
4089 r_shadow_shadowmode_deferred != r_shadow_deferred.integer ||
4090 r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4091 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4092 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4093 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4094 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4095 r_shadow_shadowmapborder != shadowmapborder ||
4096 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4097 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4098 R_Shadow_FreeShadowMaps();
4100 r_shadow_usingshadowmaportho = false;
4102 switch (vid.renderpath)
4104 case RENDERPATH_GL32:
4106 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4108 r_shadow_usingdeferredprepass = false;
4109 if (r_shadow_prepass_width)
4110 R_Shadow_FreeDeferred();
4111 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4115 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4117 R_Shadow_FreeDeferred();
4119 r_shadow_usingdeferredprepass = true;
4120 r_shadow_prepass_width = vid.width;
4121 r_shadow_prepass_height = vid.height;
4122 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4123 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4124 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4125 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4127 // set up the geometry pass fbo (depth + normalmap)
4128 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4129 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4130 // render depth into a renderbuffer and other important properties into the normalmap texture
4132 // set up the lighting pass fbo (diffuse + specular)
4133 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4134 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4135 // render diffuse into one texture and specular into another,
4136 // with depth and normalmap bound as textures,
4137 // with depth bound as attachment as well
4139 // set up the lighting pass fbo (diffuse)
4140 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4141 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4142 // render diffuse into one texture,
4143 // with depth and normalmap bound as textures,
4144 // with depth bound as attachment as well
4148 case RENDERPATH_GLES2:
4149 r_shadow_usingdeferredprepass = false;
4153 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
4155 r_shadow_scenenumlights = 0;
4156 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4157 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4158 for (lightindex = 0; lightindex < range; lightindex++)
4160 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4161 if (light && (light->flags & flag))
4163 R_Shadow_PrepareLight(&light->rtlight);
4164 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4167 if (r_refdef.scene.rtdlight)
4169 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4171 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4172 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4175 else if (gl_flashblend.integer)
4177 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4179 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4180 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4181 VectorScale(rtlight->color, f, rtlight->currentcolor);
4185 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4186 if (r_shadow_debuglight.integer >= 0)
4188 r_shadow_scenenumlights = 0;
4189 lightindex = r_shadow_debuglight.integer;
4190 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4193 R_Shadow_PrepareLight(&light->rtlight);
4194 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4198 // if we're doing shadowmaps we need to prepare the atlas layout now
4199 if (R_Shadow_ShadowMappingEnabled())
4203 // allocate shadowmaps in the atlas now
4204 // we may have to make multiple attempts to fit the shadowmaps in the limited space of the atlas, this will appear as lod popping of all shadowmaps whenever it changes, but at least we can still cast shadows from all lights...
4205 for (lod = 0; lod < 16; lod++)
4207 int packing_success = 0;
4208 int packing_failure = 0;
4209 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4210 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4211 if (r_shadow_shadowmapatlas_modelshadows_size)
4212 Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, &r_shadow_shadowmapatlas_modelshadows_x, &r_shadow_shadowmapatlas_modelshadows_y);
4213 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4215 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4216 int size = rtlight->shadowmapsidesize >> lod;
4218 if (!rtlight->castshadows)
4220 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4223 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4224 if (rtlight->cached_numshadowentities_noselfshadow)
4226 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4228 rtlight->shadowmapatlassidesize = size;
4233 // note down that we failed to pack this one, it will have to disable shadows
4234 rtlight->shadowmapatlassidesize = 0;
4238 // generally everything fits and we stop here on the first iteration
4239 if (packing_failure == 0)
4244 if (r_editlights.integer)
4245 R_Shadow_DrawLightSprites();
4248 void R_Shadow_DrawShadowMaps(void)
4250 R_Shadow_RenderMode_Begin();
4251 R_Shadow_RenderMode_ActiveLight(NULL);
4253 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4254 R_Shadow_ClearShadowMapTexture();
4256 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4257 if (r_shadow_shadowmapatlas_modelshadows_size)
4259 R_Shadow_DrawModelShadowMaps();
4260 // don't let sound skip if going slow
4261 if (r_refdef.scene.extraupdate)
4265 if (R_Shadow_ShadowMappingEnabled())
4268 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4269 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4272 R_Shadow_RenderMode_End();
4275 void R_Shadow_DrawLights(void)
4279 R_Shadow_RenderMode_Begin();
4281 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4282 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4284 R_Shadow_RenderMode_End();
4287 #define MAX_MODELSHADOWS 1024
4288 static int r_shadow_nummodelshadows;
4289 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4291 void R_Shadow_PrepareModelShadows(void)
4294 float scale, size, radius, dot1, dot2;
4295 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4296 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4297 entity_render_t *ent;
4299 r_shadow_nummodelshadows = 0;
4300 r_shadow_shadowmapatlas_modelshadows_size = 0;
4302 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4305 size = r_shadow_shadowmaptexturesize / 4;
4306 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4307 radius = 0.5f * size / scale;
4309 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4310 VectorCopy(prvmshadowdir, shadowdir);
4311 VectorNormalize(shadowdir);
4312 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4313 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4314 if (fabs(dot1) <= fabs(dot2))
4315 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4317 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4318 VectorNormalize(shadowforward);
4319 CrossProduct(shadowdir, shadowforward, shadowright);
4320 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4321 VectorCopy(prvmshadowfocus, shadowfocus);
4322 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4323 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4324 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4325 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4326 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4328 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4330 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4331 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4332 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4333 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4334 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4335 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4337 for (i = 0; i < r_refdef.scene.numentities; i++)
4339 ent = r_refdef.scene.entities[i];
4340 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4342 // cast shadows from anything of the map (submodels are optional)
4343 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4345 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4347 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4348 R_AnimCache_GetEntity(ent, false, false);
4352 if (r_shadow_nummodelshadows)
4354 r_shadow_shadowmapatlas_modelshadows_x = 0;
4355 r_shadow_shadowmapatlas_modelshadows_y = 0;
4356 r_shadow_shadowmapatlas_modelshadows_size = size;
4360 static void R_Shadow_DrawModelShadowMaps(void)
4363 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4364 entity_render_t *ent;
4365 vec3_t relativelightorigin;
4366 vec3_t relativelightdirection, relativeforward, relativeright;
4367 vec3_t relativeshadowmins, relativeshadowmaxs;
4368 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4369 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4371 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4372 r_viewport_t viewport;
4374 size = r_shadow_shadowmapatlas_modelshadows_size;
4375 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4376 radius = 0.5f / scale;
4377 nearclip = -r_shadows_throwdistance.value;
4378 farclip = r_shadows_throwdistance.value;
4379 bias = (r_shadows_shadowmapbias.value < 0) ? r_shadow_shadowmapping_bias.value : r_shadows_shadowmapbias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4381 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4382 r_shadow_modelshadowmap_parameters[0] = size;
4383 r_shadow_modelshadowmap_parameters[1] = size;
4384 r_shadow_modelshadowmap_parameters[2] = 1.0;
4385 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4386 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4387 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4388 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4389 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4390 r_shadow_usingshadowmaportho = true;
4392 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4393 VectorCopy(prvmshadowdir, shadowdir);
4394 VectorNormalize(shadowdir);
4395 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4396 VectorCopy(prvmshadowfocus, shadowfocus);
4397 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4398 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4399 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4400 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4401 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4402 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4403 if (fabs(dot1) <= fabs(dot2))
4404 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4406 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4407 VectorNormalize(shadowforward);
4408 VectorM(scale, shadowforward, &m[0]);
4409 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4411 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4412 CrossProduct(shadowdir, shadowforward, shadowright);
4413 VectorM(scale, shadowright, &m[4]);
4414 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4415 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4416 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4417 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4418 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4419 R_Viewport_InitOrtho(&viewport, &cameramatrix, r_shadow_shadowmapatlas_modelshadows_x, r_shadow_shadowmapatlas_modelshadows_y, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, 0, 0, 1, 1, 0, -1, NULL);
4420 R_SetViewport(&viewport);
4422 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4424 // render into a slightly restricted region so that the borders of the
4425 // shadowmap area fade away, rather than streaking across everything
4426 // outside the usable area
4427 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4429 for (i = 0;i < r_shadow_nummodelshadows;i++)
4431 ent = r_shadow_modelshadows[i];
4432 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4433 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4434 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4435 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4436 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4437 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4438 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4439 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4440 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4441 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4442 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4443 RSurf_ActiveModelEntity(ent, false, false, false);
4444 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4445 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4451 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4453 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4455 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4456 Cvar_SetValueQuick(&r_test, 0);
4461 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4462 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4463 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4464 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4465 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4466 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4469 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4472 vec3_t centerorigin;
4476 // if it's too close, skip it
4477 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4479 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4482 if (usequery && r_numqueries + 2 <= r_maxqueries)
4484 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4485 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4486 // we count potential samples in the middle of the screen, we count actual samples at the light location, this allows counting potential samples of off-screen lights
4487 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4489 switch(vid.renderpath)
4491 case RENDERPATH_GL32:
4492 case RENDERPATH_GLES2:
4495 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4496 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4497 GL_DepthFunc(GL_ALWAYS);
4498 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4499 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4500 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4501 qglEndQuery(GL_SAMPLES_PASSED);
4502 GL_DepthFunc(GL_LEQUAL);
4503 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4504 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4505 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4506 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4507 qglEndQuery(GL_SAMPLES_PASSED);
4513 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4516 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4518 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4521 unsigned int occlude = 0;
4523 // now we have to check the query result
4524 if (rtlight->corona_queryindex_visiblepixels)
4526 switch(vid.renderpath)
4528 case RENDERPATH_GL32:
4529 case RENDERPATH_GLES2:
4531 // store the pixel counts into a uniform buffer for the shader to
4532 // use - we'll never know the results on the cpu without
4533 // synchronizing and we don't want that
4534 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4535 if (!r_shadow_occlusion_buf) {
4536 qglGenBuffers(1, &r_shadow_occlusion_buf);
4537 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4538 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4540 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4542 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4543 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4544 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4545 occlude = MATERIALFLAG_OCCLUDE;
4546 cscale *= rtlight->corona_visibility;
4556 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4559 VectorScale(rtlight->currentcolor, cscale, color);
4560 if (VectorLength(color) > (1.0f / 256.0f))
4563 qboolean negated = (color[0] + color[1] + color[2] < 0);
4566 VectorNegate(color, color);
4567 GL_BlendEquationSubtract(true);
4569 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4570 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4571 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4573 GL_BlendEquationSubtract(false);
4577 void R_Shadow_DrawCoronas(void)
4580 qboolean usequery = false;
4585 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4587 if (r_fb.water.renderingscene)
4589 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4590 R_EntityMatrix(&identitymatrix);
4592 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4594 // check occlusion of coronas, using occlusion queries or raytraces
4596 switch (vid.renderpath)
4598 case RENDERPATH_GL32:
4599 case RENDERPATH_GLES2:
4600 usequery = r_coronas_occlusionquery.integer;
4604 GL_ColorMask(0,0,0,0);
4605 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4606 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4609 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4610 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4612 qglGenQueries(r_maxqueries - i, r_queries + i);
4615 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4616 GL_BlendFunc(GL_ONE, GL_ZERO);
4617 GL_CullFace(GL_NONE);
4618 GL_DepthMask(false);
4619 GL_DepthRange(0, 1);
4620 GL_PolygonOffset(0, 0);
4622 R_Mesh_ResetTextureState();
4623 R_SetupShader_Generic_NoTexture(false, false);
4628 for (lightindex = 0;lightindex < range;lightindex++)
4630 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4633 rtlight = &light->rtlight;
4634 rtlight->corona_visibility = 0;
4635 rtlight->corona_queryindex_visiblepixels = 0;
4636 rtlight->corona_queryindex_allpixels = 0;
4637 if (!(rtlight->flags & flag))
4639 if (rtlight->corona <= 0)
4641 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4643 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4645 for (i = 0;i < r_refdef.scene.numlights;i++)
4647 rtlight = r_refdef.scene.lights[i];
4648 rtlight->corona_visibility = 0;
4649 rtlight->corona_queryindex_visiblepixels = 0;
4650 rtlight->corona_queryindex_allpixels = 0;
4651 if (!(rtlight->flags & flag))
4653 if (rtlight->corona <= 0)
4655 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4658 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4660 // now draw the coronas using the query data for intensity info
4661 for (lightindex = 0;lightindex < range;lightindex++)
4663 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4666 rtlight = &light->rtlight;
4667 if (rtlight->corona_visibility <= 0)
4669 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4671 for (i = 0;i < r_refdef.scene.numlights;i++)
4673 rtlight = r_refdef.scene.lights[i];
4674 if (rtlight->corona_visibility <= 0)
4676 if (gl_flashblend.integer)
4677 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4679 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4685 static dlight_t *R_Shadow_NewWorldLight(void)
4687 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4690 static void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
4694 // note that style is no longer validated here, -1 is used for unstyled lights and >= MAX_LIGHTSTYLES is accepted for sake of editing rtlights files that might be out of bounds but perfectly formatted
4696 // validate parameters
4700 // copy to light properties
4701 VectorCopy(origin, light->origin);
4702 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4703 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4704 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4706 light->color[0] = max(color[0], 0);
4707 light->color[1] = max(color[1], 0);
4708 light->color[2] = max(color[2], 0);
4710 light->color[0] = color[0];
4711 light->color[1] = color[1];
4712 light->color[2] = color[2];
4713 light->radius = max(radius, 0);
4714 light->style = style;
4715 light->shadow = shadowenable;
4716 light->corona = corona;
4717 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4718 light->coronasizescale = coronasizescale;
4719 light->ambientscale = ambientscale;
4720 light->diffusescale = diffusescale;
4721 light->specularscale = specularscale;
4722 light->flags = flags;
4724 // update renderable light data
4725 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4726 R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
4729 static void R_Shadow_FreeWorldLight(dlight_t *light)
4731 if (r_shadow_selectedlight == light)
4732 r_shadow_selectedlight = NULL;
4733 R_RTLight_Uncompile(&light->rtlight);
4734 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4737 void R_Shadow_ClearWorldLights(void)
4741 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4742 for (lightindex = 0;lightindex < range;lightindex++)
4744 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4746 R_Shadow_FreeWorldLight(light);
4748 r_shadow_selectedlight = NULL;
4751 static void R_Shadow_SelectLight(dlight_t *light)
4753 if (r_shadow_selectedlight)
4754 r_shadow_selectedlight->selected = false;
4755 r_shadow_selectedlight = light;
4756 if (r_shadow_selectedlight)
4757 r_shadow_selectedlight->selected = true;
4760 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4762 // this is never batched (there can be only one)
4764 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4765 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4766 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4769 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4774 skinframe_t *skinframe;
4777 // this is never batched (due to the ent parameter changing every time)
4778 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4779 const dlight_t *light = (dlight_t *)ent;
4782 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4785 VectorScale(light->color, intensity, spritecolor);
4786 if (VectorLength(spritecolor) < 0.1732f)
4787 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4788 if (VectorLength(spritecolor) > 1.0f)
4789 VectorNormalize(spritecolor);
4791 // draw light sprite
4792 if (light->cubemapname[0] && !light->shadow)
4793 skinframe = r_editlights_sprcubemapnoshadowlight;
4794 else if (light->cubemapname[0])
4795 skinframe = r_editlights_sprcubemaplight;
4796 else if (!light->shadow)
4797 skinframe = r_editlights_sprnoshadowlight;
4799 skinframe = r_editlights_sprlight;
4801 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, spritecolor[0], spritecolor[1], spritecolor[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4802 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4804 // draw selection sprite if light is selected
4805 if (light->selected)
4807 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4808 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4809 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4813 void R_Shadow_DrawLightSprites(void)
4817 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4818 for (lightindex = 0;lightindex < range;lightindex++)
4820 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4822 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4824 if (!r_editlights_lockcursor)
4825 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4828 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4833 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4834 if (lightindex >= range)
4836 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4839 rtlight = &light->rtlight;
4840 //if (!(rtlight->flags & flag))
4842 VectorCopy(rtlight->shadoworigin, origin);
4843 *radius = rtlight->radius;
4844 VectorCopy(rtlight->color, color);
4848 static void R_Shadow_SelectLightInView(void)
4850 float bestrating, rating, temp[3];
4854 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4858 if (r_editlights_lockcursor)
4860 for (lightindex = 0;lightindex < range;lightindex++)
4862 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4865 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4866 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4869 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4870 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
4872 bestrating = rating;
4877 R_Shadow_SelectLight(best);
4880 void R_Shadow_LoadWorldLights(void)
4882 int n, a, style, shadow, flags;
4883 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4884 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4885 if (cl.worldmodel == NULL)
4887 Con_Print("No map loaded.\n");
4890 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4891 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4901 for (;COM_Parse(t, true) && strcmp(
4902 if (COM_Parse(t, true))
4904 if (com_token[0] == '!')
4907 origin[0] = atof(com_token+1);
4910 origin[0] = atof(com_token);
4915 while (*s && *s != '\n' && *s != '\r')
4921 // check for modifier flags
4928 #if _MSC_VER >= 1400
4929 #define sscanf sscanf_s
4931 cubemapname[sizeof(cubemapname)-1] = 0;
4932 #if MAX_QPATH != 128
4933 #error update this code if MAX_QPATH changes
4935 a = sscanf(t, "%f %f %f %f %f %f %f %d %127s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname
4936 #if _MSC_VER >= 1400
4937 , (unsigned int)sizeof(cubemapname)
4939 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4942 flags = LIGHTFLAG_REALTIMEMODE;
4950 coronasizescale = 0.25f;
4952 VectorClear(angles);
4955 if (a < 9 || !strcmp(cubemapname, "\"\""))
4957 // remove quotes on cubemapname
4958 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4961 namelen = strlen(cubemapname) - 2;
4962 memmove(cubemapname, cubemapname + 1, namelen);
4963 cubemapname[namelen] = '\0';
4967 Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1);
4970 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4978 Con_Printf("invalid rtlights file \"%s\"\n", name);
4979 Mem_Free(lightsstring);
4983 void R_Shadow_SaveWorldLights(void)
4987 size_t bufchars, bufmaxchars;
4989 char name[MAX_QPATH];
4990 char line[MAX_INPUTLINE];
4991 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4992 // I hate lines which are 3 times my screen size :( --blub
4995 if (cl.worldmodel == NULL)
4997 Con_Print("No map loaded.\n");
5000 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5001 bufchars = bufmaxchars = 0;
5003 for (lightindex = 0;lightindex < range;lightindex++)
5005 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5008 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5009 dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
5010 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5011 dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
5013 dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style);
5014 if (bufchars + strlen(line) > bufmaxchars)
5016 bufmaxchars = bufchars + strlen(line) + 2048;
5018 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5022 memcpy(buf, oldbuf, bufchars);
5028 memcpy(buf + bufchars, line, strlen(line));
5029 bufchars += strlen(line);
5033 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5038 void R_Shadow_LoadLightsFile(void)
5041 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5042 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5043 if (cl.worldmodel == NULL)
5045 Con_Print("No map loaded.\n");
5048 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5049 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5057 while (*s && *s != '\n' && *s != '\r')
5063 a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style);
5067 Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
5070 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5071 radius = bound(15, radius, 4096);
5072 VectorScale(color, (2.0f / (8388608.0f)), color);
5073 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5081 Con_Printf("invalid lights file \"%s\"\n", name);
5082 Mem_Free(lightsstring);
5086 // tyrlite/hmap2 light types in the delay field
5087 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5089 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5101 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5102 char key[256], value[MAX_INPUTLINE];
5105 if (cl.worldmodel == NULL)
5107 Con_Print("No map loaded.\n");
5110 // try to load a .ent file first
5111 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5112 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5113 // and if that is not found, fall back to the bsp file entity string
5115 data = cl.worldmodel->brush.entities;
5118 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5120 type = LIGHTTYPE_MINUSX;
5121 origin[0] = origin[1] = origin[2] = 0;
5122 originhack[0] = originhack[1] = originhack[2] = 0;
5123 angles[0] = angles[1] = angles[2] = 0;
5124 color[0] = color[1] = color[2] = 1;
5125 light[0] = light[1] = light[2] = 1;light[3] = 300;
5126 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5136 if (!COM_ParseToken_Simple(&data, false, false, true))
5138 if (com_token[0] == '}')
5139 break; // end of entity
5140 if (com_token[0] == '_')
5141 strlcpy(key, com_token + 1, sizeof(key));
5143 strlcpy(key, com_token, sizeof(key));
5144 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5145 key[strlen(key)-1] = 0;
5146 if (!COM_ParseToken_Simple(&data, false, false, true))
5148 strlcpy(value, com_token, sizeof(value));
5150 // now that we have the key pair worked out...
5151 if (!strcmp("light", key))
5153 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5157 light[0] = vec[0] * (1.0f / 256.0f);
5158 light[1] = vec[0] * (1.0f / 256.0f);
5159 light[2] = vec[0] * (1.0f / 256.0f);
5165 light[0] = vec[0] * (1.0f / 255.0f);
5166 light[1] = vec[1] * (1.0f / 255.0f);
5167 light[2] = vec[2] * (1.0f / 255.0f);
5171 else if (!strcmp("delay", key))
5173 else if (!strcmp("origin", key))
5174 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5175 else if (!strcmp("angle", key))
5176 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5177 else if (!strcmp("angles", key))
5178 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5179 else if (!strcmp("color", key))
5180 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5181 else if (!strcmp("wait", key))
5182 fadescale = atof(value);
5183 else if (!strcmp("classname", key))
5185 if (!strncmp(value, "light", 5))
5188 if (!strcmp(value, "light_fluoro"))
5193 overridecolor[0] = 1;
5194 overridecolor[1] = 1;
5195 overridecolor[2] = 1;
5197 if (!strcmp(value, "light_fluorospark"))
5202 overridecolor[0] = 1;
5203 overridecolor[1] = 1;
5204 overridecolor[2] = 1;
5206 if (!strcmp(value, "light_globe"))
5211 overridecolor[0] = 1;
5212 overridecolor[1] = 0.8;
5213 overridecolor[2] = 0.4;
5215 if (!strcmp(value, "light_flame_large_yellow"))
5220 overridecolor[0] = 1;
5221 overridecolor[1] = 0.5;
5222 overridecolor[2] = 0.1;
5224 if (!strcmp(value, "light_flame_small_yellow"))
5229 overridecolor[0] = 1;
5230 overridecolor[1] = 0.5;
5231 overridecolor[2] = 0.1;
5233 if (!strcmp(value, "light_torch_small_white"))
5238 overridecolor[0] = 1;
5239 overridecolor[1] = 0.5;
5240 overridecolor[2] = 0.1;
5242 if (!strcmp(value, "light_torch_small_walltorch"))
5247 overridecolor[0] = 1;
5248 overridecolor[1] = 0.5;
5249 overridecolor[2] = 0.1;
5253 else if (!strcmp("style", key))
5254 style = atoi(value);
5255 else if (!strcmp("skin", key))
5256 skin = (int)atof(value);
5257 else if (!strcmp("pflags", key))
5258 pflags = (int)atof(value);
5259 //else if (!strcmp("effects", key))
5260 // effects = (int)atof(value);
5261 else if (cl.worldmodel->type == mod_brushq3)
5263 if (!strcmp("scale", key))
5264 lightscale = atof(value);
5265 if (!strcmp("fade", key))
5266 fadescale = atof(value);
5271 if (lightscale <= 0)
5275 if (color[0] == color[1] && color[0] == color[2])
5277 color[0] *= overridecolor[0];
5278 color[1] *= overridecolor[1];
5279 color[2] *= overridecolor[2];
5281 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5282 color[0] = color[0] * light[0];
5283 color[1] = color[1] * light[1];
5284 color[2] = color[2] * light[2];
5287 case LIGHTTYPE_MINUSX:
5289 case LIGHTTYPE_RECIPX:
5291 VectorScale(color, (1.0f / 16.0f), color);
5293 case LIGHTTYPE_RECIPXX:
5295 VectorScale(color, (1.0f / 16.0f), color);
5298 case LIGHTTYPE_NONE:
5302 case LIGHTTYPE_MINUSXX:
5305 VectorAdd(origin, originhack, origin);
5307 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5310 Mem_Free(entfiledata);
5314 static void R_Shadow_SetCursorLocationForView(void)
5317 vec3_t dest, endpos;
5319 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5320 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5321 if (trace.fraction < 1)
5323 dist = trace.fraction * r_editlights_cursordistance.value;
5324 push = r_editlights_cursorpushback.value;
5328 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5329 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5333 VectorClear( endpos );
5335 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5336 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5337 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5340 void R_Shadow_UpdateWorldLightSelection(void)
5342 if (r_editlights.integer)
5344 R_Shadow_SetCursorLocationForView();
5345 R_Shadow_SelectLightInView();
5348 R_Shadow_SelectLight(NULL);
5351 static void R_Shadow_EditLights_Clear_f(cmd_state_t *cmd)
5353 R_Shadow_ClearWorldLights();
5356 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd)
5360 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5361 R_Shadow_ClearWorldLights();
5362 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5364 R_Shadow_LoadWorldLights();
5365 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5366 R_Shadow_LoadLightsFile();
5368 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5370 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5371 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5375 static void R_Shadow_EditLights_Save_f(cmd_state_t *cmd)
5379 R_Shadow_SaveWorldLights();
5382 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(cmd_state_t *cmd)
5384 R_Shadow_ClearWorldLights();
5385 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5388 static void R_Shadow_EditLights_ImportLightsFile_f(cmd_state_t *cmd)
5390 R_Shadow_ClearWorldLights();
5391 R_Shadow_LoadLightsFile();
5394 static void R_Shadow_EditLights_Spawn_f(cmd_state_t *cmd)
5397 if (!r_editlights.integer)
5399 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5402 if (Cmd_Argc(cmd) != 1)
5404 Con_Print("r_editlights_spawn does not take parameters\n");
5407 color[0] = color[1] = color[2] = 1;
5408 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5411 static void R_Shadow_EditLights_Edit_f(cmd_state_t *cmd)
5413 vec3_t origin, angles, color;
5414 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5415 int style, shadows, flags, normalmode, realtimemode;
5416 char cubemapname[MAX_INPUTLINE];
5417 if (!r_editlights.integer)
5419 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5422 if (!r_shadow_selectedlight)
5424 Con_Print("No selected light.\n");
5427 VectorCopy(r_shadow_selectedlight->origin, origin);
5428 VectorCopy(r_shadow_selectedlight->angles, angles);
5429 VectorCopy(r_shadow_selectedlight->color, color);
5430 radius = r_shadow_selectedlight->radius;
5431 style = r_shadow_selectedlight->style;
5432 if (r_shadow_selectedlight->cubemapname)
5433 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5436 shadows = r_shadow_selectedlight->shadow;
5437 corona = r_shadow_selectedlight->corona;
5438 coronasizescale = r_shadow_selectedlight->coronasizescale;
5439 ambientscale = r_shadow_selectedlight->ambientscale;
5440 diffusescale = r_shadow_selectedlight->diffusescale;
5441 specularscale = r_shadow_selectedlight->specularscale;
5442 flags = r_shadow_selectedlight->flags;
5443 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5444 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5445 if (!strcmp(Cmd_Argv(cmd, 1), "origin"))
5447 if (Cmd_Argc(cmd) != 5)
5449 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5452 origin[0] = atof(Cmd_Argv(cmd, 2));
5453 origin[1] = atof(Cmd_Argv(cmd, 3));
5454 origin[2] = atof(Cmd_Argv(cmd, 4));
5456 else if (!strcmp(Cmd_Argv(cmd, 1), "originscale"))
5458 if (Cmd_Argc(cmd) != 5)
5460 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5463 origin[0] *= atof(Cmd_Argv(cmd, 2));
5464 origin[1] *= atof(Cmd_Argv(cmd, 3));
5465 origin[2] *= atof(Cmd_Argv(cmd, 4));
5467 else if (!strcmp(Cmd_Argv(cmd, 1), "originx"))
5469 if (Cmd_Argc(cmd) != 3)
5471 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5474 origin[0] = atof(Cmd_Argv(cmd, 2));
5476 else if (!strcmp(Cmd_Argv(cmd, 1), "originy"))
5478 if (Cmd_Argc(cmd) != 3)
5480 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5483 origin[1] = atof(Cmd_Argv(cmd, 2));
5485 else if (!strcmp(Cmd_Argv(cmd, 1), "originz"))
5487 if (Cmd_Argc(cmd) != 3)
5489 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5492 origin[2] = atof(Cmd_Argv(cmd, 2));
5494 else if (!strcmp(Cmd_Argv(cmd, 1), "move"))
5496 if (Cmd_Argc(cmd) != 5)
5498 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5501 origin[0] += atof(Cmd_Argv(cmd, 2));
5502 origin[1] += atof(Cmd_Argv(cmd, 3));
5503 origin[2] += atof(Cmd_Argv(cmd, 4));
5505 else if (!strcmp(Cmd_Argv(cmd, 1), "movex"))
5507 if (Cmd_Argc(cmd) != 3)
5509 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5512 origin[0] += atof(Cmd_Argv(cmd, 2));
5514 else if (!strcmp(Cmd_Argv(cmd, 1), "movey"))
5516 if (Cmd_Argc(cmd) != 3)
5518 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5521 origin[1] += atof(Cmd_Argv(cmd, 2));
5523 else if (!strcmp(Cmd_Argv(cmd, 1), "movez"))
5525 if (Cmd_Argc(cmd) != 3)
5527 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5530 origin[2] += atof(Cmd_Argv(cmd, 2));
5532 else if (!strcmp(Cmd_Argv(cmd, 1), "angles"))
5534 if (Cmd_Argc(cmd) != 5)
5536 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5539 angles[0] = atof(Cmd_Argv(cmd, 2));
5540 angles[1] = atof(Cmd_Argv(cmd, 3));
5541 angles[2] = atof(Cmd_Argv(cmd, 4));
5543 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesx"))
5545 if (Cmd_Argc(cmd) != 3)
5547 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5550 angles[0] = atof(Cmd_Argv(cmd, 2));
5552 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesy"))
5554 if (Cmd_Argc(cmd) != 3)
5556 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5559 angles[1] = atof(Cmd_Argv(cmd, 2));
5561 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesz"))
5563 if (Cmd_Argc(cmd) != 3)
5565 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5568 angles[2] = atof(Cmd_Argv(cmd, 2));
5570 else if (!strcmp(Cmd_Argv(cmd, 1), "color"))
5572 if (Cmd_Argc(cmd) != 5)
5574 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(cmd, 1));
5577 color[0] = atof(Cmd_Argv(cmd, 2));
5578 color[1] = atof(Cmd_Argv(cmd, 3));
5579 color[2] = atof(Cmd_Argv(cmd, 4));
5581 else if (!strcmp(Cmd_Argv(cmd, 1), "radius"))
5583 if (Cmd_Argc(cmd) != 3)
5585 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5588 radius = atof(Cmd_Argv(cmd, 2));
5590 else if (!strcmp(Cmd_Argv(cmd, 1), "colorscale"))
5592 if (Cmd_Argc(cmd) == 3)
5594 double scale = atof(Cmd_Argv(cmd, 2));
5601 if (Cmd_Argc(cmd) != 5)
5603 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(cmd, 1));
5606 color[0] *= atof(Cmd_Argv(cmd, 2));
5607 color[1] *= atof(Cmd_Argv(cmd, 3));
5608 color[2] *= atof(Cmd_Argv(cmd, 4));
5611 else if (!strcmp(Cmd_Argv(cmd, 1), "radiusscale") || !strcmp(Cmd_Argv(cmd, 1), "sizescale"))
5613 if (Cmd_Argc(cmd) != 3)
5615 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5618 radius *= atof(Cmd_Argv(cmd, 2));
5620 else if (!strcmp(Cmd_Argv(cmd, 1), "style"))
5622 if (Cmd_Argc(cmd) != 3)
5624 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5627 style = atoi(Cmd_Argv(cmd, 2));
5629 else if (!strcmp(Cmd_Argv(cmd, 1), "cubemap"))
5631 if (Cmd_Argc(cmd) > 3)
5633 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5636 if (Cmd_Argc(cmd) == 3)
5637 strlcpy(cubemapname, Cmd_Argv(cmd, 2), sizeof(cubemapname));
5641 else if (!strcmp(Cmd_Argv(cmd, 1), "shadows"))
5643 if (Cmd_Argc(cmd) != 3)
5645 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5648 shadows = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5650 else if (!strcmp(Cmd_Argv(cmd, 1), "corona"))
5652 if (Cmd_Argc(cmd) != 3)
5654 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5657 corona = atof(Cmd_Argv(cmd, 2));
5659 else if (!strcmp(Cmd_Argv(cmd, 1), "coronasize"))
5661 if (Cmd_Argc(cmd) != 3)
5663 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5666 coronasizescale = atof(Cmd_Argv(cmd, 2));
5668 else if (!strcmp(Cmd_Argv(cmd, 1), "ambient"))
5670 if (Cmd_Argc(cmd) != 3)
5672 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5675 ambientscale = atof(Cmd_Argv(cmd, 2));
5677 else if (!strcmp(Cmd_Argv(cmd, 1), "diffuse"))
5679 if (Cmd_Argc(cmd) != 3)
5681 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5684 diffusescale = atof(Cmd_Argv(cmd, 2));
5686 else if (!strcmp(Cmd_Argv(cmd, 1), "specular"))
5688 if (Cmd_Argc(cmd) != 3)
5690 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5693 specularscale = atof(Cmd_Argv(cmd, 2));
5695 else if (!strcmp(Cmd_Argv(cmd, 1), "normalmode"))
5697 if (Cmd_Argc(cmd) != 3)
5699 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5702 normalmode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5704 else if (!strcmp(Cmd_Argv(cmd, 1), "realtimemode"))
5706 if (Cmd_Argc(cmd) != 3)
5708 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5711 realtimemode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5715 Con_Print("usage: r_editlights_edit [property] [value]\n");
5716 Con_Print("Selected light's properties:\n");
5717 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5718 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5719 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5720 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5721 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5722 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5723 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5724 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5725 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5726 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5727 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5728 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5729 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5730 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5733 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5734 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5737 static void R_Shadow_EditLights_EditAll_f(cmd_state_t *cmd)
5740 dlight_t *light, *oldselected;
5743 if (!r_editlights.integer)
5745 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5749 oldselected = r_shadow_selectedlight;
5750 // EditLights doesn't seem to have a "remove" command or something so:
5751 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5752 for (lightindex = 0;lightindex < range;lightindex++)
5754 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5757 R_Shadow_SelectLight(light);
5758 R_Shadow_EditLights_Edit_f(&cmd_client);
5760 // return to old selected (to not mess editing once selection is locked)
5761 R_Shadow_SelectLight(oldselected);
5764 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5766 int lightnumber, lightcount;
5767 size_t lightindex, range;
5772 if (!r_editlights.integer)
5775 // update cvars so QC can query them
5776 if (r_shadow_selectedlight)
5778 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5779 Cvar_SetQuick(&r_editlights_current_origin, temp);
5780 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5781 Cvar_SetQuick(&r_editlights_current_angles, temp);
5782 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5783 Cvar_SetQuick(&r_editlights_current_color, temp);
5784 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5785 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5786 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5787 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5788 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5789 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5790 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5791 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5792 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5793 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5794 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5797 // draw properties on screen
5798 if (!r_editlights_drawproperties.integer)
5800 x = vid_conwidth.value - 320;
5802 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5805 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5806 for (lightindex = 0;lightindex < range;lightindex++)
5808 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5811 if (light == r_shadow_selectedlight)
5812 lightnumber = (int)lightindex;
5815 dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5816 dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5818 if (r_shadow_selectedlight == NULL)
5820 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5821 dpsnprintf(temp, sizeof(temp), "Origin : %.0f %.0f %.0f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5822 dpsnprintf(temp, sizeof(temp), "Angles : %.0f %.0f %.0f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5823 dpsnprintf(temp, sizeof(temp), "Color : %.2f %.2f %.2f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5824 dpsnprintf(temp, sizeof(temp), "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5825 dpsnprintf(temp, sizeof(temp), "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5826 dpsnprintf(temp, sizeof(temp), "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5827 dpsnprintf(temp, sizeof(temp), "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5828 dpsnprintf(temp, sizeof(temp), "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5829 dpsnprintf(temp, sizeof(temp), "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5830 dpsnprintf(temp, sizeof(temp), "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5831 dpsnprintf(temp, sizeof(temp), "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5832 dpsnprintf(temp, sizeof(temp), "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5833 dpsnprintf(temp, sizeof(temp), "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5834 dpsnprintf(temp, sizeof(temp), "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5836 dpsnprintf(temp, sizeof(temp), "Render stats\n"); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5837 dpsnprintf(temp, sizeof(temp), "Current color: %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.currentcolor[0], r_shadow_selectedlight->rtlight.currentcolor[1], r_shadow_selectedlight->rtlight.currentcolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5838 dpsnprintf(temp, sizeof(temp), "Shadow size : %ix%ix6\n", r_shadow_selectedlight->rtlight.shadowmapatlassidesize, r_shadow_selectedlight->rtlight.shadowmapatlassidesize); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5839 dpsnprintf(temp, sizeof(temp), "World surfs : %i\n", r_shadow_selectedlight->rtlight.cached_numsurfaces); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5840 dpsnprintf(temp, sizeof(temp), "Shadow ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numshadowentities, r_shadow_selectedlight->rtlight.cached_numshadowentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5841 dpsnprintf(temp, sizeof(temp), "Lit ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numlightentities, r_shadow_selectedlight->rtlight.cached_numlightentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5842 dpsnprintf(temp, sizeof(temp), "BG photons : %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photons); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5843 dpsnprintf(temp, sizeof(temp), "BG radius : %.0f\n", r_shadow_selectedlight->rtlight.bouncegrid_effectiveradius); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5844 dpsnprintf(temp, sizeof(temp), "BG color : %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[0], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[1], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5845 dpsnprintf(temp, sizeof(temp), "BG stats : %i traces %i hits\n", r_shadow_selectedlight->rtlight.bouncegrid_traces, r_shadow_selectedlight->rtlight.bouncegrid_hits); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
5848 static void R_Shadow_EditLights_ToggleShadow_f(cmd_state_t *cmd)
5850 if (!r_editlights.integer)
5852 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5855 if (!r_shadow_selectedlight)
5857 Con_Print("No selected light.\n");
5860 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
5863 static void R_Shadow_EditLights_ToggleCorona_f(cmd_state_t *cmd)
5865 if (!r_editlights.integer)
5867 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5870 if (!r_shadow_selectedlight)
5872 Con_Print("No selected light.\n");
5875 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
5878 static void R_Shadow_EditLights_Remove_f(cmd_state_t *cmd)
5880 if (!r_editlights.integer)
5882 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5885 if (!r_shadow_selectedlight)
5887 Con_Print("No selected light.\n");
5890 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5891 r_shadow_selectedlight = NULL;
5894 static void R_Shadow_EditLights_Help_f(cmd_state_t *cmd)
5897 "Documentation on r_editlights system:\n"
5899 "r_editlights : enable/disable editing mode\n"
5900 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5901 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5902 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5903 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5904 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5906 "r_editlights_help : this help\n"
5907 "r_editlights_clear : remove all lights\n"
5908 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5909 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5910 "r_editlights_save : save to .rtlights file\n"
5911 "r_editlights_spawn : create a light with default settings\n"
5912 "r_editlights_edit command : edit selected light - more documentation below\n"
5913 "r_editlights_remove : remove selected light\n"
5914 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5915 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5916 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5918 "origin x y z : set light location\n"
5919 "originx x: set x component of light location\n"
5920 "originy y: set y component of light location\n"
5921 "originz z: set z component of light location\n"
5922 "move x y z : adjust light location\n"
5923 "movex x: adjust x component of light location\n"
5924 "movey y: adjust y component of light location\n"
5925 "movez z: adjust z component of light location\n"
5926 "angles x y z : set light angles\n"
5927 "anglesx x: set x component of light angles\n"
5928 "anglesy y: set y component of light angles\n"
5929 "anglesz z: set z component of light angles\n"
5930 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5931 "radius radius : set radius (size) of light\n"
5932 "colorscale grey : multiply color of light (1 does nothing)\n"
5933 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5934 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5935 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5936 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5937 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5938 "cubemap basename : set filter cubemap of light\n"
5939 "shadows 1/0 : turn on/off shadows\n"
5940 "corona n : set corona intensity\n"
5941 "coronasize n : set corona size (0-1)\n"
5942 "ambient n : set ambient intensity (0-1)\n"
5943 "diffuse n : set diffuse intensity (0-1)\n"
5944 "specular n : set specular intensity (0-1)\n"
5945 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5946 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5947 "<nothing> : print light properties to console\n"
5951 static void R_Shadow_EditLights_CopyInfo_f(cmd_state_t *cmd)
5953 if (!r_editlights.integer)
5955 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5958 if (!r_shadow_selectedlight)
5960 Con_Print("No selected light.\n");
5963 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5964 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5965 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5966 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5967 if (r_shadow_selectedlight->cubemapname)
5968 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5970 r_shadow_bufferlight.cubemapname[0] = 0;
5971 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5972 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5973 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5974 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5975 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5976 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5977 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5980 static void R_Shadow_EditLights_PasteInfo_f(cmd_state_t *cmd)
5982 if (!r_editlights.integer)
5984 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5987 if (!r_shadow_selectedlight)
5989 Con_Print("No selected light.\n");
5992 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
5995 static void R_Shadow_EditLights_Lock_f(cmd_state_t *cmd)
5997 if (!r_editlights.integer)
5999 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6002 if (r_editlights_lockcursor)
6004 r_editlights_lockcursor = false;
6007 if (!r_shadow_selectedlight)
6009 Con_Print("No selected light to lock on.\n");
6012 r_editlights_lockcursor = true;
6015 static void R_Shadow_EditLights_Init(void)
6017 Cvar_RegisterVariable(&r_editlights);
6018 Cvar_RegisterVariable(&r_editlights_cursordistance);
6019 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6020 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6021 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6022 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6023 Cvar_RegisterVariable(&r_editlights_drawproperties);
6024 Cvar_RegisterVariable(&r_editlights_current_origin);
6025 Cvar_RegisterVariable(&r_editlights_current_angles);
6026 Cvar_RegisterVariable(&r_editlights_current_color);
6027 Cvar_RegisterVariable(&r_editlights_current_radius);
6028 Cvar_RegisterVariable(&r_editlights_current_corona);
6029 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6030 Cvar_RegisterVariable(&r_editlights_current_style);
6031 Cvar_RegisterVariable(&r_editlights_current_shadows);
6032 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6033 Cvar_RegisterVariable(&r_editlights_current_ambient);
6034 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6035 Cvar_RegisterVariable(&r_editlights_current_specular);
6036 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6037 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6038 Cmd_AddCommand(&cmd_client, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6039 Cmd_AddCommand(&cmd_client, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6040 Cmd_AddCommand(&cmd_client, "r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
6041 Cmd_AddCommand(&cmd_client, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6042 Cmd_AddCommand(&cmd_client, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6043 Cmd_AddCommand(&cmd_client, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6044 Cmd_AddCommand(&cmd_client, "r_editlights_editall", R_Shadow_EditLights_EditAll_f, "changes a property on ALL lights at once (tip: use radiusscale and colorscale to alter these properties)");
6045 Cmd_AddCommand(&cmd_client, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6046 Cmd_AddCommand(&cmd_client, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6047 Cmd_AddCommand(&cmd_client, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6048 Cmd_AddCommand(&cmd_client, "r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6049 Cmd_AddCommand(&cmd_client, "r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6050 Cmd_AddCommand(&cmd_client, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6051 Cmd_AddCommand(&cmd_client, "r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
6052 Cmd_AddCommand(&cmd_client, "r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6058 =============================================================================
6062 =============================================================================
6065 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6067 int i, numlights, flag, q;
6070 float relativepoint[3];
6075 float sa[3], sx[3], sy[3], sz[3], sd[3];
6078 // use first order spherical harmonics to combine directional lights
6079 for (q = 0; q < 3; q++)
6080 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6082 if (flags & LP_LIGHTMAP)
6084 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6086 float tempambient[3];
6087 for (q = 0; q < 3; q++)
6088 tempambient[q] = color[q] = relativepoint[q] = 0;
6089 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6090 // calculate a weighted average light direction as well
6091 intensity = VectorLength(color);
6092 for (q = 0; q < 3; q++)
6094 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6095 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6096 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6097 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6098 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6103 // unlit map - fullbright but scaled by lightmapintensity
6104 for (q = 0; q < 3; q++)
6105 sa[q] += lightmapintensity;
6109 if (flags & LP_RTWORLD)
6111 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6112 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6113 for (i = 0; i < numlights; i++)
6115 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6118 light = &dlight->rtlight;
6119 if (!(light->flags & flag))
6122 lightradius2 = light->radius * light->radius;
6123 VectorSubtract(light->shadoworigin, p, relativepoint);
6124 dist2 = VectorLength2(relativepoint);
6125 if (dist2 >= lightradius2)
6127 dist = sqrt(dist2) / light->radius;
6128 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6129 if (intensity <= 0.0f)
6131 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6133 for (q = 0; q < 3; q++)
6134 color[q] = light->currentcolor[q] * intensity;
6135 intensity = VectorLength(color);
6136 VectorNormalize(relativepoint);
6137 for (q = 0; q < 3; q++)
6139 sa[q] += 0.5f * color[q];
6140 sx[q] += relativepoint[0] * color[q];
6141 sy[q] += relativepoint[1] * color[q];
6142 sz[q] += relativepoint[2] * color[q];
6143 sd[q] += intensity * relativepoint[q];
6146 // FIXME: sample bouncegrid too!
6149 if (flags & LP_DYNLIGHT)
6152 for (i = 0;i < r_refdef.scene.numlights;i++)
6154 light = r_refdef.scene.lights[i];
6156 lightradius2 = light->radius * light->radius;
6157 VectorSubtract(light->shadoworigin, p, relativepoint);
6158 dist2 = VectorLength2(relativepoint);
6159 if (dist2 >= lightradius2)
6161 dist = sqrt(dist2) / light->radius;
6162 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6163 if (intensity <= 0.0f)
6165 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6167 for (q = 0; q < 3; q++)
6168 color[q] = light->currentcolor[q] * intensity;
6169 intensity = VectorLength(color);
6170 VectorNormalize(relativepoint);
6171 for (q = 0; q < 3; q++)
6173 sa[q] += 0.5f * color[q];
6174 sx[q] += relativepoint[0] * color[q];
6175 sy[q] += relativepoint[1] * color[q];
6176 sz[q] += relativepoint[2] * color[q];
6177 sd[q] += intensity * relativepoint[q];
6182 // calculate the weighted-average light direction (bentnormal)
6183 for (q = 0; q < 3; q++)
6184 lightdir[q] = sd[q];
6185 VectorNormalize(lightdir);
6186 for (q = 0; q < 3; q++)
6188 // extract the diffuse color along the chosen direction and scale it
6189 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6190 // subtract some of diffuse from ambient
6191 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;