3 #include "cl_collision.h"
7 static void R_Shadow_EditLights_Init(void);
9 typedef enum r_shadow_rendermode_e
11 R_SHADOW_RENDERMODE_NONE,
12 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
13 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
14 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
15 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
16 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
17 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
18 R_SHADOW_RENDERMODE_LIGHT_GLSL,
19 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
20 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
21 R_SHADOW_RENDERMODE_SHADOWMAP2D
23 r_shadow_rendermode_t;
25 typedef enum r_shadow_shadowmode_e
27 R_SHADOW_SHADOWMODE_SHADOWMAP2D
29 r_shadow_shadowmode_t;
31 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
32 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
33 int r_shadow_scenemaxlights;
34 int r_shadow_scenenumlights;
35 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
36 qboolean r_shadow_usingshadowmap2d;
37 qboolean r_shadow_usingshadowmaportho;
38 int r_shadow_shadowmapside;
39 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
40 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
41 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
42 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
44 int r_shadow_drawbuffer;
45 int r_shadow_readbuffer;
47 int r_shadow_cullface_front, r_shadow_cullface_back;
48 GLuint r_shadow_fbo2d;
49 r_shadow_shadowmode_t r_shadow_shadowmode;
50 int r_shadow_shadowmapfilterquality;
51 int r_shadow_shadowmapdepthbits;
52 int r_shadow_shadowmapmaxsize;
53 int r_shadow_shadowmaptexturesize;
54 qboolean r_shadow_shadowmapvsdct;
55 qboolean r_shadow_shadowmapsampler;
56 qboolean r_shadow_shadowmapshadowsampler;
57 int r_shadow_shadowmappcf;
58 int r_shadow_shadowmapborder;
59 matrix4x4_t r_shadow_shadowmapmatrix;
60 int r_shadow_lightscissor[4];
61 qboolean r_shadow_usingdeferredprepass;
62 qboolean r_shadow_shadowmapdepthtexture;
63 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
64 int r_shadow_shadowmapatlas_modelshadows_x;
65 int r_shadow_shadowmapatlas_modelshadows_y;
66 int r_shadow_shadowmapatlas_modelshadows_size;
67 int maxshadowtriangles;
70 int maxshadowvertices;
71 float *shadowvertex3f;
81 unsigned char *shadowsides;
89 int r_shadow_buffer_numleafpvsbytes;
90 unsigned char *r_shadow_buffer_visitingleafpvs;
91 unsigned char *r_shadow_buffer_leafpvs;
92 int *r_shadow_buffer_leaflist;
94 int r_shadow_buffer_numsurfacepvsbytes;
95 unsigned char *r_shadow_buffer_surfacepvs;
96 int *r_shadow_buffer_surfacelist;
97 unsigned char *r_shadow_buffer_surfacesides;
99 int r_shadow_buffer_numshadowtrispvsbytes;
100 unsigned char *r_shadow_buffer_shadowtrispvs;
101 int r_shadow_buffer_numlighttrispvsbytes;
102 unsigned char *r_shadow_buffer_lighttrispvs;
104 rtexturepool_t *r_shadow_texturepool;
105 rtexture_t *r_shadow_attenuationgradienttexture;
106 skinframe_t *r_shadow_lightcorona;
107 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
108 rtexture_t *r_shadow_shadowmap2ddepthtexture;
109 rtexture_t *r_shadow_shadowmapvsdcttexture;
111 GLuint r_shadow_prepassgeometryfbo;
112 GLuint r_shadow_prepasslightingdiffusespecularfbo;
113 GLuint r_shadow_prepasslightingdiffusefbo;
114 int r_shadow_prepass_width;
115 int r_shadow_prepass_height;
116 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
117 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
118 rtexture_t *r_shadow_prepasslightingdiffusetexture;
119 rtexture_t *r_shadow_prepasslightingspeculartexture;
121 int r_shadow_viewfbo;
122 rtexture_t *r_shadow_viewdepthtexture;
123 rtexture_t *r_shadow_viewcolortexture;
126 int r_shadow_viewwidth;
127 int r_shadow_viewheight;
129 // lights are reloaded when this changes
130 char r_shadow_mapname[MAX_QPATH];
132 // buffer for doing corona fading
133 unsigned int r_shadow_occlusion_buf = 0;
135 // used only for light filters (cubemaps)
136 rtexturepool_t *r_shadow_filters_texturepool;
138 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
139 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
140 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
141 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
142 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
143 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
144 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
145 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
146 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
147 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
148 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
149 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
150 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
151 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
152 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
153 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
154 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
155 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
156 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
157 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
158 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
159 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
160 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
161 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
162 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
163 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
164 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
165 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
166 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
167 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
168 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
169 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
170 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
171 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
172 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
173 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
174 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
175 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
176 cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
177 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
178 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
179 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
180 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
181 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
182 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
183 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
184 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
185 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
186 cvar_t r_shadow_culllights_pvs = {CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
187 cvar_t r_shadow_culllights_trace = {CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
188 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
189 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
190 cvar_t r_shadow_culllights_trace_expand = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
191 cvar_t r_shadow_culllights_trace_pad = {CVAR_SAVE, "r_shadow_culllights_trace_pad", "8", "accept traces that hit within this many units of the light bounds"};
192 cvar_t r_shadow_culllights_trace_samples = {CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
193 cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"};
194 cvar_t r_shadow_culllights_trace_delay = {CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
195 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
196 cvar_t r_shadow_bouncegrid_blur = {CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
197 cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"};
198 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color" };
199 cvar_t r_shadow_bouncegrid_dynamic_culllightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_culllightpaths", "1", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
200 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
201 cvar_t r_shadow_bouncegrid_dynamic_dlightparticlemultiplier = {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"};
202 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
203 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
204 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
205 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {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"};
206 cvar_t r_shadow_bouncegrid_dynamic_quality = {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)"};
207 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
208 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
209 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
210 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
211 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
212 cvar_t r_shadow_bouncegrid_floatcolors = {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"};
213 cvar_t r_shadow_bouncegrid_includedirectlighting = {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)"};
214 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
215 cvar_t r_shadow_bouncegrid_lightpathsize_conespread = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_conespread", "0.015625", "increase lightpathsize over distance at this rate per grid cell"};
216 cvar_t r_shadow_bouncegrid_lightpathsize_initial = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_initial", "0.5", "width (in grid cells) of the light path for accumulation of light in the bouncegrid texture"};
217 cvar_t r_shadow_bouncegrid_normalizevectors = { CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)" };
218 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "2", "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"};
219 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
220 cvar_t r_shadow_bouncegrid_rng_seed = { 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" };
221 cvar_t r_shadow_bouncegrid_rng_type = { CVAR_SAVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)" };
222 cvar_t r_shadow_bouncegrid_sortlightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_sortlightpaths", "1", "sort light paths before accumulating them into the bouncegrid texture, this reduces cpu cache misses"};
223 cvar_t r_shadow_bouncegrid_static = {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_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_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
226 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "2", "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_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_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
229 cvar_t r_shadow_bouncegrid_static_quality = { 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_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
231 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
232 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
233 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"};
234 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
235 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
236 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
237 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
238 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
239 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
240 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
241 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
242 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
243 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
244 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
245 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
246 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
247 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
248 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
249 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
250 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
251 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
252 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
253 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
254 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
255 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
257 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
259 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
260 #define ATTENTABLESIZE 256
261 // 1D gradient, 2D circle and 3D sphere attenuation textures
262 #define ATTEN1DSIZE 32
263 #define ATTEN2DSIZE 64
264 #define ATTEN3DSIZE 32
266 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
267 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
268 static float r_shadow_attentable[ATTENTABLESIZE+1];
270 rtlight_t *r_shadow_compilingrtlight;
271 static memexpandablearray_t r_shadow_worldlightsarray;
272 dlight_t *r_shadow_selectedlight;
273 dlight_t r_shadow_bufferlight;
274 vec3_t r_editlights_cursorlocation;
275 qboolean r_editlights_lockcursor;
277 extern int con_vislines;
279 void R_Shadow_UncompileWorldLights(void);
280 void R_Shadow_ClearWorldLights(void);
281 void R_Shadow_SaveWorldLights(void);
282 void R_Shadow_LoadWorldLights(void);
283 void R_Shadow_LoadLightsFile(void);
284 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
285 void R_Shadow_EditLights_Reload_f(void);
286 static void R_Shadow_MakeTextures(void);
288 #define EDLIGHTSPRSIZE 8
289 skinframe_t *r_editlights_sprcursor;
290 skinframe_t *r_editlights_sprlight;
291 skinframe_t *r_editlights_sprnoshadowlight;
292 skinframe_t *r_editlights_sprcubemaplight;
293 skinframe_t *r_editlights_sprcubemapnoshadowlight;
294 skinframe_t *r_editlights_sprselection;
296 static void R_Shadow_DrawModelShadowMaps(void);
297 static void R_Shadow_MakeShadowMap(int texturesize);
298 static void R_Shadow_MakeVSDCT(void);
299 static void R_Shadow_SetShadowMode(void)
301 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
302 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
303 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
304 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
305 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
306 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
307 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
308 r_shadow_shadowmapsampler = false;
309 r_shadow_shadowmappcf = 0;
310 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
311 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
312 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
313 if (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)
315 switch(vid.renderpath)
317 case RENDERPATH_GL32:
318 if(r_shadow_shadowmapfilterquality < 0)
320 if (!r_fb.usedepthtextures)
321 r_shadow_shadowmappcf = 1;
322 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
324 r_shadow_shadowmapsampler = true;
325 r_shadow_shadowmappcf = 1;
327 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
328 r_shadow_shadowmappcf = 1;
329 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
330 r_shadow_shadowmappcf = 1;
332 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
336 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
337 switch (r_shadow_shadowmapfilterquality)
342 r_shadow_shadowmappcf = 1;
345 r_shadow_shadowmappcf = 1;
348 r_shadow_shadowmappcf = 2;
352 if (!r_fb.usedepthtextures)
353 r_shadow_shadowmapsampler = false;
354 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
356 case RENDERPATH_GLES2:
361 if(R_CompileShader_CheckStaticParms())
365 qboolean R_Shadow_ShadowMappingEnabled(void)
367 switch (r_shadow_shadowmode)
369 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
376 static void R_Shadow_FreeShadowMaps(void)
378 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
380 R_Shadow_SetShadowMode();
382 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
386 if (r_shadow_shadowmap2ddepthtexture)
387 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
388 r_shadow_shadowmap2ddepthtexture = NULL;
390 if (r_shadow_shadowmap2ddepthbuffer)
391 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
392 r_shadow_shadowmap2ddepthbuffer = NULL;
394 if (r_shadow_shadowmapvsdcttexture)
395 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
396 r_shadow_shadowmapvsdcttexture = NULL;
399 static void r_shadow_start(void)
401 // allocate vertex processing arrays
402 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
403 r_shadow_attenuationgradienttexture = NULL;
404 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
405 r_shadow_shadowmap2ddepthtexture = NULL;
406 r_shadow_shadowmap2ddepthbuffer = NULL;
407 r_shadow_shadowmapvsdcttexture = NULL;
408 r_shadow_shadowmapmaxsize = 0;
409 r_shadow_shadowmaptexturesize = 0;
410 r_shadow_shadowmapfilterquality = -1;
411 r_shadow_shadowmapdepthbits = 0;
412 r_shadow_shadowmapvsdct = false;
413 r_shadow_shadowmapsampler = false;
414 r_shadow_shadowmappcf = 0;
417 R_Shadow_FreeShadowMaps();
419 r_shadow_texturepool = NULL;
420 r_shadow_filters_texturepool = NULL;
421 R_Shadow_MakeTextures();
422 r_shadow_scenemaxlights = 0;
423 r_shadow_scenenumlights = 0;
424 r_shadow_scenelightlist = NULL;
425 maxshadowtriangles = 0;
426 shadowelements = NULL;
427 maxshadowvertices = 0;
428 shadowvertex3f = NULL;
436 shadowmarklist = NULL;
441 shadowsideslist = NULL;
442 r_shadow_buffer_numleafpvsbytes = 0;
443 r_shadow_buffer_visitingleafpvs = NULL;
444 r_shadow_buffer_leafpvs = NULL;
445 r_shadow_buffer_leaflist = NULL;
446 r_shadow_buffer_numsurfacepvsbytes = 0;
447 r_shadow_buffer_surfacepvs = NULL;
448 r_shadow_buffer_surfacelist = NULL;
449 r_shadow_buffer_surfacesides = NULL;
450 r_shadow_buffer_numshadowtrispvsbytes = 0;
451 r_shadow_buffer_shadowtrispvs = NULL;
452 r_shadow_buffer_numlighttrispvsbytes = 0;
453 r_shadow_buffer_lighttrispvs = NULL;
455 r_shadow_usingdeferredprepass = false;
456 r_shadow_prepass_width = r_shadow_prepass_height = 0;
458 // determine renderpath specific capabilities, we don't need to figure
459 // these out per frame...
460 switch(vid.renderpath)
462 case RENDERPATH_GL32:
463 r_shadow_bouncegrid_state.allowdirectionalshading = true;
464 r_shadow_bouncegrid_state.capable = true;
466 case RENDERPATH_GLES2:
467 // for performance reasons, do not use directional shading on GLES devices
468 r_shadow_bouncegrid_state.capable = true;
473 static void R_Shadow_FreeDeferred(void);
474 static void r_shadow_shutdown(void)
477 R_Shadow_UncompileWorldLights();
479 R_Shadow_FreeShadowMaps();
481 r_shadow_usingdeferredprepass = false;
482 if (r_shadow_prepass_width)
483 R_Shadow_FreeDeferred();
484 r_shadow_prepass_width = r_shadow_prepass_height = 0;
487 r_shadow_scenemaxlights = 0;
488 r_shadow_scenenumlights = 0;
489 if (r_shadow_scenelightlist)
490 Mem_Free(r_shadow_scenelightlist);
491 r_shadow_scenelightlist = NULL;
492 r_shadow_bouncegrid_state.highpixels = NULL;
493 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
494 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
495 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
496 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
497 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
498 r_shadow_bouncegrid_state.maxsplatpaths = 0;
499 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
500 r_shadow_attenuationgradienttexture = NULL;
501 R_FreeTexturePool(&r_shadow_texturepool);
502 R_FreeTexturePool(&r_shadow_filters_texturepool);
503 maxshadowtriangles = 0;
505 Mem_Free(shadowelements);
506 shadowelements = NULL;
508 Mem_Free(shadowvertex3f);
509 shadowvertex3f = NULL;
512 Mem_Free(vertexupdate);
515 Mem_Free(vertexremap);
521 Mem_Free(shadowmark);
524 Mem_Free(shadowmarklist);
525 shadowmarklist = NULL;
530 Mem_Free(shadowsides);
533 Mem_Free(shadowsideslist);
534 shadowsideslist = NULL;
535 r_shadow_buffer_numleafpvsbytes = 0;
536 if (r_shadow_buffer_visitingleafpvs)
537 Mem_Free(r_shadow_buffer_visitingleafpvs);
538 r_shadow_buffer_visitingleafpvs = NULL;
539 if (r_shadow_buffer_leafpvs)
540 Mem_Free(r_shadow_buffer_leafpvs);
541 r_shadow_buffer_leafpvs = NULL;
542 if (r_shadow_buffer_leaflist)
543 Mem_Free(r_shadow_buffer_leaflist);
544 r_shadow_buffer_leaflist = NULL;
545 r_shadow_buffer_numsurfacepvsbytes = 0;
546 if (r_shadow_buffer_surfacepvs)
547 Mem_Free(r_shadow_buffer_surfacepvs);
548 r_shadow_buffer_surfacepvs = NULL;
549 if (r_shadow_buffer_surfacelist)
550 Mem_Free(r_shadow_buffer_surfacelist);
551 r_shadow_buffer_surfacelist = NULL;
552 if (r_shadow_buffer_surfacesides)
553 Mem_Free(r_shadow_buffer_surfacesides);
554 r_shadow_buffer_surfacesides = NULL;
555 r_shadow_buffer_numshadowtrispvsbytes = 0;
556 if (r_shadow_buffer_shadowtrispvs)
557 Mem_Free(r_shadow_buffer_shadowtrispvs);
558 r_shadow_buffer_numlighttrispvsbytes = 0;
559 if (r_shadow_buffer_lighttrispvs)
560 Mem_Free(r_shadow_buffer_lighttrispvs);
563 static void r_shadow_newmap(void)
565 r_shadow_bouncegrid_state.highpixels = NULL;
566 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
567 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
568 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
569 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
570 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
571 r_shadow_bouncegrid_state.maxsplatpaths = 0;
572 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
573 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
574 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
575 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
576 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
577 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
578 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
579 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
580 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
581 R_Shadow_EditLights_Reload_f();
584 void R_Shadow_Init(void)
586 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
587 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
588 Cvar_RegisterVariable(&r_shadow_usebihculling);
589 Cvar_RegisterVariable(&r_shadow_usenormalmap);
590 Cvar_RegisterVariable(&r_shadow_debuglight);
591 Cvar_RegisterVariable(&r_shadow_deferred);
592 Cvar_RegisterVariable(&r_shadow_gloss);
593 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
594 Cvar_RegisterVariable(&r_shadow_glossintensity);
595 Cvar_RegisterVariable(&r_shadow_glossexponent);
596 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
597 Cvar_RegisterVariable(&r_shadow_glossexact);
598 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
599 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
600 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
601 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
602 Cvar_RegisterVariable(&r_shadow_projectdistance);
603 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
604 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
605 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
606 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
607 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
608 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
609 Cvar_RegisterVariable(&r_shadow_realtime_world);
610 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
611 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
612 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
613 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
614 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
615 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
616 Cvar_RegisterVariable(&r_shadow_scissor);
617 Cvar_RegisterVariable(&r_shadow_shadowmapping);
618 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
619 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
620 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
621 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
622 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
623 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
624 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
625 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
626 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
627 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
628 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
629 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
630 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
631 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
632 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
633 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
634 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
635 Cvar_RegisterVariable(&r_shadow_culllights_trace);
636 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
637 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
638 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
639 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
640 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
641 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
642 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
643 Cvar_RegisterVariable(&r_shadow_bouncegrid);
644 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
645 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
646 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
647 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
648 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
649 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
650 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
651 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
652 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
653 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
654 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
655 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
656 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
657 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
658 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
659 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
660 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
661 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
662 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
663 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
664 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
665 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
666 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
667 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
668 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
669 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
670 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
671 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
672 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
673 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
674 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
675 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
676 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
677 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
678 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
679 Cvar_RegisterVariable(&r_coronas);
680 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
681 Cvar_RegisterVariable(&r_coronas_occlusionquery);
682 Cvar_RegisterVariable(&gl_flashblend);
683 R_Shadow_EditLights_Init();
684 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
685 r_shadow_scenemaxlights = 0;
686 r_shadow_scenenumlights = 0;
687 r_shadow_scenelightlist = NULL;
688 maxshadowtriangles = 0;
689 shadowelements = NULL;
690 maxshadowvertices = 0;
691 shadowvertex3f = NULL;
699 shadowmarklist = NULL;
704 shadowsideslist = NULL;
705 r_shadow_buffer_numleafpvsbytes = 0;
706 r_shadow_buffer_visitingleafpvs = NULL;
707 r_shadow_buffer_leafpvs = NULL;
708 r_shadow_buffer_leaflist = NULL;
709 r_shadow_buffer_numsurfacepvsbytes = 0;
710 r_shadow_buffer_surfacepvs = NULL;
711 r_shadow_buffer_surfacelist = NULL;
712 r_shadow_buffer_surfacesides = NULL;
713 r_shadow_buffer_shadowtrispvs = NULL;
714 r_shadow_buffer_lighttrispvs = NULL;
715 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
718 matrix4x4_t matrix_attenuationxyz =
721 {0.5, 0.0, 0.0, 0.5},
722 {0.0, 0.5, 0.0, 0.5},
723 {0.0, 0.0, 0.5, 0.5},
728 matrix4x4_t matrix_attenuationz =
731 {0.0, 0.0, 0.5, 0.5},
732 {0.0, 0.0, 0.0, 0.5},
733 {0.0, 0.0, 0.0, 0.5},
738 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
740 numvertices = ((numvertices + 255) & ~255) * vertscale;
741 numtriangles = ((numtriangles + 255) & ~255) * triscale;
742 // make sure shadowelements is big enough for this volume
743 if (maxshadowtriangles < numtriangles)
745 maxshadowtriangles = numtriangles;
747 Mem_Free(shadowelements);
748 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
750 // make sure shadowvertex3f is big enough for this volume
751 if (maxshadowvertices < numvertices)
753 maxshadowvertices = numvertices;
755 Mem_Free(shadowvertex3f);
756 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
760 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
762 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
763 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
764 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
765 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
766 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
768 if (r_shadow_buffer_visitingleafpvs)
769 Mem_Free(r_shadow_buffer_visitingleafpvs);
770 if (r_shadow_buffer_leafpvs)
771 Mem_Free(r_shadow_buffer_leafpvs);
772 if (r_shadow_buffer_leaflist)
773 Mem_Free(r_shadow_buffer_leaflist);
774 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
775 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
776 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
777 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
779 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
781 if (r_shadow_buffer_surfacepvs)
782 Mem_Free(r_shadow_buffer_surfacepvs);
783 if (r_shadow_buffer_surfacelist)
784 Mem_Free(r_shadow_buffer_surfacelist);
785 if (r_shadow_buffer_surfacesides)
786 Mem_Free(r_shadow_buffer_surfacesides);
787 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
788 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
789 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
790 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
792 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
794 if (r_shadow_buffer_shadowtrispvs)
795 Mem_Free(r_shadow_buffer_shadowtrispvs);
796 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
797 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
799 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
801 if (r_shadow_buffer_lighttrispvs)
802 Mem_Free(r_shadow_buffer_lighttrispvs);
803 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
804 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
808 void R_Shadow_PrepareShadowMark(int numtris)
810 // make sure shadowmark is big enough for this volume
811 if (maxshadowmark < numtris)
813 maxshadowmark = numtris;
815 Mem_Free(shadowmark);
817 Mem_Free(shadowmarklist);
818 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
819 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
823 // if shadowmarkcount wrapped we clear the array and adjust accordingly
824 if (shadowmarkcount == 0)
827 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
832 void R_Shadow_PrepareShadowSides(int numtris)
834 if (maxshadowsides < numtris)
836 maxshadowsides = numtris;
838 Mem_Free(shadowsides);
840 Mem_Free(shadowsideslist);
841 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
842 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
847 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
849 // p1, p2, p3 are in the cubemap's local coordinate system
850 // bias = border/(size - border)
853 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
854 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
855 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
856 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
858 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
859 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
860 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
861 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
863 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
864 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
865 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
867 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
868 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
869 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
870 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
872 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
873 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
874 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
875 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
877 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
878 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
879 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
881 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
882 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
883 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
884 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
886 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
887 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
888 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
889 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
891 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
892 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
893 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
898 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
900 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
901 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
904 VectorSubtract(maxs, mins, radius);
905 VectorScale(radius, 0.5f, radius);
906 VectorAdd(mins, radius, center);
907 Matrix4x4_Transform(worldtolight, center, lightcenter);
908 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
909 VectorSubtract(lightcenter, lightradius, pmin);
910 VectorAdd(lightcenter, lightradius, pmax);
912 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
913 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
914 if(ap1 > bias*an1 && ap2 > bias*an2)
916 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
917 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
918 if(an1 > bias*ap1 && an2 > bias*ap2)
920 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
921 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
923 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
924 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
925 if(ap1 > bias*an1 && ap2 > bias*an2)
927 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
928 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
929 if(an1 > bias*ap1 && an2 > bias*ap2)
931 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
932 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
934 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
935 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
936 if(ap1 > bias*an1 && ap2 > bias*an2)
938 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
939 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
940 if(an1 > bias*ap1 && an2 > bias*ap2)
942 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
943 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
948 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
950 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
952 // p is in the cubemap's local coordinate system
953 // bias = border/(size - border)
954 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
955 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
956 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
958 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
959 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
960 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
961 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
962 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
963 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
967 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
971 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
972 float scale = (size - 2*border)/size, len;
973 float bias = border / (float)(size - border), dp, dn, ap, an;
974 // check if cone enclosing side would cross frustum plane
975 scale = 2 / (scale*scale + 2);
976 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
977 for (i = 0;i < 5;i++)
979 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
981 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
982 len = scale*VectorLength2(n);
983 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
984 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
985 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
987 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
989 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
990 len = scale*VectorLength2(n);
991 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
992 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
993 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
995 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
996 // check if frustum corners/origin cross plane sides
998 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
999 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1000 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1001 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1002 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1003 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1004 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1005 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1006 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1007 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1008 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1009 for (i = 0;i < 4;i++)
1011 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1012 VectorSubtract(n, p, n);
1013 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1014 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1015 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1016 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1017 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1018 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1019 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1020 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1021 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1024 // finite version, assumes corners are a finite distance from origin dependent on far plane
1025 for (i = 0;i < 5;i++)
1027 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1028 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1029 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1030 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1031 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1032 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1033 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1034 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1035 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1036 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1039 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1042 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)
1050 int mask, surfacemask = 0;
1051 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1053 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1054 tend = firsttriangle + numtris;
1055 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1057 // surface box entirely inside light box, no box cull
1058 if (projectdirection)
1060 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1062 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1063 TriangleNormal(v[0], v[1], v[2], normal);
1064 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1066 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1067 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1068 surfacemask |= mask;
1071 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;
1072 shadowsides[numshadowsides] = mask;
1073 shadowsideslist[numshadowsides++] = t;
1080 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1082 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1083 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1085 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1086 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1087 surfacemask |= mask;
1090 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;
1091 shadowsides[numshadowsides] = mask;
1092 shadowsideslist[numshadowsides++] = t;
1100 // surface box not entirely inside light box, cull each triangle
1101 if (projectdirection)
1103 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1105 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1106 TriangleNormal(v[0], v[1], v[2], normal);
1107 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1108 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1110 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1111 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1112 surfacemask |= mask;
1115 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;
1116 shadowsides[numshadowsides] = mask;
1117 shadowsideslist[numshadowsides++] = t;
1124 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1126 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1127 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1128 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1130 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1131 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1132 surfacemask |= mask;
1135 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;
1136 shadowsides[numshadowsides] = mask;
1137 shadowsideslist[numshadowsides++] = t;
1146 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)
1148 int i, j, outtriangles = 0;
1149 int *outelement3i[6];
1150 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1152 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1153 // make sure shadowelements is big enough for this mesh
1154 if (maxshadowtriangles < outtriangles)
1155 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1157 // compute the offset and size of the separate index lists for each cubemap side
1159 for (i = 0;i < 6;i++)
1161 outelement3i[i] = shadowelements + outtriangles * 3;
1162 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1163 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1164 outtriangles += sidetotals[i];
1167 // gather up the (sparse) triangles into separate index lists for each cubemap side
1168 for (i = 0;i < numsidetris;i++)
1170 const int *element = elements + sidetris[i] * 3;
1171 for (j = 0;j < 6;j++)
1173 if (sides[i] & (1 << j))
1175 outelement3i[j][0] = element[0];
1176 outelement3i[j][1] = element[1];
1177 outelement3i[j][2] = element[2];
1178 outelement3i[j] += 3;
1183 Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1186 static void R_Shadow_MakeTextures_MakeCorona(void)
1190 unsigned char pixels[32][32][4];
1191 for (y = 0;y < 32;y++)
1193 dy = (y - 15.5f) * (1.0f / 16.0f);
1194 for (x = 0;x < 32;x++)
1196 dx = (x - 15.5f) * (1.0f / 16.0f);
1197 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1198 a = bound(0, a, 255);
1199 pixels[y][x][0] = a;
1200 pixels[y][x][1] = a;
1201 pixels[y][x][2] = a;
1202 pixels[y][x][3] = 255;
1205 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1208 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1210 float dist = sqrt(x*x+y*y+z*z);
1211 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1212 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1213 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1216 static void R_Shadow_MakeTextures(void)
1219 float intensity, dist;
1221 R_Shadow_FreeShadowMaps();
1222 R_FreeTexturePool(&r_shadow_texturepool);
1223 r_shadow_texturepool = R_AllocTexturePool();
1224 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1225 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1226 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1227 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1228 for (x = 0;x <= ATTENTABLESIZE;x++)
1230 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1231 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1232 r_shadow_attentable[x] = bound(0, intensity, 1);
1234 // 1D gradient texture
1235 for (x = 0;x < ATTEN1DSIZE;x++)
1236 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1237 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1240 R_Shadow_MakeTextures_MakeCorona();
1242 // Editor light sprites
1243 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1260 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1261 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1278 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1279 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1296 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1297 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1314 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1315 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1332 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1333 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1350 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1353 void R_Shadow_RenderMode_Begin(void)
1360 if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1361 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1362 R_Shadow_MakeTextures();
1365 R_Mesh_ResetTextureState();
1366 GL_BlendFunc(GL_ONE, GL_ZERO);
1367 GL_DepthRange(0, 1);
1368 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1370 GL_DepthMask(false);
1371 GL_Color(0, 0, 0, 1);
1372 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1374 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1375 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1379 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1380 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1381 r_shadow_drawbuffer = drawbuffer;
1382 r_shadow_readbuffer = readbuffer;
1384 r_shadow_cullface_front = r_refdef.view.cullface_front;
1385 r_shadow_cullface_back = r_refdef.view.cullface_back;
1388 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1390 rsurface.rtlight = rtlight;
1393 void R_Shadow_RenderMode_Reset(void)
1395 R_Mesh_ResetTextureState();
1396 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1397 R_SetViewport(&r_refdef.view.viewport);
1398 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1399 GL_DepthRange(0, 1);
1401 GL_DepthMask(false);
1402 GL_DepthFunc(GL_LEQUAL);
1403 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1404 r_refdef.view.cullface_front = r_shadow_cullface_front;
1405 r_refdef.view.cullface_back = r_shadow_cullface_back;
1406 GL_CullFace(r_refdef.view.cullface_back);
1407 GL_Color(1, 1, 1, 1);
1408 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1409 GL_BlendFunc(GL_ONE, GL_ZERO);
1410 R_SetupShader_Generic_NoTexture(false, false);
1411 r_shadow_usingshadowmap2d = false;
1414 void R_Shadow_ClearStencil(void)
1416 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1417 r_refdef.stats[r_stat_lights_clears]++;
1420 static void R_Shadow_MakeVSDCT(void)
1422 // maps to a 2x3 texture rectangle with normalized coordinates
1427 // stores abs(dir.xy), offset.xy/2.5
1428 unsigned char data[4*6] =
1430 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1431 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1432 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1433 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1434 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1435 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1437 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1440 static void R_Shadow_MakeShadowMap(int texturesize)
1442 switch (r_shadow_shadowmode)
1444 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1445 if (r_shadow_shadowmap2ddepthtexture) return;
1446 if (r_fb.usedepthtextures)
1448 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);
1449 r_shadow_shadowmap2ddepthbuffer = NULL;
1450 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1454 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1455 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1456 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1464 void R_Shadow_ClearShadowMapTexture(void)
1466 r_viewport_t viewport;
1467 float clearcolor[4];
1469 // if they don't exist, create our textures now
1470 if (!r_shadow_shadowmap2ddepthtexture)
1471 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1472 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1473 R_Shadow_MakeVSDCT();
1475 // we're setting up to render shadowmaps, so change rendermode
1476 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1478 R_Mesh_ResetTextureState();
1479 R_Shadow_RenderMode_Reset();
1480 if (r_shadow_shadowmap2ddepthbuffer)
1481 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1483 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1484 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1485 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1489 // we have to set a viewport to clear anything in some renderpaths (D3D)
1490 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1491 R_SetViewport(&viewport);
1492 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1493 if (r_shadow_shadowmap2ddepthbuffer)
1494 GL_ColorMask(1, 1, 1, 1);
1496 GL_ColorMask(0, 0, 0, 0);
1497 switch (vid.renderpath)
1499 case RENDERPATH_GL32:
1500 case RENDERPATH_GLES2:
1501 GL_CullFace(r_refdef.view.cullface_back);
1504 Vector4Set(clearcolor, 1, 1, 1, 1);
1505 if (r_shadow_shadowmap2ddepthbuffer)
1506 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1508 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1511 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1513 int size = rsurface.rtlight->shadowmapatlassidesize;
1514 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1515 float farclip = 1.0f;
1516 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1517 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1518 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1519 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1520 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1521 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1522 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1523 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1524 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1525 if (r_shadow_shadowmap2ddepthbuffer)
1527 // completely different meaning than in depthtexture approach
1528 r_shadow_lightshadowmap_parameters[1] = 0;
1529 r_shadow_lightshadowmap_parameters[3] = -bias;
1533 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1535 float nearclip, farclip, bias;
1536 r_viewport_t viewport;
1538 float clearcolor[4];
1540 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1542 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1544 R_Mesh_ResetTextureState();
1545 R_Shadow_RenderMode_Reset();
1546 if (r_shadow_shadowmap2ddepthbuffer)
1547 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1549 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1550 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1551 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1556 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1558 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1560 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1561 R_SetViewport(&viewport);
1562 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1563 flipped = (side & 1) ^ (side >> 2);
1564 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1565 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1567 Vector4Set(clearcolor, 1,1,1,1);
1568 if (r_shadow_shadowmap2ddepthbuffer)
1569 GL_ColorMask(1,1,1,1);
1571 GL_ColorMask(0,0,0,0);
1572 switch(vid.renderpath)
1574 case RENDERPATH_GL32:
1575 case RENDERPATH_GLES2:
1576 GL_CullFace(r_refdef.view.cullface_back);
1580 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1581 r_shadow_shadowmapside = side;
1584 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1586 R_Mesh_ResetTextureState();
1589 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1590 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1591 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1592 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1595 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1596 R_Shadow_RenderMode_Reset();
1597 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1599 GL_DepthFunc(GL_EQUAL);
1600 // do global setup needed for the chosen lighting mode
1601 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1602 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1603 r_shadow_usingshadowmap2d = shadowmapping;
1604 r_shadow_rendermode = r_shadow_lightingrendermode;
1607 static const unsigned short bboxelements[36] =
1617 static const float bboxpoints[8][3] =
1629 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1632 float vertex3f[8*3];
1633 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1634 // do global setup needed for the chosen lighting mode
1635 R_Shadow_RenderMode_Reset();
1636 r_shadow_rendermode = r_shadow_lightingrendermode;
1637 R_EntityMatrix(&identitymatrix);
1638 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1639 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1640 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1642 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1644 r_shadow_usingshadowmap2d = shadowmapping;
1646 // render the lighting
1647 R_SetupShader_DeferredLight(rsurface.rtlight);
1648 for (i = 0;i < 8;i++)
1649 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1650 GL_ColorMask(1,1,1,1);
1651 GL_DepthMask(false);
1652 GL_DepthRange(0, 1);
1653 GL_PolygonOffset(0, 0);
1655 GL_DepthFunc(GL_GREATER);
1656 GL_CullFace(r_refdef.view.cullface_back);
1657 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1658 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1661 #define MAXBOUNCEGRIDSPLATSIZE 7
1662 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
1664 // these are temporary data per-frame, sorted and performed in a more
1665 // cache-friendly order than the original photons
1666 typedef struct r_shadow_bouncegrid_splatpath_s
1672 vec_t splatintensity;
1673 vec_t splatsize_current;
1674 vec_t splatsize_perstep;
1675 int remainingsplats;
1677 r_shadow_bouncegrid_splatpath_t;
1679 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
1689 r_shadow_bouncegrid_splatpath_t *path;
1691 // cull paths that fail R_CullBox in dynamic mode
1692 if (!r_shadow_bouncegrid_state.settings.staticmode
1693 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
1695 vec3_t cullmins, cullmaxs;
1696 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
1697 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
1698 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
1699 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
1700 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
1701 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
1702 if (R_CullBox(cullmins, cullmaxs))
1706 // if the light path is going upward, reverse it - we always draw down.
1707 if (originalend[2] < originalstart[2])
1709 VectorCopy(originalend, start);
1710 VectorCopy(originalstart, end);
1714 VectorCopy(originalstart, start);
1715 VectorCopy(originalend, end);
1718 // transform to texture pixels
1719 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1720 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1721 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1722 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1723 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1724 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1726 // check if we need to grow the splatpaths array
1727 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
1729 // double the limit, this will persist from frame to frame so we don't
1730 // make the same mistake each time
1731 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
1732 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
1733 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
1734 r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)Mem_Realloc(r_main_mempool, r_shadow_bouncegrid_state.splatpaths, sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
1737 // divide a series of splats along the length using the maximum axis
1738 VectorSubtract(end, start, diff);
1739 // pick the best axis to trace along
1741 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
1743 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
1745 len = fabs(diff[bestaxis]);
1747 numsplats = (int)(floor(len + 0.5f));
1749 numsplats = bound(0, numsplats, 1024);
1751 VectorSubtract(originalstart, originalend, originaldir);
1752 VectorNormalize(originaldir);
1754 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
1755 VectorCopy(start, path->point);
1756 VectorScale(diff, ilen, path->step);
1757 VectorCopy(color, path->splatcolor);
1758 VectorCopy(originaldir, path->splatdir);
1759 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
1760 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
1761 path->splatintensity = VectorLength(color);
1762 path->remainingsplats = numsplats;
1765 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1767 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1774 // see if there are really any lights to render...
1775 if (enable && r_shadow_bouncegrid_static.integer)
1778 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1779 for (lightindex = 0;lightindex < range;lightindex++)
1781 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1782 if (!light || !(light->flags & flag))
1784 rtlight = &light->rtlight;
1785 // when static, we skip styled lights because they tend to change...
1786 if (rtlight->style > 0)
1788 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1789 if (!VectorLength2(lightcolor))
1799 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1801 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1802 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1803 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1804 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1806 // prevent any garbage in alignment padded areas as we'll be using memcmp
1807 memset(settings, 0, sizeof(*settings));
1809 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1810 settings->staticmode = s;
1811 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1812 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1813 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
1814 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
1815 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
1816 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1817 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1818 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1819 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1820 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1821 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1822 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1823 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
1824 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1825 settings->energyperphoton = spacing * spacing / quality;
1826 settings->spacing[0] = spacing;
1827 settings->spacing[1] = spacing;
1828 settings->spacing[2] = spacing;
1829 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1830 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1831 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1832 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1833 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1835 // bound the values for sanity
1836 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1837 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1838 settings->maxbounce = bound(0, settings->maxbounce, 16);
1839 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1840 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1841 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1844 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1855 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1857 // get the spacing values
1858 spacing[0] = settings->spacing[0];
1859 spacing[1] = settings->spacing[1];
1860 spacing[2] = settings->spacing[2];
1861 ispacing[0] = 1.0f / spacing[0];
1862 ispacing[1] = 1.0f / spacing[1];
1863 ispacing[2] = 1.0f / spacing[2];
1865 // calculate texture size enclosing entire world bounds at the spacing
1866 if (r_refdef.scene.worldmodel)
1870 qboolean bounds_set = false;
1874 // calculate bounds enclosing world lights as they should be noticably tighter
1875 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1876 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1877 for (lightindex = 0;lightindex < range;lightindex++)
1879 const vec_t *rtlmins, *rtlmaxs;
1881 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1885 rtlight = &light->rtlight;
1886 rtlmins = rtlight->cullmins;
1887 rtlmaxs = rtlight->cullmaxs;
1891 VectorCopy(rtlmins, mins);
1892 VectorCopy(rtlmaxs, maxs);
1897 mins[0] = min(mins[0], rtlmins[0]);
1898 mins[1] = min(mins[1], rtlmins[1]);
1899 mins[2] = min(mins[2], rtlmins[2]);
1900 maxs[0] = max(maxs[0], rtlmaxs[0]);
1901 maxs[1] = max(maxs[1], rtlmaxs[1]);
1902 maxs[2] = max(maxs[2], rtlmaxs[2]);
1906 // limit to no larger than the world bounds
1907 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1908 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1909 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1910 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1911 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1912 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1914 VectorMA(mins, -2.0f, spacing, mins);
1915 VectorMA(maxs, 2.0f, spacing, maxs);
1919 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1920 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1922 VectorSubtract(maxs, mins, size);
1923 // now we can calculate the resolution we want
1924 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1925 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1926 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1927 // figure out the exact texture size (honoring power of 2 if required)
1928 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1929 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1930 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1931 size[0] = spacing[0] * resolution[0];
1932 size[1] = spacing[1] * resolution[1];
1933 size[2] = spacing[2] * resolution[2];
1935 // if dynamic we may or may not want to use the world bounds
1936 // if the dynamic size is smaller than the world bounds, use it instead
1937 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]))
1939 // we know the resolution we want
1940 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1941 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1942 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1943 // now we can calculate the texture size
1944 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1945 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1946 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1947 size[0] = spacing[0] * resolution[0];
1948 size[1] = spacing[1] * resolution[1];
1949 size[2] = spacing[2] * resolution[2];
1950 // center the rendering on the view
1951 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1952 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1953 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1956 // recalculate the maxs in case the resolution was not satisfactory
1957 VectorAdd(mins, size, maxs);
1959 // check if this changed the texture size
1960 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);
1961 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1962 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1963 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1964 VectorCopy(size, r_shadow_bouncegrid_state.size);
1965 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1966 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1967 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1969 // reallocate pixels for this update if needed...
1970 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1971 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1972 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1973 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1974 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1976 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
1977 r_shadow_bouncegrid_state.highpixels = NULL;
1978 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
1979 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
1980 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
1981 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
1982 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
1983 r_shadow_bouncegrid_state.maxsplatpaths = 0;
1984 r_shadow_bouncegrid_state.numpixels = numpixels;
1987 // update the bouncegrid matrix to put it in the world properly
1988 memset(m, 0, sizeof(m));
1989 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1990 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1991 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1992 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1993 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1994 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1996 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1999 // enumerate world rtlights and sum the overall amount of light in the world,
2000 // from that we can calculate a scaling factor to fairly distribute photons
2001 // to all the lights
2003 // this modifies rtlight->photoncolor and rtlight->photons
2004 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2006 float normalphotonscaling;
2007 float photonscaling;
2008 float photonintensity;
2009 float photoncount = 0.0f;
2010 float lightintensity;
2016 unsigned int lightindex;
2019 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2020 for (lightindex = 0;lightindex < range2;lightindex++)
2022 if (lightindex < range)
2024 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2027 rtlight = &light->rtlight;
2028 VectorClear(rtlight->bouncegrid_photoncolor);
2029 rtlight->bouncegrid_photons = 0;
2030 rtlight->bouncegrid_hits = 0;
2031 rtlight->bouncegrid_traces = 0;
2032 rtlight->bouncegrid_effectiveradius = 0;
2033 if (!(light->flags & flag))
2035 if (settings->staticmode)
2037 // when static, we skip styled lights because they tend to change...
2038 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2041 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2046 rtlight = r_refdef.scene.lights[lightindex - range];
2047 VectorClear(rtlight->bouncegrid_photoncolor);
2048 rtlight->bouncegrid_photons = 0;
2049 rtlight->bouncegrid_hits = 0;
2050 rtlight->bouncegrid_traces = 0;
2051 rtlight->bouncegrid_effectiveradius = 0;
2053 // draw only visible lights (major speedup)
2054 radius = rtlight->radius * settings->lightradiusscale;
2055 cullmins[0] = rtlight->shadoworigin[0] - radius;
2056 cullmins[1] = rtlight->shadoworigin[1] - radius;
2057 cullmins[2] = rtlight->shadoworigin[2] - radius;
2058 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2059 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2060 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2061 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2062 if (!settings->staticmode)
2064 // skip if the expanded light box does not touch any visible leafs
2065 if (r_refdef.scene.worldmodel
2066 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2067 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2069 // skip if the expanded light box is not visible to traceline
2070 // note that PrepareLight already did this check but for a smaller box, so we
2071 // end up casting more traces per frame per light when using bouncegrid, which
2072 // is probably fine (and they use the same timer)
2073 if (r_shadow_culllights_trace.integer)
2075 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))
2076 rtlight->trace_timer = realtime;
2077 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2080 // skip if expanded light box is offscreen
2081 if (R_CullBox(cullmins, cullmaxs))
2083 // skip if overall light intensity is zero
2084 if (w * VectorLength2(rtlight->color) == 0.0f)
2087 // a light that does not emit any light before style is applied, can be
2088 // skipped entirely (it may just be a corona)
2089 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2091 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2092 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2093 // skip lights that will emit no photons
2094 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2096 // shoot particles from this light
2097 // use a calculation for the number of particles that will not
2098 // vary with lightstyle, otherwise we get randomized particle
2099 // distribution, the seeded random is only consistent for a
2100 // consistent number of particles on this light...
2101 s = rtlight->radius;
2102 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2103 if (lightindex >= range)
2104 lightintensity *= settings->dlightparticlemultiplier;
2105 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2106 photoncount += rtlight->bouncegrid_photons;
2107 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2108 // if the lightstyle happens to be off right now, we can skip actually
2109 // firing the photons, but we did have to count them in the total.
2110 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2111 // rtlight->bouncegrid_photons = 0;
2113 // the user provided an energyperphoton value which we try to use
2114 // if that results in too many photons to shoot this frame, then we cap it
2115 // which causes photons to appear/disappear from frame to frame, so we don't
2116 // like doing that in the typical case
2117 photonscaling = 1.0f;
2118 photonintensity = 1.0f;
2119 if (photoncount > settings->maxphotons)
2121 photonscaling = settings->maxphotons / photoncount;
2122 photonintensity = 1.0f / photonscaling;
2125 // modify the lights to reflect our computed scaling
2126 for (lightindex = 0; lightindex < range2; lightindex++)
2128 if (lightindex < range)
2130 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2133 rtlight = &light->rtlight;
2136 rtlight = r_refdef.scene.lights[lightindex - range];
2137 rtlight->bouncegrid_photons *= photonscaling;
2138 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2142 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2144 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2145 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2146 // we only really care about sorting by Z
2147 if (a->point[2] < b->point[2])
2149 if (a->point[2] > b->point[2])
2154 static void R_Shadow_BounceGrid_ClearPixels(void)
2156 // clear the highpixels array we'll be accumulating into
2157 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2158 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2159 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2160 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2161 r_shadow_bouncegrid_state.highpixels_index = 0;
2162 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2163 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2166 static void R_Shadow_BounceGrid_PerformSplats(void)
2168 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2169 r_shadow_bouncegrid_splatpath_t *splatpath;
2170 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2171 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2176 vec_t lightpathsize_current;
2177 vec_t lightpathsize_perstep;
2178 float splatcolor[32];
2180 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2181 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2185 // hush warnings about uninitialized data - pixelbands doesn't change but...
2186 memset(splatcolor, 0, sizeof(splatcolor));
2188 // we use this a lot, so get a local copy
2189 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2191 // sort the splats before we execute them, to reduce cache misses
2192 if (r_shadow_bouncegrid_sortlightpaths.integer)
2193 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2195 splatpath = splatpaths;
2196 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2198 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2199 // accumulate average shotcolor
2200 VectorCopy(splatpath->splatdir, dir);
2201 splatcolor[ 0] = splatpath->splatcolor[0];
2202 splatcolor[ 1] = splatpath->splatcolor[1];
2203 splatcolor[ 2] = splatpath->splatcolor[2];
2204 splatcolor[ 3] = 0.0f;
2207 // store bentnormal in case the shader has a use for it,
2208 // bentnormal is an intensity-weighted average of the directions,
2209 // and will be normalized on conversion to texture pixels.
2210 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2211 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2212 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2213 splatcolor[ 7] = splatpath->splatintensity;
2214 // for each color component (R, G, B) calculate the amount that a
2215 // direction contributes
2216 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2217 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2218 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2219 splatcolor[11] = 0.0f;
2220 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2221 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2222 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2223 splatcolor[15] = 0.0f;
2224 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2225 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2226 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2227 splatcolor[19] = 0.0f;
2228 // and do the same for negative directions
2229 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2230 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2231 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2232 splatcolor[23] = 0.0f;
2233 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2234 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2235 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2236 splatcolor[27] = 0.0f;
2237 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2238 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2239 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2240 splatcolor[31] = 0.0f;
2242 // calculate the number of steps we need to traverse this distance
2243 VectorCopy(splatpath->point, steppos);
2244 VectorCopy(splatpath->step, stepdelta);
2245 numsteps = splatpath->remainingsplats;
2246 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
2247 lightpathsize_perstep = splatpath->splatsize_perstep;
2248 for (step = 0;step < numsteps;step++)
2250 // the middle row/column/layer of each splat are full intensity
2253 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
2254 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
2255 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
2256 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
2257 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
2258 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
2259 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
2260 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
2261 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
2263 // it is within bounds... do the real work now
2264 int xi, yi, zi, band, row;
2268 float colorscale = 1.0f / lightpathsize_current;
2269 r_refdef.stats[r_stat_bouncegrid_splats]++;
2270 // accumulate light onto the pixels
2271 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
2273 pixelpos[2] = zi + 0.5f;
2274 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
2276 pixelpos[1] = yi + 0.5f;
2277 row = (zi*resolution[1] + yi)*resolution[0];
2278 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
2280 pixelpos[0] = xi + 0.5f;
2281 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
2282 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
2288 p = highpixels + 4 * (row + xi);
2289 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
2291 // add to the pixel color
2292 p[0] += splatcolor[band * 4 + 0] * w;
2293 p[1] += splatcolor[band * 4 + 1] * w;
2294 p[2] += splatcolor[band * 4 + 2] * w;
2295 p[3] += splatcolor[band * 4 + 3] * w;
2302 VectorAdd(steppos, stepdelta, steppos);
2303 lightpathsize_current += lightpathsize_perstep;
2308 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2310 const float *inpixel;
2312 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2315 unsigned int x, y, z;
2316 unsigned int resolution[3];
2317 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2318 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2320 for (z = 1;z < resolution[2]-1;z++)
2322 for (y = 1;y < resolution[1]-1;y++)
2325 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2326 inpixel = inpixels + 4*index;
2327 outpixel = outpixels + 4*index;
2328 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2330 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2331 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2332 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2333 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2340 static void R_Shadow_BounceGrid_BlurPixels(void)
2343 unsigned int resolution[3];
2345 if (!r_shadow_bouncegrid_state.settings.blur)
2348 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2350 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2351 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2352 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2353 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2356 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2358 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2360 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2362 // toggle the state, highpixels now points to pixels[3] result
2363 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2364 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2367 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2369 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2370 unsigned char *pixelsbgra8 = NULL;
2371 unsigned char *pixelbgra8;
2372 unsigned short *pixelsrgba16f = NULL;
2373 unsigned short *pixelrgba16f;
2374 float *pixelsrgba32f = NULL;
2375 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2378 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2379 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2380 unsigned int pixelband;
2381 unsigned int x, y, z;
2382 unsigned int index, bandindex;
2383 unsigned int resolution[3];
2385 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2387 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2389 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2390 r_shadow_bouncegrid_state.texture = NULL;
2393 // if bentnormals exist, we need to normalize and bias them for the shader
2397 for (z = 0;z < resolution[2]-1;z++)
2399 for (y = 0;y < resolution[1]-1;y++)
2402 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2403 highpixel = highpixels + 4*index;
2404 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2406 // only convert pixels that were hit by photons
2407 if (highpixel[3] != 0.0f)
2408 VectorNormalize(highpixel);
2409 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2410 highpixel[pixelsperband * 4 + 3] = 1.0f;
2416 // start by clearing the pixels array - we won't be writing to all of it
2418 // then process only the pixels that have at least some color, skipping
2419 // the higher bands for speed on pixels that are black
2420 switch (floatcolors)
2423 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2424 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2425 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2426 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2429 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2431 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2433 for (z = 1;z < resolution[2]-1;z++)
2435 for (y = 1;y < resolution[1]-1;y++)
2439 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2440 highpixel = highpixels + 4*index;
2441 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2443 // only convert pixels that were hit by photons
2444 if (VectorLength2(highpixel))
2446 // normalize the bentnormal now
2449 VectorNormalize(highpixel + pixelsperband * 4);
2450 highpixel[pixelsperband * 4 + 3] = 1.0f;
2452 // process all of the pixelbands for this pixel
2453 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2455 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2456 bandpixel = highpixels + 4*bandindex;
2457 c[0] = (int)(bandpixel[0]*256.0f);
2458 c[1] = (int)(bandpixel[1]*256.0f);
2459 c[2] = (int)(bandpixel[2]*256.0f);
2460 c[3] = (int)(bandpixel[3]*256.0f);
2461 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2462 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2463 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2464 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2471 if (!r_shadow_bouncegrid_state.createtexture)
2472 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2474 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);
2477 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2478 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2479 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2480 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2481 for (z = 1;z < resolution[2]-1;z++)
2483 for (y = 1;y < resolution[1]-1;y++)
2487 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2488 highpixel = highpixels + 4*index;
2489 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2491 // only convert pixels that were hit by photons
2492 if (VectorLength2(highpixel))
2494 // process all of the pixelbands for this pixel
2495 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2497 // time to have fun with IEEE 754 bit hacking...
2500 unsigned int raw[4];
2502 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2503 bandpixel = highpixels + 4*bandindex;
2504 VectorCopy4(bandpixel, u.f);
2505 VectorCopy4(u.raw, c);
2506 // this math supports negative numbers, snaps denormals to zero
2507 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2508 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2509 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2510 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2511 // this math does not support negative
2512 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2513 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2514 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2515 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2522 if (!r_shadow_bouncegrid_state.createtexture)
2523 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2525 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);
2528 // our native format happens to match, so this is easy.
2529 pixelsrgba32f = highpixels;
2531 if (!r_shadow_bouncegrid_state.createtexture)
2532 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2534 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);
2538 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2541 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2543 vec3_t bouncerandom[10];
2546 int hitsupercontentsmask;
2547 int skipsupercontentsmask;
2548 int skipmaterialflagsmask;
2552 float bounceminimumintensity2;
2554 //trace_t cliptrace2;
2555 //trace_t cliptrace3;
2556 unsigned int lightindex;
2558 randomseed_t randomseed;
2560 vec3_t baseshotcolor;
2566 vec_t distancetraveled;
2570 // compute a seed for the unstable random modes
2571 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2572 seed = realtime * 1000.0;
2574 r_shadow_bouncegrid_state.numsplatpaths = 0;
2576 // figure out what we want to interact with
2577 if (settings.hitmodels)
2578 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2580 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2581 skipsupercontentsmask = 0;
2582 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
2583 maxbounce = settings.maxbounce;
2585 for (lightindex = 0;lightindex < range2;lightindex++)
2587 if (lightindex < range)
2589 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2592 rtlight = &light->rtlight;
2595 rtlight = r_refdef.scene.lights[lightindex - range];
2596 // note that this code used to keep track of residual photons and
2597 // distribute them evenly to achieve exactly a desired photon count,
2598 // but that caused unwanted flickering in dynamic mode
2599 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2600 // skip if we won't be shooting any photons
2601 if (!shootparticles)
2603 radius = rtlight->radius * settings.lightradiusscale;
2604 //s = settings.particleintensity / shootparticles;
2605 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2606 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2607 if (VectorLength2(baseshotcolor) <= 0.0f)
2609 r_refdef.stats[r_stat_bouncegrid_lights]++;
2610 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2611 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2612 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
2614 // for seeded random we start the RNG with the position of the light
2615 if (settings.rng_seed >= 0)
2623 u.f[0] = rtlight->shadoworigin[0];
2624 u.f[1] = rtlight->shadoworigin[1];
2625 u.f[2] = rtlight->shadoworigin[2];
2627 switch (settings.rng_type)
2631 // we have to shift the seed provided by the user because the result must be odd
2632 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
2635 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
2640 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2642 VectorCopy(baseshotcolor, shotcolor);
2643 VectorCopy(rtlight->shadoworigin, clipstart);
2644 switch (settings.rng_type)
2648 VectorLehmerRandom(&randomseed, clipend);
2649 if (settings.bounceanglediffuse)
2651 // we want random to be stable, so we still have to do all the random we would have done
2652 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2653 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
2657 VectorCheeseRandom(seed, clipend);
2658 if (settings.bounceanglediffuse)
2660 // we want random to be stable, so we still have to do all the random we would have done
2661 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2662 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
2667 // we want a uniform distribution spherically, not merely within the sphere
2668 if (settings.normalizevectors)
2669 VectorNormalize(clipend);
2671 VectorMA(clipstart, radius, clipend, clipend);
2672 distancetraveled = 0.0f;
2673 for (bouncecount = 0;;bouncecount++)
2675 r_refdef.stats[r_stat_bouncegrid_traces]++;
2676 rtlight->bouncegrid_traces++;
2677 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2678 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2679 if (settings.staticmode || settings.rng_seed < 0)
2681 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2682 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2683 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value, true, false, NULL, true, true);
2687 // dynamic mode fires many rays and most will match the cache from the previous frame
2688 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
2690 if (bouncecount > 0 || settings.includedirectlighting)
2693 VectorCopy(cliptrace.endpos, hitpos);
2694 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
2696 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
2697 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
2698 if (rtlight->bouncegrid_effectiveradius < s)
2699 rtlight->bouncegrid_effectiveradius = s;
2700 if (cliptrace.fraction >= 1.0f)
2702 r_refdef.stats[r_stat_bouncegrid_hits]++;
2703 rtlight->bouncegrid_hits++;
2704 if (bouncecount >= maxbounce)
2706 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2707 // also clamp the resulting color to never add energy, even if the user requests extreme values
2708 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2709 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2711 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2712 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2713 surfcolor[0] = min(surfcolor[0], 1.0f);
2714 surfcolor[1] = min(surfcolor[1], 1.0f);
2715 surfcolor[2] = min(surfcolor[2], 1.0f);
2716 VectorMultiply(shotcolor, surfcolor, shotcolor);
2717 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
2719 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2720 if (settings.bounceanglediffuse)
2722 // random direction, primarily along plane normal
2723 s = VectorDistance(cliptrace.endpos, clipend);
2724 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
2725 VectorNormalize(clipend);
2726 VectorScale(clipend, s, clipend);
2730 // reflect the remaining portion of the line across plane normal
2731 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2732 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2734 // calculate the new line start and end
2735 VectorCopy(cliptrace.endpos, clipstart);
2736 VectorAdd(clipstart, clipend, clipend);
2742 void R_Shadow_UpdateBounceGridTexture(void)
2744 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2745 r_shadow_bouncegrid_settings_t settings;
2746 qboolean enable = false;
2747 qboolean settingschanged;
2748 unsigned int range; // number of world lights
2749 unsigned int range1; // number of dynamic lights (or zero if disabled)
2750 unsigned int range2; // range+range1
2752 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2754 R_Shadow_BounceGrid_GenerateSettings(&settings);
2756 // changing intensity does not require an update
2757 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2759 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2761 // when settings change, we free everything as it is just simpler that way.
2762 if (settingschanged || !enable)
2764 // not enabled, make sure we free anything we don't need anymore.
2765 if (r_shadow_bouncegrid_state.texture)
2767 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2768 r_shadow_bouncegrid_state.texture = NULL;
2770 r_shadow_bouncegrid_state.highpixels = NULL;
2771 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2772 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2773 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2774 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2775 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2776 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2777 r_shadow_bouncegrid_state.numpixels = 0;
2778 r_shadow_bouncegrid_state.directional = false;
2784 // if all the settings seem identical to the previous update, return
2785 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2788 // store the new settings
2789 r_shadow_bouncegrid_state.settings = settings;
2791 R_Shadow_BounceGrid_UpdateSpacing();
2793 // get the range of light numbers we'll be looping over:
2794 // range = static lights
2795 // range1 = dynamic lights (optional)
2796 // range2 = range + range1
2797 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2798 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2799 range2 = range + range1;
2801 // calculate weighting factors for distributing photons among the lights
2802 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
2804 // trace the photons from lights and accumulate illumination
2805 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
2807 // clear the texture
2808 R_Shadow_BounceGrid_ClearPixels();
2810 // accumulate the light splatting into texture
2811 R_Shadow_BounceGrid_PerformSplats();
2813 // apply a mild blur filter to the texture
2814 R_Shadow_BounceGrid_BlurPixels();
2816 // convert the pixels to lower precision and upload the texture
2817 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2819 // after we compute the static lighting we don't need to keep the highpixels array around
2820 if (settings.staticmode)
2822 r_shadow_bouncegrid_state.highpixels = NULL;
2823 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2824 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2825 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2826 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2827 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2828 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2832 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2834 R_Shadow_RenderMode_Reset();
2835 GL_BlendFunc(GL_ONE, GL_ONE);
2836 GL_DepthRange(0, 1);
2837 GL_DepthTest(r_showlighting.integer < 2);
2838 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2840 GL_DepthFunc(GL_EQUAL);
2841 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2844 void R_Shadow_RenderMode_End(void)
2846 R_Shadow_RenderMode_Reset();
2847 R_Shadow_RenderMode_ActiveLight(NULL);
2849 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2850 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2853 int bboxedges[12][2] =
2872 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2874 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2876 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2877 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2878 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2879 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2882 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2883 return true; // invisible
2884 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2885 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2886 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2887 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2888 r_refdef.stats[r_stat_lights_scissored]++;
2892 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2894 // used to display how many times a surface is lit for level design purposes
2895 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2896 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2900 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])
2902 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2903 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2907 extern cvar_t gl_lightmaps;
2908 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2911 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2912 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2913 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2914 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2915 if (!r_shadow_usenormalmap.integer)
2917 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2918 VectorClear(diffusecolor);
2919 VectorClear(specularcolor);
2921 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2922 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2923 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2924 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2926 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2929 VectorNegate(ambientcolor, ambientcolor);
2930 VectorNegate(diffusecolor, diffusecolor);
2931 VectorNegate(specularcolor, specularcolor);
2932 GL_BlendEquationSubtract(true);
2934 RSurf_SetupDepthAndCulling();
2935 switch (r_shadow_rendermode)
2937 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2938 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2939 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2941 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2942 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2945 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2949 GL_BlendEquationSubtract(false);
2952 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)
2954 matrix4x4_t tempmatrix = *matrix;
2955 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2957 // if this light has been compiled before, free the associated data
2958 R_RTLight_Uncompile(rtlight);
2960 // clear it completely to avoid any lingering data
2961 memset(rtlight, 0, sizeof(*rtlight));
2963 // copy the properties
2964 rtlight->matrix_lighttoworld = tempmatrix;
2965 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2966 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2967 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2968 VectorCopy(color, rtlight->color);
2969 rtlight->cubemapname[0] = 0;
2970 if (cubemapname && cubemapname[0])
2971 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2972 rtlight->shadow = shadow;
2973 rtlight->corona = corona;
2974 rtlight->style = style;
2975 rtlight->isstatic = isstatic;
2976 rtlight->coronasizescale = coronasizescale;
2977 rtlight->ambientscale = ambientscale;
2978 rtlight->diffusescale = diffusescale;
2979 rtlight->specularscale = specularscale;
2980 rtlight->flags = flags;
2982 // compute derived data
2983 //rtlight->cullradius = rtlight->radius;
2984 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2985 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2986 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2987 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2988 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2989 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2990 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2993 // compiles rtlight geometry
2994 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2995 void R_RTLight_Compile(rtlight_t *rtlight)
2998 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2999 int lighttris, shadowtris;
3000 entity_render_t *ent = r_refdef.scene.worldentity;
3001 dp_model_t *model = r_refdef.scene.worldmodel;
3002 unsigned char *data;
3004 // compile the light
3005 rtlight->compiled = true;
3006 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3007 rtlight->static_numleafs = 0;
3008 rtlight->static_numleafpvsbytes = 0;
3009 rtlight->static_leaflist = NULL;
3010 rtlight->static_leafpvs = NULL;
3011 rtlight->static_numsurfaces = 0;
3012 rtlight->static_surfacelist = NULL;
3013 rtlight->static_shadowmap_receivers = 0x3F;
3014 rtlight->static_shadowmap_casters = 0x3F;
3015 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3016 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3017 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3018 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3019 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3020 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3022 if (model && model->GetLightInfo)
3024 // this variable must be set for the CompileShadowMap code
3025 r_shadow_compilingrtlight = rtlight;
3026 R_FrameData_SetMark();
3027 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);
3028 R_FrameData_ReturnToMark();
3029 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3030 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3031 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3032 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3033 rtlight->static_numsurfaces = numsurfaces;
3034 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3035 rtlight->static_numleafs = numleafs;
3036 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3037 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3038 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3039 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3040 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3041 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3042 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3043 if (rtlight->static_numsurfaces)
3044 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3045 if (rtlight->static_numleafs)
3046 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3047 if (rtlight->static_numleafpvsbytes)
3048 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3049 if (rtlight->static_numshadowtrispvsbytes)
3050 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3051 if (rtlight->static_numlighttrispvsbytes)
3052 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3053 R_FrameData_SetMark();
3054 if (model->CompileShadowMap && rtlight->shadow)
3055 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3056 R_FrameData_ReturnToMark();
3057 // now we're done compiling the rtlight
3058 r_shadow_compilingrtlight = NULL;
3062 // use smallest available cullradius - box radius or light radius
3063 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3064 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3067 if (rtlight->static_numlighttrispvsbytes)
3068 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3069 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3073 if (rtlight->static_numshadowtrispvsbytes)
3074 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3075 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3078 if (developer_extra.integer)
3079 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);
3082 void R_RTLight_Uncompile(rtlight_t *rtlight)
3084 if (rtlight->compiled)
3086 if (rtlight->static_meshchain_shadow_shadowmap)
3087 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3088 rtlight->static_meshchain_shadow_shadowmap = NULL;
3089 // these allocations are grouped
3090 if (rtlight->static_surfacelist)
3091 Mem_Free(rtlight->static_surfacelist);
3092 rtlight->static_numleafs = 0;
3093 rtlight->static_numleafpvsbytes = 0;
3094 rtlight->static_leaflist = NULL;
3095 rtlight->static_leafpvs = NULL;
3096 rtlight->static_numsurfaces = 0;
3097 rtlight->static_surfacelist = NULL;
3098 rtlight->static_numshadowtrispvsbytes = 0;
3099 rtlight->static_shadowtrispvs = NULL;
3100 rtlight->static_numlighttrispvsbytes = 0;
3101 rtlight->static_lighttrispvs = NULL;
3102 rtlight->compiled = false;
3106 void R_Shadow_UncompileWorldLights(void)
3110 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3111 for (lightindex = 0;lightindex < range;lightindex++)
3113 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3116 R_RTLight_Uncompile(&light->rtlight);
3120 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3124 // reset the count of frustum planes
3125 // see rtlight->cached_frustumplanes definition for how much this array
3127 rtlight->cached_numfrustumplanes = 0;
3129 if (r_trippy.integer)
3132 // haven't implemented a culling path for ortho rendering
3133 if (!r_refdef.view.useperspective)
3135 // check if the light is on screen and copy the 4 planes if it is
3136 for (i = 0;i < 4;i++)
3137 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3140 for (i = 0;i < 4;i++)
3141 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3146 // generate a deformed frustum that includes the light origin, this is
3147 // used to cull shadow casting surfaces that can not possibly cast a
3148 // shadow onto the visible light-receiving surfaces, which can be a
3151 // if the light origin is onscreen the result will be 4 planes exactly
3152 // if the light origin is offscreen on only one axis the result will
3153 // be exactly 5 planes (split-side case)
3154 // if the light origin is offscreen on two axes the result will be
3155 // exactly 4 planes (stretched corner case)
3156 for (i = 0;i < 4;i++)
3158 // quickly reject standard frustum planes that put the light
3159 // origin outside the frustum
3160 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3163 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3165 // if all the standard frustum planes were accepted, the light is onscreen
3166 // otherwise we need to generate some more planes below...
3167 if (rtlight->cached_numfrustumplanes < 4)
3169 // at least one of the stock frustum planes failed, so we need to
3170 // create one or two custom planes to enclose the light origin
3171 for (i = 0;i < 4;i++)
3173 // create a plane using the view origin and light origin, and a
3174 // single point from the frustum corner set
3175 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3176 VectorNormalize(plane.normal);
3177 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3178 // see if this plane is backwards and flip it if so
3179 for (j = 0;j < 4;j++)
3180 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3184 VectorNegate(plane.normal, plane.normal);
3186 // flipped plane, test again to see if it is now valid
3187 for (j = 0;j < 4;j++)
3188 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3190 // if the plane is still not valid, then it is dividing the
3191 // frustum and has to be rejected
3195 // we have created a valid plane, compute extra info
3196 PlaneClassify(&plane);
3198 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3200 // if we've found 5 frustum planes then we have constructed a
3201 // proper split-side case and do not need to keep searching for
3202 // planes to enclose the light origin
3203 if (rtlight->cached_numfrustumplanes == 5)
3211 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3213 plane = rtlight->cached_frustumplanes[i];
3214 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));
3219 // now add the light-space box planes if the light box is rotated, as any
3220 // caster outside the oriented light box is irrelevant (even if it passed
3221 // the worldspace light box, which is axial)
3222 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3224 for (i = 0;i < 6;i++)
3228 v[i >> 1] = (i & 1) ? -1 : 1;
3229 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3230 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3231 plane.dist = VectorNormalizeLength(plane.normal);
3232 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3233 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3239 // add the world-space reduced box planes
3240 for (i = 0;i < 6;i++)
3242 VectorClear(plane.normal);
3243 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3244 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3245 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3254 // reduce all plane distances to tightly fit the rtlight cull box, which
3256 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3257 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3258 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3259 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3260 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3261 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3262 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3263 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3264 oldnum = rtlight->cached_numfrustumplanes;
3265 rtlight->cached_numfrustumplanes = 0;
3266 for (j = 0;j < oldnum;j++)
3268 // find the nearest point on the box to this plane
3269 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3270 for (i = 1;i < 8;i++)
3272 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3273 if (bestdist > dist)
3276 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);
3277 // if the nearest point is near or behind the plane, we want this
3278 // plane, otherwise the plane is useless as it won't cull anything
3279 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3281 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3282 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3289 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3291 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3293 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3295 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3296 if (mesh->sidetotals[r_shadow_shadowmapside])
3299 GL_CullFace(GL_NONE);
3300 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3301 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3302 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);
3306 else if (r_refdef.scene.worldentity->model)
3307 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);
3309 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3312 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3314 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3315 vec_t relativeshadowradius;
3316 RSurf_ActiveModelEntity(ent, false, false, false);
3317 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3318 // we need to re-init the shader for each entity because the matrix changed
3319 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3320 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3321 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3322 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3323 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3324 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3325 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3326 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3327 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3330 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3332 // set up properties for rendering light onto this entity
3333 RSurf_ActiveModelEntity(ent, true, true, false);
3334 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3335 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3336 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3337 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3340 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3342 if (!r_refdef.scene.worldmodel->DrawLight)
3345 // set up properties for rendering light onto this entity
3346 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3347 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3348 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3349 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3350 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3352 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3354 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3357 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3359 dp_model_t *model = ent->model;
3360 if (!model->DrawLight)
3363 R_Shadow_SetupEntityLight(ent);
3365 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3367 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3370 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3374 int numleafs, numsurfaces;
3375 int *leaflist, *surfacelist;
3376 unsigned char *leafpvs;
3377 unsigned char *shadowtrispvs;
3378 unsigned char *lighttrispvs;
3379 //unsigned char *surfacesides;
3380 int numlightentities;
3381 int numlightentities_noselfshadow;
3382 int numshadowentities;
3383 int numshadowentities_noselfshadow;
3384 // FIXME: bounds check lightentities and shadowentities, etc.
3385 static entity_render_t *lightentities[MAX_EDICTS];
3386 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3387 static entity_render_t *shadowentities[MAX_EDICTS];
3388 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3390 qboolean castshadows;
3392 rtlight->draw = false;
3393 rtlight->cached_numlightentities = 0;
3394 rtlight->cached_numlightentities_noselfshadow = 0;
3395 rtlight->cached_numshadowentities = 0;
3396 rtlight->cached_numshadowentities_noselfshadow = 0;
3397 rtlight->cached_numsurfaces = 0;
3398 rtlight->cached_lightentities = NULL;
3399 rtlight->cached_lightentities_noselfshadow = NULL;
3400 rtlight->cached_shadowentities = NULL;
3401 rtlight->cached_shadowentities_noselfshadow = NULL;
3402 rtlight->cached_shadowtrispvs = NULL;
3403 rtlight->cached_lighttrispvs = NULL;
3404 rtlight->cached_surfacelist = NULL;
3405 rtlight->shadowmapsidesize = 0;
3407 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3408 // skip lights that are basically invisible (color 0 0 0)
3409 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3411 // loading is done before visibility checks because loading should happen
3412 // all at once at the start of a level, not when it stalls gameplay.
3413 // (especially important to benchmarks)
3415 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3417 if (rtlight->compiled)
3418 R_RTLight_Uncompile(rtlight);
3419 R_RTLight_Compile(rtlight);
3423 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3425 // look up the light style value at this time
3426 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3427 VectorScale(rtlight->color, f, rtlight->currentcolor);
3429 if (rtlight->selected)
3431 f = 2 + sin(realtime * M_PI * 4.0);
3432 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3436 // skip if lightstyle is currently off
3437 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3440 // skip processing on corona-only lights
3444 // skip if the light box is not touching any visible leafs
3445 if (r_shadow_culllights_pvs.integer
3446 && r_refdef.scene.worldmodel
3447 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3448 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3451 // skip if the light box is not visible to traceline
3452 if (r_shadow_culllights_trace.integer)
3454 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))
3455 rtlight->trace_timer = realtime;
3456 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3460 // skip if the light box is off screen
3461 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3464 // in the typical case this will be quickly replaced by GetLightInfo
3465 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3466 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3468 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3470 // 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
3471 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3474 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3476 // compiled light, world available and can receive realtime lighting
3477 // retrieve leaf information
3478 numleafs = rtlight->static_numleafs;
3479 leaflist = rtlight->static_leaflist;
3480 leafpvs = rtlight->static_leafpvs;
3481 numsurfaces = rtlight->static_numsurfaces;
3482 surfacelist = rtlight->static_surfacelist;
3483 //surfacesides = NULL;
3484 shadowtrispvs = rtlight->static_shadowtrispvs;
3485 lighttrispvs = rtlight->static_lighttrispvs;
3487 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3489 // dynamic light, world available and can receive realtime lighting
3490 // calculate lit surfaces and leafs
3491 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);
3492 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3493 leaflist = r_shadow_buffer_leaflist;
3494 leafpvs = r_shadow_buffer_leafpvs;
3495 surfacelist = r_shadow_buffer_surfacelist;
3496 //surfacesides = r_shadow_buffer_surfacesides;
3497 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3498 lighttrispvs = r_shadow_buffer_lighttrispvs;
3499 // if the reduced leaf bounds are offscreen, skip it
3500 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3511 //surfacesides = NULL;
3512 shadowtrispvs = NULL;
3513 lighttrispvs = NULL;
3515 // check if light is illuminating any visible leafs
3518 for (i = 0; i < numleafs; i++)
3519 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3525 // make a list of lit entities and shadow casting entities
3526 numlightentities = 0;
3527 numlightentities_noselfshadow = 0;
3528 numshadowentities = 0;
3529 numshadowentities_noselfshadow = 0;
3531 // add dynamic entities that are lit by the light
3532 for (i = 0; i < r_refdef.scene.numentities; i++)
3535 entity_render_t *ent = r_refdef.scene.entities[i];
3537 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3539 // skip the object entirely if it is not within the valid
3540 // shadow-casting region (which includes the lit region)
3541 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3543 if (!(model = ent->model))
3545 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3547 // this entity wants to receive light, is visible, and is
3548 // inside the light box
3549 // TODO: check if the surfaces in the model can receive light
3550 // so now check if it's in a leaf seen by the light
3551 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))
3553 if (ent->flags & RENDER_NOSELFSHADOW)
3554 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3556 lightentities[numlightentities++] = ent;
3557 // since it is lit, it probably also casts a shadow...
3558 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3559 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3560 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3562 // note: exterior models without the RENDER_NOSELFSHADOW
3563 // flag still create a RENDER_NOSELFSHADOW shadow but
3564 // are lit normally, this means that they are
3565 // self-shadowing but do not shadow other
3566 // RENDER_NOSELFSHADOW entities such as the gun
3567 // (very weird, but keeps the player shadow off the gun)
3568 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3569 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3571 shadowentities[numshadowentities++] = ent;
3574 else if (ent->flags & RENDER_SHADOW)
3576 // this entity is not receiving light, but may still need to
3578 // TODO: check if the surfaces in the model can cast shadow
3579 // now check if it is in a leaf seen by the light
3580 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))
3582 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3583 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3584 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3586 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3587 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3589 shadowentities[numshadowentities++] = ent;
3594 // return if there's nothing at all to light
3595 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3598 // count this light in the r_speeds
3599 r_refdef.stats[r_stat_lights]++;
3601 // flag it as worth drawing later
3602 rtlight->draw = true;
3604 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3605 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3607 numshadowentities = numshadowentities_noselfshadow = 0;
3608 rtlight->castshadows = castshadows;
3610 // cache all the animated entities that cast a shadow but are not visible
3611 for (i = 0; i < numshadowentities; i++)
3612 R_AnimCache_GetEntity(shadowentities[i], false, false);
3613 for (i = 0; i < numshadowentities_noselfshadow; i++)
3614 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3616 // 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)
3617 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3619 for (i = 0; i < numshadowentities_noselfshadow; i++)
3620 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3621 numshadowentities_noselfshadow = 0;
3624 // we can convert noselfshadow to regular if there are no casters of that type
3625 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3627 for (i = 0; i < numlightentities_noselfshadow; i++)
3628 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3629 numlightentities_noselfshadow = 0;
3632 // allocate some temporary memory for rendering this light later in the frame
3633 // reusable buffers need to be copied, static data can be used as-is
3634 rtlight->cached_numlightentities = numlightentities;
3635 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3636 rtlight->cached_numshadowentities = numshadowentities;
3637 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3638 rtlight->cached_numsurfaces = numsurfaces;
3639 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3640 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3641 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3642 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3643 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3645 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3646 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3647 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3648 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3649 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3653 // compiled light data
3654 rtlight->cached_shadowtrispvs = shadowtrispvs;
3655 rtlight->cached_lighttrispvs = lighttrispvs;
3656 rtlight->cached_surfacelist = surfacelist;
3659 if (R_Shadow_ShadowMappingEnabled())
3661 // figure out the shadowmapping parameters for this light
3662 vec3_t nearestpoint;
3665 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3666 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3667 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3668 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3669 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3670 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3671 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3672 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3673 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3677 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3681 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3682 int numlightentities;
3683 int numlightentities_noselfshadow;
3684 int numshadowentities;
3685 int numshadowentities_noselfshadow;
3686 entity_render_t **lightentities;
3687 entity_render_t **lightentities_noselfshadow;
3688 entity_render_t **shadowentities;
3689 entity_render_t **shadowentities_noselfshadow;
3691 static unsigned char entitysides[MAX_EDICTS];
3692 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3698 matrix4x4_t radiustolight;
3700 // check if we cached this light this frame (meaning it is worth drawing)
3701 if (!rtlight->draw || !rtlight->castshadows)
3704 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3705 if (rtlight->shadowmapatlassidesize == 0)
3707 rtlight->castshadows = false;
3711 // set up a scissor rectangle for this light
3712 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3715 // don't let sound skip if going slow
3716 if (r_refdef.scene.extraupdate)
3719 numlightentities = rtlight->cached_numlightentities;
3720 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3721 numshadowentities = rtlight->cached_numshadowentities;
3722 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3723 numsurfaces = rtlight->cached_numsurfaces;
3724 lightentities = rtlight->cached_lightentities;
3725 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3726 shadowentities = rtlight->cached_shadowentities;
3727 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3728 shadowtrispvs = rtlight->cached_shadowtrispvs;
3729 lighttrispvs = rtlight->cached_lighttrispvs;
3730 surfacelist = rtlight->cached_surfacelist;
3732 // make this the active rtlight for rendering purposes
3733 R_Shadow_RenderMode_ActiveLight(rtlight);
3735 radiustolight = rtlight->matrix_worldtolight;
3736 Matrix4x4_Abs(&radiustolight);
3738 size = rtlight->shadowmapatlassidesize;
3739 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3741 surfacesides = NULL;
3746 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3748 castermask = rtlight->static_shadowmap_casters;
3749 receivermask = rtlight->static_shadowmap_receivers;
3753 surfacesides = r_shadow_buffer_surfacesides;
3754 for (i = 0; i < numsurfaces; i++)
3756 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3757 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3758 castermask |= surfacesides[i];
3759 receivermask |= surfacesides[i];
3764 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3765 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3766 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3767 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3769 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3773 for (i = 0; i < numshadowentities; i++)
3774 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3775 for (i = 0; i < numshadowentities_noselfshadow; i++)
3776 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3779 // there is no need to render shadows for sides that have no receivers...
3780 castermask &= receivermask;
3782 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3784 // render shadow casters into shadowmaps for this light
3785 for (side = 0; side < 6; side++)
3787 int bit = 1 << side;
3788 if (castermask & bit)
3790 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3792 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3793 for (i = 0; i < numshadowentities; i++)
3794 if (entitysides[i] & bit)
3795 R_Shadow_DrawEntityShadow(shadowentities[i]);
3796 for (i = 0; i < numshadowentities_noselfshadow; i++)
3797 if (entitysides_noselfshadow[i] & bit)
3798 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3801 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3802 if (numshadowentities_noselfshadow)
3804 for (side = 0; side < 6; side++)
3806 int bit = 1 << side;
3807 if (castermask & bit)
3809 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3811 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3812 for (i = 0; i < numshadowentities; i++)
3813 if (entitysides[i] & bit)
3814 R_Shadow_DrawEntityShadow(shadowentities[i]);
3820 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3824 unsigned char *shadowtrispvs, *lighttrispvs;
3825 int numlightentities;
3826 int numlightentities_noselfshadow;
3827 int numshadowentities;
3828 int numshadowentities_noselfshadow;
3829 entity_render_t **lightentities;
3830 entity_render_t **lightentities_noselfshadow;
3831 entity_render_t **shadowentities;
3832 entity_render_t **shadowentities_noselfshadow;
3834 qboolean castshadows;
3836 // check if we cached this light this frame (meaning it is worth drawing)
3840 // set up a scissor rectangle for this light
3841 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3844 // don't let sound skip if going slow
3845 if (r_refdef.scene.extraupdate)
3848 numlightentities = rtlight->cached_numlightentities;
3849 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3850 numshadowentities = rtlight->cached_numshadowentities;
3851 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3852 numsurfaces = rtlight->cached_numsurfaces;
3853 lightentities = rtlight->cached_lightentities;
3854 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3855 shadowentities = rtlight->cached_shadowentities;
3856 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3857 shadowtrispvs = rtlight->cached_shadowtrispvs;
3858 lighttrispvs = rtlight->cached_lighttrispvs;
3859 surfacelist = rtlight->cached_surfacelist;
3860 castshadows = rtlight->castshadows;
3862 // make this the active rtlight for rendering purposes
3863 R_Shadow_RenderMode_ActiveLight(rtlight);
3865 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3867 // optionally draw the illuminated areas
3868 // for performance analysis by level designers
3869 R_Shadow_RenderMode_VisibleLighting(false);
3871 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3872 for (i = 0;i < numlightentities;i++)
3873 R_Shadow_DrawEntityLight(lightentities[i]);
3874 for (i = 0;i < numlightentities_noselfshadow;i++)
3875 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3878 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3882 float shadowmapoffsetnoselfshadow = 0;
3883 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3884 Matrix4x4_Abs(&radiustolight);
3886 size = rtlight->shadowmapatlassidesize;
3887 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3889 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3891 if (rtlight->cached_numshadowentities_noselfshadow)
3892 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3894 // render lighting using the depth texture as shadowmap
3895 // draw lighting in the unmasked areas
3896 if (numsurfaces + numlightentities)
3898 R_Shadow_RenderMode_Lighting(false, true, false);
3899 // draw lighting in the unmasked areas
3901 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3902 for (i = 0; i < numlightentities; i++)
3903 R_Shadow_DrawEntityLight(lightentities[i]);
3905 // offset to the noselfshadow part of the atlas and draw those too
3906 if (numlightentities_noselfshadow)
3908 R_Shadow_RenderMode_Lighting(false, true, true);
3909 for (i = 0; i < numlightentities_noselfshadow; i++)
3910 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3913 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3914 if (r_shadow_usingdeferredprepass)
3915 R_Shadow_RenderMode_DrawDeferredLight(true);
3919 // draw lighting in the unmasked areas
3920 R_Shadow_RenderMode_Lighting(false, false, false);
3922 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3923 for (i = 0;i < numlightentities;i++)
3924 R_Shadow_DrawEntityLight(lightentities[i]);
3925 for (i = 0;i < numlightentities_noselfshadow;i++)
3926 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3928 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3929 if (r_shadow_usingdeferredprepass)
3930 R_Shadow_RenderMode_DrawDeferredLight(false);
3934 static void R_Shadow_FreeDeferred(void)
3936 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3937 r_shadow_prepassgeometryfbo = 0;
3939 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3940 r_shadow_prepasslightingdiffusespecularfbo = 0;
3942 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3943 r_shadow_prepasslightingdiffusefbo = 0;
3945 if (r_shadow_prepassgeometrydepthbuffer)
3946 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3947 r_shadow_prepassgeometrydepthbuffer = NULL;
3949 if (r_shadow_prepassgeometrynormalmaptexture)
3950 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3951 r_shadow_prepassgeometrynormalmaptexture = NULL;
3953 if (r_shadow_prepasslightingdiffusetexture)
3954 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3955 r_shadow_prepasslightingdiffusetexture = NULL;
3957 if (r_shadow_prepasslightingspeculartexture)
3958 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3959 r_shadow_prepasslightingspeculartexture = NULL;
3962 void R_Shadow_DrawPrepass(void)
3966 entity_render_t *ent;
3967 float clearcolor[4];
3969 R_Mesh_ResetTextureState();
3971 GL_ColorMask(1,1,1,1);
3972 GL_BlendFunc(GL_ONE, GL_ZERO);
3975 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3976 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3977 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3978 if (r_timereport_active)
3979 R_TimeReport("prepasscleargeom");
3981 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3982 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3983 if (r_timereport_active)
3984 R_TimeReport("prepassworld");
3986 for (i = 0;i < r_refdef.scene.numentities;i++)
3988 if (!r_refdef.viewcache.entityvisible[i])
3990 ent = r_refdef.scene.entities[i];
3991 if (ent->model && ent->model->DrawPrepass != NULL)
3992 ent->model->DrawPrepass(ent);
3995 if (r_timereport_active)
3996 R_TimeReport("prepassmodels");
3998 GL_DepthMask(false);
3999 GL_ColorMask(1,1,1,1);
4002 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4003 Vector4Set(clearcolor, 0, 0, 0, 0);
4004 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4005 if (r_timereport_active)
4006 R_TimeReport("prepassclearlit");
4008 R_Shadow_RenderMode_Begin();
4010 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4011 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4013 R_Shadow_RenderMode_End();
4015 if (r_timereport_active)
4016 R_TimeReport("prepasslights");
4019 #define MAX_SCENELIGHTS 65536
4020 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4022 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4024 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4026 r_shadow_scenemaxlights *= 2;
4027 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4028 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4030 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4034 void R_Shadow_DrawLightSprites(void);
4035 void R_Shadow_PrepareLights(void)
4044 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4045 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4046 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4048 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4049 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4050 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4051 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4052 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4053 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4054 r_shadow_shadowmapborder != shadowmapborder ||
4055 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4056 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4057 R_Shadow_FreeShadowMaps();
4059 r_shadow_usingshadowmaportho = false;
4061 switch (vid.renderpath)
4063 case RENDERPATH_GL32:
4065 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4067 r_shadow_usingdeferredprepass = false;
4068 if (r_shadow_prepass_width)
4069 R_Shadow_FreeDeferred();
4070 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4074 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4076 R_Shadow_FreeDeferred();
4078 r_shadow_usingdeferredprepass = true;
4079 r_shadow_prepass_width = vid.width;
4080 r_shadow_prepass_height = vid.height;
4081 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4082 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);
4083 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);
4084 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);
4086 // set up the geometry pass fbo (depth + normalmap)
4087 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4088 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4089 // render depth into a renderbuffer and other important properties into the normalmap texture
4091 // set up the lighting pass fbo (diffuse + specular)
4092 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4093 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4094 // render diffuse into one texture and specular into another,
4095 // with depth and normalmap bound as textures,
4096 // with depth bound as attachment as well
4098 // set up the lighting pass fbo (diffuse)
4099 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4100 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4101 // render diffuse into one texture,
4102 // with depth and normalmap bound as textures,
4103 // with depth bound as attachment as well
4107 case RENDERPATH_GLES2:
4108 r_shadow_usingdeferredprepass = false;
4112 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);
4114 r_shadow_scenenumlights = 0;
4115 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4116 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4117 for (lightindex = 0; lightindex < range; lightindex++)
4119 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4120 if (light && (light->flags & flag))
4122 R_Shadow_PrepareLight(&light->rtlight);
4123 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4126 if (r_refdef.scene.rtdlight)
4128 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4130 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4131 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4134 else if (gl_flashblend.integer)
4136 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4138 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4139 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4140 VectorScale(rtlight->color, f, rtlight->currentcolor);
4144 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4145 if (r_shadow_debuglight.integer >= 0)
4147 r_shadow_scenenumlights = 0;
4148 lightindex = r_shadow_debuglight.integer;
4149 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4152 R_Shadow_PrepareLight(&light->rtlight);
4153 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4157 // if we're doing shadowmaps we need to prepare the atlas layout now
4158 if (R_Shadow_ShadowMappingEnabled())
4162 // allocate shadowmaps in the atlas now
4163 // 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...
4164 for (lod = 0; lod < 16; lod++)
4166 int packing_success = 0;
4167 int packing_failure = 0;
4168 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4169 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4170 if (r_shadow_shadowmapatlas_modelshadows_size)
4171 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);
4172 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4174 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4175 int size = rtlight->shadowmapsidesize >> lod;
4177 if (!rtlight->castshadows)
4179 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4182 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4183 if (rtlight->cached_numshadowentities_noselfshadow)
4185 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4187 rtlight->shadowmapatlassidesize = size;
4192 // note down that we failed to pack this one, it will have to disable shadows
4193 rtlight->shadowmapatlassidesize = 0;
4197 // generally everything fits and we stop here on the first iteration
4198 if (packing_failure == 0)
4203 if (r_editlights.integer)
4204 R_Shadow_DrawLightSprites();
4207 void R_Shadow_DrawShadowMaps(void)
4209 R_Shadow_RenderMode_Begin();
4210 R_Shadow_RenderMode_ActiveLight(NULL);
4212 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4213 R_Shadow_ClearShadowMapTexture();
4215 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4216 if (r_shadow_shadowmapatlas_modelshadows_size)
4218 R_Shadow_DrawModelShadowMaps();
4219 // don't let sound skip if going slow
4220 if (r_refdef.scene.extraupdate)
4224 if (R_Shadow_ShadowMappingEnabled())
4227 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4228 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4231 R_Shadow_RenderMode_End();
4234 void R_Shadow_DrawLights(void)
4238 R_Shadow_RenderMode_Begin();
4240 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4241 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4243 R_Shadow_RenderMode_End();
4246 #define MAX_MODELSHADOWS 1024
4247 static int r_shadow_nummodelshadows;
4248 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4250 void R_Shadow_PrepareModelShadows(void)
4253 float scale, size, radius, dot1, dot2;
4254 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4255 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4256 entity_render_t *ent;
4258 r_shadow_nummodelshadows = 0;
4259 r_shadow_shadowmapatlas_modelshadows_size = 0;
4261 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4264 size = r_shadow_shadowmaptexturesize / 4;
4265 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4266 radius = 0.5f * size / scale;
4268 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4269 VectorCopy(prvmshadowdir, shadowdir);
4270 VectorNormalize(shadowdir);
4271 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4272 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4273 if (fabs(dot1) <= fabs(dot2))
4274 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4276 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4277 VectorNormalize(shadowforward);
4278 CrossProduct(shadowdir, shadowforward, shadowright);
4279 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4280 VectorCopy(prvmshadowfocus, shadowfocus);
4281 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4282 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4283 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4284 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4285 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4287 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4289 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4290 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4291 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4292 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4293 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4294 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4296 for (i = 0; i < r_refdef.scene.numentities; i++)
4298 ent = r_refdef.scene.entities[i];
4299 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4301 // cast shadows from anything of the map (submodels are optional)
4302 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4304 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4306 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4307 R_AnimCache_GetEntity(ent, false, false);
4311 if (r_shadow_nummodelshadows)
4313 r_shadow_shadowmapatlas_modelshadows_x = 0;
4314 r_shadow_shadowmapatlas_modelshadows_y = 0;
4315 r_shadow_shadowmapatlas_modelshadows_size = size;
4319 static void R_Shadow_DrawModelShadowMaps(void)
4322 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4323 entity_render_t *ent;
4324 vec3_t relativelightorigin;
4325 vec3_t relativelightdirection, relativeforward, relativeright;
4326 vec3_t relativeshadowmins, relativeshadowmaxs;
4327 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4328 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4330 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4331 r_viewport_t viewport;
4333 size = r_shadow_shadowmapatlas_modelshadows_size;
4334 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4335 radius = 0.5f / scale;
4336 nearclip = -r_shadows_throwdistance.value;
4337 farclip = r_shadows_throwdistance.value;
4338 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);
4340 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4341 r_shadow_modelshadowmap_parameters[0] = size;
4342 r_shadow_modelshadowmap_parameters[1] = size;
4343 r_shadow_modelshadowmap_parameters[2] = 1.0;
4344 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4345 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4346 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4347 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4348 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4349 r_shadow_usingshadowmaportho = true;
4351 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4352 VectorCopy(prvmshadowdir, shadowdir);
4353 VectorNormalize(shadowdir);
4354 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4355 VectorCopy(prvmshadowfocus, shadowfocus);
4356 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4357 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4358 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4359 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4360 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4361 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4362 if (fabs(dot1) <= fabs(dot2))
4363 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4365 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4366 VectorNormalize(shadowforward);
4367 VectorM(scale, shadowforward, &m[0]);
4368 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4370 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4371 CrossProduct(shadowdir, shadowforward, shadowright);
4372 VectorM(scale, shadowright, &m[4]);
4373 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4374 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4375 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4376 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4377 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4378 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);
4379 R_SetViewport(&viewport);
4381 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4383 // render into a slightly restricted region so that the borders of the
4384 // shadowmap area fade away, rather than streaking across everything
4385 // outside the usable area
4386 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4388 for (i = 0;i < r_shadow_nummodelshadows;i++)
4390 ent = r_shadow_modelshadows[i];
4391 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4392 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4393 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4394 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4395 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4396 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4397 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4398 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4399 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4400 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4401 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4402 RSurf_ActiveModelEntity(ent, false, false, false);
4403 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4404 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4410 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4412 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4414 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4415 Cvar_SetValueQuick(&r_test, 0);
4420 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4421 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4422 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4423 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4424 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4425 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4428 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4431 vec3_t centerorigin;
4435 // if it's too close, skip it
4436 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4438 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4441 if (usequery && r_numqueries + 2 <= r_maxqueries)
4443 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4444 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4445 // 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
4446 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4448 switch(vid.renderpath)
4450 case RENDERPATH_GL32:
4451 case RENDERPATH_GLES2:
4454 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4455 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4456 GL_DepthFunc(GL_ALWAYS);
4457 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4458 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4459 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4460 qglEndQuery(GL_SAMPLES_PASSED);
4461 GL_DepthFunc(GL_LEQUAL);
4462 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4463 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4464 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4465 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4466 qglEndQuery(GL_SAMPLES_PASSED);
4472 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4475 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4477 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4480 unsigned int occlude = 0;
4482 // now we have to check the query result
4483 if (rtlight->corona_queryindex_visiblepixels)
4485 switch(vid.renderpath)
4487 case RENDERPATH_GL32:
4488 case RENDERPATH_GLES2:
4490 // store the pixel counts into a uniform buffer for the shader to
4491 // use - we'll never know the results on the cpu without
4492 // synchronizing and we don't want that
4493 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4494 if (!r_shadow_occlusion_buf) {
4495 qglGenBuffers(1, &r_shadow_occlusion_buf);
4496 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4497 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4499 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4501 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4502 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4503 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4504 occlude = MATERIALFLAG_OCCLUDE;
4505 cscale *= rtlight->corona_visibility;
4515 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4518 VectorScale(rtlight->currentcolor, cscale, color);
4519 if (VectorLength(color) > (1.0f / 256.0f))
4522 qboolean negated = (color[0] + color[1] + color[2] < 0);
4525 VectorNegate(color, color);
4526 GL_BlendEquationSubtract(true);
4528 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4529 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);
4530 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
4532 GL_BlendEquationSubtract(false);
4536 void R_Shadow_DrawCoronas(void)
4539 qboolean usequery = false;
4544 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4546 if (r_fb.water.renderingscene)
4548 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4549 R_EntityMatrix(&identitymatrix);
4551 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4553 // check occlusion of coronas, using occlusion queries or raytraces
4555 switch (vid.renderpath)
4557 case RENDERPATH_GL32:
4558 case RENDERPATH_GLES2:
4559 usequery = r_coronas_occlusionquery.integer;
4563 GL_ColorMask(0,0,0,0);
4564 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4565 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4568 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4569 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4571 qglGenQueries(r_maxqueries - i, r_queries + i);
4574 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4575 GL_BlendFunc(GL_ONE, GL_ZERO);
4576 GL_CullFace(GL_NONE);
4577 GL_DepthMask(false);
4578 GL_DepthRange(0, 1);
4579 GL_PolygonOffset(0, 0);
4581 R_Mesh_ResetTextureState();
4582 R_SetupShader_Generic_NoTexture(false, false);
4587 for (lightindex = 0;lightindex < range;lightindex++)
4589 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4592 rtlight = &light->rtlight;
4593 rtlight->corona_visibility = 0;
4594 rtlight->corona_queryindex_visiblepixels = 0;
4595 rtlight->corona_queryindex_allpixels = 0;
4596 if (!(rtlight->flags & flag))
4598 if (rtlight->corona <= 0)
4600 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4602 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4604 for (i = 0;i < r_refdef.scene.numlights;i++)
4606 rtlight = r_refdef.scene.lights[i];
4607 rtlight->corona_visibility = 0;
4608 rtlight->corona_queryindex_visiblepixels = 0;
4609 rtlight->corona_queryindex_allpixels = 0;
4610 if (!(rtlight->flags & flag))
4612 if (rtlight->corona <= 0)
4614 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4617 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4619 // now draw the coronas using the query data for intensity info
4620 for (lightindex = 0;lightindex < range;lightindex++)
4622 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4625 rtlight = &light->rtlight;
4626 if (rtlight->corona_visibility <= 0)
4628 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4630 for (i = 0;i < r_refdef.scene.numlights;i++)
4632 rtlight = r_refdef.scene.lights[i];
4633 if (rtlight->corona_visibility <= 0)
4635 if (gl_flashblend.integer)
4636 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4638 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4644 static dlight_t *R_Shadow_NewWorldLight(void)
4646 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4649 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)
4653 // 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
4655 // validate parameters
4659 // copy to light properties
4660 VectorCopy(origin, light->origin);
4661 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4662 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4663 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4665 light->color[0] = max(color[0], 0);
4666 light->color[1] = max(color[1], 0);
4667 light->color[2] = max(color[2], 0);
4669 light->color[0] = color[0];
4670 light->color[1] = color[1];
4671 light->color[2] = color[2];
4672 light->radius = max(radius, 0);
4673 light->style = style;
4674 light->shadow = shadowenable;
4675 light->corona = corona;
4676 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4677 light->coronasizescale = coronasizescale;
4678 light->ambientscale = ambientscale;
4679 light->diffusescale = diffusescale;
4680 light->specularscale = specularscale;
4681 light->flags = flags;
4683 // update renderable light data
4684 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4685 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);
4688 static void R_Shadow_FreeWorldLight(dlight_t *light)
4690 if (r_shadow_selectedlight == light)
4691 r_shadow_selectedlight = NULL;
4692 R_RTLight_Uncompile(&light->rtlight);
4693 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4696 void R_Shadow_ClearWorldLights(void)
4700 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4701 for (lightindex = 0;lightindex < range;lightindex++)
4703 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4705 R_Shadow_FreeWorldLight(light);
4707 r_shadow_selectedlight = NULL;
4710 static void R_Shadow_SelectLight(dlight_t *light)
4712 if (r_shadow_selectedlight)
4713 r_shadow_selectedlight->selected = false;
4714 r_shadow_selectedlight = light;
4715 if (r_shadow_selectedlight)
4716 r_shadow_selectedlight->selected = true;
4719 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4721 // this is never batched (there can be only one)
4723 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4724 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4725 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4728 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4733 skinframe_t *skinframe;
4736 // this is never batched (due to the ent parameter changing every time)
4737 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4738 const dlight_t *light = (dlight_t *)ent;
4741 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4744 VectorScale(light->color, intensity, spritecolor);
4745 if (VectorLength(spritecolor) < 0.1732f)
4746 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4747 if (VectorLength(spritecolor) > 1.0f)
4748 VectorNormalize(spritecolor);
4750 // draw light sprite
4751 if (light->cubemapname[0] && !light->shadow)
4752 skinframe = r_editlights_sprcubemapnoshadowlight;
4753 else if (light->cubemapname[0])
4754 skinframe = r_editlights_sprcubemaplight;
4755 else if (!light->shadow)
4756 skinframe = r_editlights_sprnoshadowlight;
4758 skinframe = r_editlights_sprlight;
4760 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);
4761 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4763 // draw selection sprite if light is selected
4764 if (light->selected)
4766 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4767 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4768 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4772 void R_Shadow_DrawLightSprites(void)
4776 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4777 for (lightindex = 0;lightindex < range;lightindex++)
4779 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4781 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4783 if (!r_editlights_lockcursor)
4784 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4787 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4792 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4793 if (lightindex >= range)
4795 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4798 rtlight = &light->rtlight;
4799 //if (!(rtlight->flags & flag))
4801 VectorCopy(rtlight->shadoworigin, origin);
4802 *radius = rtlight->radius;
4803 VectorCopy(rtlight->color, color);
4807 static void R_Shadow_SelectLightInView(void)
4809 float bestrating, rating, temp[3];
4813 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4817 if (r_editlights_lockcursor)
4819 for (lightindex = 0;lightindex < range;lightindex++)
4821 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4824 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4825 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4828 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4829 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)
4831 bestrating = rating;
4836 R_Shadow_SelectLight(best);
4839 void R_Shadow_LoadWorldLights(void)
4841 int n, a, style, shadow, flags;
4842 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4843 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4844 if (cl.worldmodel == NULL)
4846 Con_Print("No map loaded.\n");
4849 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4850 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4860 for (;COM_Parse(t, true) && strcmp(
4861 if (COM_Parse(t, true))
4863 if (com_token[0] == '!')
4866 origin[0] = atof(com_token+1);
4869 origin[0] = atof(com_token);
4874 while (*s && *s != '\n' && *s != '\r')
4880 // check for modifier flags
4887 #if _MSC_VER >= 1400
4888 #define sscanf sscanf_s
4890 cubemapname[sizeof(cubemapname)-1] = 0;
4891 #if MAX_QPATH != 128
4892 #error update this code if MAX_QPATH changes
4894 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
4895 #if _MSC_VER >= 1400
4896 , sizeof(cubemapname)
4898 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4901 flags = LIGHTFLAG_REALTIMEMODE;
4909 coronasizescale = 0.25f;
4911 VectorClear(angles);
4914 if (a < 9 || !strcmp(cubemapname, "\"\""))
4916 // remove quotes on cubemapname
4917 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4920 namelen = strlen(cubemapname) - 2;
4921 memmove(cubemapname, cubemapname + 1, namelen);
4922 cubemapname[namelen] = '\0';
4926 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);
4929 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4937 Con_Printf("invalid rtlights file \"%s\"\n", name);
4938 Mem_Free(lightsstring);
4942 void R_Shadow_SaveWorldLights(void)
4946 size_t bufchars, bufmaxchars;
4948 char name[MAX_QPATH];
4949 char line[MAX_INPUTLINE];
4950 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4951 // I hate lines which are 3 times my screen size :( --blub
4954 if (cl.worldmodel == NULL)
4956 Con_Print("No map loaded.\n");
4959 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4960 bufchars = bufmaxchars = 0;
4962 for (lightindex = 0;lightindex < range;lightindex++)
4964 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4967 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4968 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);
4969 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4970 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]);
4972 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);
4973 if (bufchars + strlen(line) > bufmaxchars)
4975 bufmaxchars = bufchars + strlen(line) + 2048;
4977 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4981 memcpy(buf, oldbuf, bufchars);
4987 memcpy(buf + bufchars, line, strlen(line));
4988 bufchars += strlen(line);
4992 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4997 void R_Shadow_LoadLightsFile(void)
5000 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5001 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5002 if (cl.worldmodel == NULL)
5004 Con_Print("No map loaded.\n");
5007 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5008 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5016 while (*s && *s != '\n' && *s != '\r')
5022 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);
5026 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);
5029 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5030 radius = bound(15, radius, 4096);
5031 VectorScale(color, (2.0f / (8388608.0f)), color);
5032 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5040 Con_Printf("invalid lights file \"%s\"\n", name);
5041 Mem_Free(lightsstring);
5045 // tyrlite/hmap2 light types in the delay field
5046 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5048 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5060 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5061 char key[256], value[MAX_INPUTLINE];
5064 if (cl.worldmodel == NULL)
5066 Con_Print("No map loaded.\n");
5069 // try to load a .ent file first
5070 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5071 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5072 // and if that is not found, fall back to the bsp file entity string
5074 data = cl.worldmodel->brush.entities;
5077 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5079 type = LIGHTTYPE_MINUSX;
5080 origin[0] = origin[1] = origin[2] = 0;
5081 originhack[0] = originhack[1] = originhack[2] = 0;
5082 angles[0] = angles[1] = angles[2] = 0;
5083 color[0] = color[1] = color[2] = 1;
5084 light[0] = light[1] = light[2] = 1;light[3] = 300;
5085 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5095 if (!COM_ParseToken_Simple(&data, false, false, true))
5097 if (com_token[0] == '}')
5098 break; // end of entity
5099 if (com_token[0] == '_')
5100 strlcpy(key, com_token + 1, sizeof(key));
5102 strlcpy(key, com_token, sizeof(key));
5103 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5104 key[strlen(key)-1] = 0;
5105 if (!COM_ParseToken_Simple(&data, false, false, true))
5107 strlcpy(value, com_token, sizeof(value));
5109 // now that we have the key pair worked out...
5110 if (!strcmp("light", key))
5112 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5116 light[0] = vec[0] * (1.0f / 256.0f);
5117 light[1] = vec[0] * (1.0f / 256.0f);
5118 light[2] = vec[0] * (1.0f / 256.0f);
5124 light[0] = vec[0] * (1.0f / 255.0f);
5125 light[1] = vec[1] * (1.0f / 255.0f);
5126 light[2] = vec[2] * (1.0f / 255.0f);
5130 else if (!strcmp("delay", key))
5132 else if (!strcmp("origin", key))
5133 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5134 else if (!strcmp("angle", key))
5135 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5136 else if (!strcmp("angles", key))
5137 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5138 else if (!strcmp("color", key))
5139 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5140 else if (!strcmp("wait", key))
5141 fadescale = atof(value);
5142 else if (!strcmp("classname", key))
5144 if (!strncmp(value, "light", 5))
5147 if (!strcmp(value, "light_fluoro"))
5152 overridecolor[0] = 1;
5153 overridecolor[1] = 1;
5154 overridecolor[2] = 1;
5156 if (!strcmp(value, "light_fluorospark"))
5161 overridecolor[0] = 1;
5162 overridecolor[1] = 1;
5163 overridecolor[2] = 1;
5165 if (!strcmp(value, "light_globe"))
5170 overridecolor[0] = 1;
5171 overridecolor[1] = 0.8;
5172 overridecolor[2] = 0.4;
5174 if (!strcmp(value, "light_flame_large_yellow"))
5179 overridecolor[0] = 1;
5180 overridecolor[1] = 0.5;
5181 overridecolor[2] = 0.1;
5183 if (!strcmp(value, "light_flame_small_yellow"))
5188 overridecolor[0] = 1;
5189 overridecolor[1] = 0.5;
5190 overridecolor[2] = 0.1;
5192 if (!strcmp(value, "light_torch_small_white"))
5197 overridecolor[0] = 1;
5198 overridecolor[1] = 0.5;
5199 overridecolor[2] = 0.1;
5201 if (!strcmp(value, "light_torch_small_walltorch"))
5206 overridecolor[0] = 1;
5207 overridecolor[1] = 0.5;
5208 overridecolor[2] = 0.1;
5212 else if (!strcmp("style", key))
5213 style = atoi(value);
5214 else if (!strcmp("skin", key))
5215 skin = (int)atof(value);
5216 else if (!strcmp("pflags", key))
5217 pflags = (int)atof(value);
5218 //else if (!strcmp("effects", key))
5219 // effects = (int)atof(value);
5220 else if (cl.worldmodel->type == mod_brushq3)
5222 if (!strcmp("scale", key))
5223 lightscale = atof(value);
5224 if (!strcmp("fade", key))
5225 fadescale = atof(value);
5230 if (lightscale <= 0)
5234 if (color[0] == color[1] && color[0] == color[2])
5236 color[0] *= overridecolor[0];
5237 color[1] *= overridecolor[1];
5238 color[2] *= overridecolor[2];
5240 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5241 color[0] = color[0] * light[0];
5242 color[1] = color[1] * light[1];
5243 color[2] = color[2] * light[2];
5246 case LIGHTTYPE_MINUSX:
5248 case LIGHTTYPE_RECIPX:
5250 VectorScale(color, (1.0f / 16.0f), color);
5252 case LIGHTTYPE_RECIPXX:
5254 VectorScale(color, (1.0f / 16.0f), color);
5257 case LIGHTTYPE_NONE:
5261 case LIGHTTYPE_MINUSXX:
5264 VectorAdd(origin, originhack, origin);
5266 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);
5269 Mem_Free(entfiledata);
5273 static void R_Shadow_SetCursorLocationForView(void)
5276 vec3_t dest, endpos;
5278 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5279 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5280 if (trace.fraction < 1)
5282 dist = trace.fraction * r_editlights_cursordistance.value;
5283 push = r_editlights_cursorpushback.value;
5287 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5288 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5292 VectorClear( endpos );
5294 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5295 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5296 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5299 void R_Shadow_UpdateWorldLightSelection(void)
5301 if (r_editlights.integer)
5303 R_Shadow_SetCursorLocationForView();
5304 R_Shadow_SelectLightInView();
5307 R_Shadow_SelectLight(NULL);
5310 static void R_Shadow_EditLights_Clear_f(void)
5312 R_Shadow_ClearWorldLights();
5315 void R_Shadow_EditLights_Reload_f(void)
5319 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5320 R_Shadow_ClearWorldLights();
5321 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5323 R_Shadow_LoadWorldLights();
5324 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5325 R_Shadow_LoadLightsFile();
5327 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5329 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5330 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5334 static void R_Shadow_EditLights_Save_f(void)
5338 R_Shadow_SaveWorldLights();
5341 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5343 R_Shadow_ClearWorldLights();
5344 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5347 static void R_Shadow_EditLights_ImportLightsFile_f(void)
5349 R_Shadow_ClearWorldLights();
5350 R_Shadow_LoadLightsFile();
5353 static void R_Shadow_EditLights_Spawn_f(void)
5356 if (!r_editlights.integer)
5358 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5361 if (Cmd_Argc() != 1)
5363 Con_Print("r_editlights_spawn does not take parameters\n");
5366 color[0] = color[1] = color[2] = 1;
5367 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5370 static void R_Shadow_EditLights_Edit_f(void)
5372 vec3_t origin, angles, color;
5373 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5374 int style, shadows, flags, normalmode, realtimemode;
5375 char cubemapname[MAX_INPUTLINE];
5376 if (!r_editlights.integer)
5378 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5381 if (!r_shadow_selectedlight)
5383 Con_Print("No selected light.\n");
5386 VectorCopy(r_shadow_selectedlight->origin, origin);
5387 VectorCopy(r_shadow_selectedlight->angles, angles);
5388 VectorCopy(r_shadow_selectedlight->color, color);
5389 radius = r_shadow_selectedlight->radius;
5390 style = r_shadow_selectedlight->style;
5391 if (r_shadow_selectedlight->cubemapname)
5392 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5395 shadows = r_shadow_selectedlight->shadow;
5396 corona = r_shadow_selectedlight->corona;
5397 coronasizescale = r_shadow_selectedlight->coronasizescale;
5398 ambientscale = r_shadow_selectedlight->ambientscale;
5399 diffusescale = r_shadow_selectedlight->diffusescale;
5400 specularscale = r_shadow_selectedlight->specularscale;
5401 flags = r_shadow_selectedlight->flags;
5402 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5403 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5404 if (!strcmp(Cmd_Argv(1), "origin"))
5406 if (Cmd_Argc() != 5)
5408 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5411 origin[0] = atof(Cmd_Argv(2));
5412 origin[1] = atof(Cmd_Argv(3));
5413 origin[2] = atof(Cmd_Argv(4));
5415 else if (!strcmp(Cmd_Argv(1), "originscale"))
5417 if (Cmd_Argc() != 5)
5419 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5422 origin[0] *= atof(Cmd_Argv(2));
5423 origin[1] *= atof(Cmd_Argv(3));
5424 origin[2] *= atof(Cmd_Argv(4));
5426 else if (!strcmp(Cmd_Argv(1), "originx"))
5428 if (Cmd_Argc() != 3)
5430 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5433 origin[0] = atof(Cmd_Argv(2));
5435 else if (!strcmp(Cmd_Argv(1), "originy"))
5437 if (Cmd_Argc() != 3)
5439 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5442 origin[1] = atof(Cmd_Argv(2));
5444 else if (!strcmp(Cmd_Argv(1), "originz"))
5446 if (Cmd_Argc() != 3)
5448 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5451 origin[2] = atof(Cmd_Argv(2));
5453 else if (!strcmp(Cmd_Argv(1), "move"))
5455 if (Cmd_Argc() != 5)
5457 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5460 origin[0] += atof(Cmd_Argv(2));
5461 origin[1] += atof(Cmd_Argv(3));
5462 origin[2] += atof(Cmd_Argv(4));
5464 else if (!strcmp(Cmd_Argv(1), "movex"))
5466 if (Cmd_Argc() != 3)
5468 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5471 origin[0] += atof(Cmd_Argv(2));
5473 else if (!strcmp(Cmd_Argv(1), "movey"))
5475 if (Cmd_Argc() != 3)
5477 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5480 origin[1] += atof(Cmd_Argv(2));
5482 else if (!strcmp(Cmd_Argv(1), "movez"))
5484 if (Cmd_Argc() != 3)
5486 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5489 origin[2] += atof(Cmd_Argv(2));
5491 else if (!strcmp(Cmd_Argv(1), "angles"))
5493 if (Cmd_Argc() != 5)
5495 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5498 angles[0] = atof(Cmd_Argv(2));
5499 angles[1] = atof(Cmd_Argv(3));
5500 angles[2] = atof(Cmd_Argv(4));
5502 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5504 if (Cmd_Argc() != 3)
5506 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5509 angles[0] = atof(Cmd_Argv(2));
5511 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5513 if (Cmd_Argc() != 3)
5515 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5518 angles[1] = atof(Cmd_Argv(2));
5520 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5522 if (Cmd_Argc() != 3)
5524 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5527 angles[2] = atof(Cmd_Argv(2));
5529 else if (!strcmp(Cmd_Argv(1), "color"))
5531 if (Cmd_Argc() != 5)
5533 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5536 color[0] = atof(Cmd_Argv(2));
5537 color[1] = atof(Cmd_Argv(3));
5538 color[2] = atof(Cmd_Argv(4));
5540 else if (!strcmp(Cmd_Argv(1), "radius"))
5542 if (Cmd_Argc() != 3)
5544 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5547 radius = atof(Cmd_Argv(2));
5549 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5551 if (Cmd_Argc() == 3)
5553 double scale = atof(Cmd_Argv(2));
5560 if (Cmd_Argc() != 5)
5562 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5565 color[0] *= atof(Cmd_Argv(2));
5566 color[1] *= atof(Cmd_Argv(3));
5567 color[2] *= atof(Cmd_Argv(4));
5570 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5572 if (Cmd_Argc() != 3)
5574 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5577 radius *= atof(Cmd_Argv(2));
5579 else if (!strcmp(Cmd_Argv(1), "style"))
5581 if (Cmd_Argc() != 3)
5583 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5586 style = atoi(Cmd_Argv(2));
5588 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5592 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5595 if (Cmd_Argc() == 3)
5596 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5600 else if (!strcmp(Cmd_Argv(1), "shadows"))
5602 if (Cmd_Argc() != 3)
5604 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5607 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5609 else if (!strcmp(Cmd_Argv(1), "corona"))
5611 if (Cmd_Argc() != 3)
5613 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5616 corona = atof(Cmd_Argv(2));
5618 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5620 if (Cmd_Argc() != 3)
5622 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5625 coronasizescale = atof(Cmd_Argv(2));
5627 else if (!strcmp(Cmd_Argv(1), "ambient"))
5629 if (Cmd_Argc() != 3)
5631 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5634 ambientscale = atof(Cmd_Argv(2));
5636 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5638 if (Cmd_Argc() != 3)
5640 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5643 diffusescale = atof(Cmd_Argv(2));
5645 else if (!strcmp(Cmd_Argv(1), "specular"))
5647 if (Cmd_Argc() != 3)
5649 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5652 specularscale = atof(Cmd_Argv(2));
5654 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5656 if (Cmd_Argc() != 3)
5658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5661 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5663 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5665 if (Cmd_Argc() != 3)
5667 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5670 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5674 Con_Print("usage: r_editlights_edit [property] [value]\n");
5675 Con_Print("Selected light's properties:\n");
5676 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5677 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5678 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5679 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5680 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5681 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5682 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5683 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5684 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5685 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5686 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5687 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5688 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5689 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5692 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5693 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5696 static void R_Shadow_EditLights_EditAll_f(void)
5699 dlight_t *light, *oldselected;
5702 if (!r_editlights.integer)
5704 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5708 oldselected = r_shadow_selectedlight;
5709 // EditLights doesn't seem to have a "remove" command or something so:
5710 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5711 for (lightindex = 0;lightindex < range;lightindex++)
5713 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5716 R_Shadow_SelectLight(light);
5717 R_Shadow_EditLights_Edit_f();
5719 // return to old selected (to not mess editing once selection is locked)
5720 R_Shadow_SelectLight(oldselected);
5723 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5725 int lightnumber, lightcount;
5726 size_t lightindex, range;
5731 if (!r_editlights.integer)
5734 // update cvars so QC can query them
5735 if (r_shadow_selectedlight)
5737 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5738 Cvar_SetQuick(&r_editlights_current_origin, temp);
5739 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5740 Cvar_SetQuick(&r_editlights_current_angles, temp);
5741 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5742 Cvar_SetQuick(&r_editlights_current_color, temp);
5743 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5744 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5745 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5746 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5747 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5748 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5749 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5750 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5751 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5752 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5753 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5756 // draw properties on screen
5757 if (!r_editlights_drawproperties.integer)
5759 x = vid_conwidth.value - 320;
5761 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5764 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5765 for (lightindex = 0;lightindex < range;lightindex++)
5767 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5770 if (light == r_shadow_selectedlight)
5771 lightnumber = (int)lightindex;
5774 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;
5775 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;
5777 if (r_shadow_selectedlight == NULL)
5779 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;
5780 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;
5781 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;
5782 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;
5783 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;
5784 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;
5785 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;
5786 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;
5787 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;
5788 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;
5789 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;
5790 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;
5791 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;
5792 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;
5793 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;
5795 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;
5796 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;
5797 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;
5798 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;
5799 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;
5800 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;
5801 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;
5802 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;
5803 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;
5804 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;
5807 static void R_Shadow_EditLights_ToggleShadow_f(void)
5809 if (!r_editlights.integer)
5811 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5814 if (!r_shadow_selectedlight)
5816 Con_Print("No selected light.\n");
5819 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);
5822 static void R_Shadow_EditLights_ToggleCorona_f(void)
5824 if (!r_editlights.integer)
5826 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5829 if (!r_shadow_selectedlight)
5831 Con_Print("No selected light.\n");
5834 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);
5837 static void R_Shadow_EditLights_Remove_f(void)
5839 if (!r_editlights.integer)
5841 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5844 if (!r_shadow_selectedlight)
5846 Con_Print("No selected light.\n");
5849 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5850 r_shadow_selectedlight = NULL;
5853 static void R_Shadow_EditLights_Help_f(void)
5856 "Documentation on r_editlights system:\n"
5858 "r_editlights : enable/disable editing mode\n"
5859 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5860 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5861 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5862 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5863 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5865 "r_editlights_help : this help\n"
5866 "r_editlights_clear : remove all lights\n"
5867 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5868 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5869 "r_editlights_save : save to .rtlights file\n"
5870 "r_editlights_spawn : create a light with default settings\n"
5871 "r_editlights_edit command : edit selected light - more documentation below\n"
5872 "r_editlights_remove : remove selected light\n"
5873 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5874 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5875 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5877 "origin x y z : set light location\n"
5878 "originx x: set x component of light location\n"
5879 "originy y: set y component of light location\n"
5880 "originz z: set z component of light location\n"
5881 "move x y z : adjust light location\n"
5882 "movex x: adjust x component of light location\n"
5883 "movey y: adjust y component of light location\n"
5884 "movez z: adjust z component of light location\n"
5885 "angles x y z : set light angles\n"
5886 "anglesx x: set x component of light angles\n"
5887 "anglesy y: set y component of light angles\n"
5888 "anglesz z: set z component of light angles\n"
5889 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5890 "radius radius : set radius (size) of light\n"
5891 "colorscale grey : multiply color of light (1 does nothing)\n"
5892 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5893 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5894 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5895 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5896 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5897 "cubemap basename : set filter cubemap of light\n"
5898 "shadows 1/0 : turn on/off shadows\n"
5899 "corona n : set corona intensity\n"
5900 "coronasize n : set corona size (0-1)\n"
5901 "ambient n : set ambient intensity (0-1)\n"
5902 "diffuse n : set diffuse intensity (0-1)\n"
5903 "specular n : set specular intensity (0-1)\n"
5904 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5905 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5906 "<nothing> : print light properties to console\n"
5910 static void R_Shadow_EditLights_CopyInfo_f(void)
5912 if (!r_editlights.integer)
5914 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5917 if (!r_shadow_selectedlight)
5919 Con_Print("No selected light.\n");
5922 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5923 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5924 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5925 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5926 if (r_shadow_selectedlight->cubemapname)
5927 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5929 r_shadow_bufferlight.cubemapname[0] = 0;
5930 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5931 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5932 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5933 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5934 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5935 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5936 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5939 static void R_Shadow_EditLights_PasteInfo_f(void)
5941 if (!r_editlights.integer)
5943 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5946 if (!r_shadow_selectedlight)
5948 Con_Print("No selected light.\n");
5951 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);
5954 static void R_Shadow_EditLights_Lock_f(void)
5956 if (!r_editlights.integer)
5958 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5961 if (r_editlights_lockcursor)
5963 r_editlights_lockcursor = false;
5966 if (!r_shadow_selectedlight)
5968 Con_Print("No selected light to lock on.\n");
5971 r_editlights_lockcursor = true;
5974 static void R_Shadow_EditLights_Init(void)
5976 Cvar_RegisterVariable(&r_editlights);
5977 Cvar_RegisterVariable(&r_editlights_cursordistance);
5978 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5979 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5980 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5981 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5982 Cvar_RegisterVariable(&r_editlights_drawproperties);
5983 Cvar_RegisterVariable(&r_editlights_current_origin);
5984 Cvar_RegisterVariable(&r_editlights_current_angles);
5985 Cvar_RegisterVariable(&r_editlights_current_color);
5986 Cvar_RegisterVariable(&r_editlights_current_radius);
5987 Cvar_RegisterVariable(&r_editlights_current_corona);
5988 Cvar_RegisterVariable(&r_editlights_current_coronasize);
5989 Cvar_RegisterVariable(&r_editlights_current_style);
5990 Cvar_RegisterVariable(&r_editlights_current_shadows);
5991 Cvar_RegisterVariable(&r_editlights_current_cubemap);
5992 Cvar_RegisterVariable(&r_editlights_current_ambient);
5993 Cvar_RegisterVariable(&r_editlights_current_diffuse);
5994 Cvar_RegisterVariable(&r_editlights_current_specular);
5995 Cvar_RegisterVariable(&r_editlights_current_normalmode);
5996 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
5997 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5998 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5999 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
6000 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6001 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6002 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6003 Cmd_AddCommand("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)");
6004 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6005 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6006 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6007 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6008 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6009 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6010 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
6011 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6017 =============================================================================
6021 =============================================================================
6024 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6026 int i, numlights, flag, q;
6029 float relativepoint[3];
6034 float sa[3], sx[3], sy[3], sz[3], sd[3];
6037 // use first order spherical harmonics to combine directional lights
6038 for (q = 0; q < 3; q++)
6039 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6041 if (flags & LP_LIGHTMAP)
6043 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6045 float tempambient[3];
6046 for (q = 0; q < 3; q++)
6047 tempambient[q] = color[q] = relativepoint[q] = 0;
6048 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6049 // calculate a weighted average light direction as well
6050 intensity = VectorLength(color);
6051 for (q = 0; q < 3; q++)
6053 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6054 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6055 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6056 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6057 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6062 // unlit map - fullbright but scaled by lightmapintensity
6063 for (q = 0; q < 3; q++)
6064 sa[q] += lightmapintensity;
6068 if (flags & LP_RTWORLD)
6070 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6071 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6072 for (i = 0; i < numlights; i++)
6074 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6077 light = &dlight->rtlight;
6078 if (!(light->flags & flag))
6081 lightradius2 = light->radius * light->radius;
6082 VectorSubtract(light->shadoworigin, p, relativepoint);
6083 dist2 = VectorLength2(relativepoint);
6084 if (dist2 >= lightradius2)
6086 dist = sqrt(dist2) / light->radius;
6087 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6088 if (intensity <= 0.0f)
6090 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)
6092 for (q = 0; q < 3; q++)
6093 color[q] = light->currentcolor[q] * intensity;
6094 intensity = VectorLength(color);
6095 VectorNormalize(relativepoint);
6096 for (q = 0; q < 3; q++)
6098 sa[q] += 0.5f * color[q];
6099 sx[q] += relativepoint[0] * color[q];
6100 sy[q] += relativepoint[1] * color[q];
6101 sz[q] += relativepoint[2] * color[q];
6102 sd[q] += intensity * relativepoint[q];
6105 // FIXME: sample bouncegrid too!
6108 if (flags & LP_DYNLIGHT)
6111 for (i = 0;i < r_refdef.scene.numlights;i++)
6113 light = r_refdef.scene.lights[i];
6115 lightradius2 = light->radius * light->radius;
6116 VectorSubtract(light->shadoworigin, p, relativepoint);
6117 dist2 = VectorLength2(relativepoint);
6118 if (dist2 >= lightradius2)
6120 dist = sqrt(dist2) / light->radius;
6121 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6122 if (intensity <= 0.0f)
6124 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)
6126 for (q = 0; q < 3; q++)
6127 color[q] = light->currentcolor[q] * intensity;
6128 intensity = VectorLength(color);
6129 VectorNormalize(relativepoint);
6130 for (q = 0; q < 3; q++)
6132 sa[q] += 0.5f * color[q];
6133 sx[q] += relativepoint[0] * color[q];
6134 sy[q] += relativepoint[1] * color[q];
6135 sz[q] += relativepoint[2] * color[q];
6136 sd[q] += intensity * relativepoint[q];
6141 // calculate the weighted-average light direction (bentnormal)
6142 for (q = 0; q < 3; q++)
6143 lightdir[q] = sd[q];
6144 VectorNormalize(lightdir);
6145 for (q = 0; q < 3; q++)
6147 // extract the diffuse color along the chosen direction and scale it
6148 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6149 // subtract some of diffuse from ambient
6150 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;