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", "1", "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", "5", "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", "5", "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", "1", "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", "5", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
227 cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_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; }
572 r_shadow_bouncegrid_state.maxsplatpaths = 0;
574 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
575 if (r_shadow_lightcorona) { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
576 if (r_editlights_sprcursor) { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
577 if (r_editlights_sprlight) { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
578 if (r_editlights_sprnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
579 if (r_editlights_sprcubemaplight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
580 if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
581 if (r_editlights_sprselection) { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
582 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
583 R_Shadow_EditLights_Reload_f();
586 void R_Shadow_Init(void)
588 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
589 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
590 Cvar_RegisterVariable(&r_shadow_usebihculling);
591 Cvar_RegisterVariable(&r_shadow_usenormalmap);
592 Cvar_RegisterVariable(&r_shadow_debuglight);
593 Cvar_RegisterVariable(&r_shadow_deferred);
594 Cvar_RegisterVariable(&r_shadow_gloss);
595 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
596 Cvar_RegisterVariable(&r_shadow_glossintensity);
597 Cvar_RegisterVariable(&r_shadow_glossexponent);
598 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
599 Cvar_RegisterVariable(&r_shadow_glossexact);
600 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
601 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
602 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
603 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
604 Cvar_RegisterVariable(&r_shadow_projectdistance);
605 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
606 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
607 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
608 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
609 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
610 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
611 Cvar_RegisterVariable(&r_shadow_realtime_world);
612 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
613 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
614 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
615 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
616 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
617 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
618 Cvar_RegisterVariable(&r_shadow_scissor);
619 Cvar_RegisterVariable(&r_shadow_shadowmapping);
620 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
621 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
622 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
623 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
624 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
625 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
626 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
627 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
628 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
629 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
630 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
631 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
632 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
633 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
634 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
635 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
636 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
637 Cvar_RegisterVariable(&r_shadow_culllights_trace);
638 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
639 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
640 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
641 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
642 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
643 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
644 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
645 Cvar_RegisterVariable(&r_shadow_bouncegrid);
646 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
647 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
648 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
649 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
650 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
651 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
652 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
653 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
654 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
655 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
656 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
657 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
658 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
659 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
660 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
661 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
662 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
663 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
664 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
665 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
666 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
667 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
668 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
669 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
670 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
671 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
672 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
673 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
674 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
675 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
676 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
677 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
678 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
679 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
680 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
681 Cvar_RegisterVariable(&r_coronas);
682 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
683 Cvar_RegisterVariable(&r_coronas_occlusionquery);
684 Cvar_RegisterVariable(&gl_flashblend);
685 R_Shadow_EditLights_Init();
686 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
687 r_shadow_scenemaxlights = 0;
688 r_shadow_scenenumlights = 0;
689 r_shadow_scenelightlist = NULL;
690 maxshadowtriangles = 0;
691 shadowelements = NULL;
692 maxshadowvertices = 0;
693 shadowvertex3f = NULL;
701 shadowmarklist = NULL;
706 shadowsideslist = NULL;
707 r_shadow_buffer_numleafpvsbytes = 0;
708 r_shadow_buffer_visitingleafpvs = NULL;
709 r_shadow_buffer_leafpvs = NULL;
710 r_shadow_buffer_leaflist = NULL;
711 r_shadow_buffer_numsurfacepvsbytes = 0;
712 r_shadow_buffer_surfacepvs = NULL;
713 r_shadow_buffer_surfacelist = NULL;
714 r_shadow_buffer_surfacesides = NULL;
715 r_shadow_buffer_shadowtrispvs = NULL;
716 r_shadow_buffer_lighttrispvs = NULL;
717 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
720 matrix4x4_t matrix_attenuationxyz =
723 {0.5, 0.0, 0.0, 0.5},
724 {0.0, 0.5, 0.0, 0.5},
725 {0.0, 0.0, 0.5, 0.5},
730 matrix4x4_t matrix_attenuationz =
733 {0.0, 0.0, 0.5, 0.5},
734 {0.0, 0.0, 0.0, 0.5},
735 {0.0, 0.0, 0.0, 0.5},
740 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
742 numvertices = ((numvertices + 255) & ~255) * vertscale;
743 numtriangles = ((numtriangles + 255) & ~255) * triscale;
744 // make sure shadowelements is big enough for this volume
745 if (maxshadowtriangles < numtriangles)
747 maxshadowtriangles = numtriangles;
749 Mem_Free(shadowelements);
750 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
752 // make sure shadowvertex3f is big enough for this volume
753 if (maxshadowvertices < numvertices)
755 maxshadowvertices = numvertices;
757 Mem_Free(shadowvertex3f);
758 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
762 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
764 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
765 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
766 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
767 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
768 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
770 if (r_shadow_buffer_visitingleafpvs)
771 Mem_Free(r_shadow_buffer_visitingleafpvs);
772 if (r_shadow_buffer_leafpvs)
773 Mem_Free(r_shadow_buffer_leafpvs);
774 if (r_shadow_buffer_leaflist)
775 Mem_Free(r_shadow_buffer_leaflist);
776 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
777 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
778 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
779 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
781 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
783 if (r_shadow_buffer_surfacepvs)
784 Mem_Free(r_shadow_buffer_surfacepvs);
785 if (r_shadow_buffer_surfacelist)
786 Mem_Free(r_shadow_buffer_surfacelist);
787 if (r_shadow_buffer_surfacesides)
788 Mem_Free(r_shadow_buffer_surfacesides);
789 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
790 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
791 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
792 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
794 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
796 if (r_shadow_buffer_shadowtrispvs)
797 Mem_Free(r_shadow_buffer_shadowtrispvs);
798 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
799 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
801 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
803 if (r_shadow_buffer_lighttrispvs)
804 Mem_Free(r_shadow_buffer_lighttrispvs);
805 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
806 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
810 void R_Shadow_PrepareShadowMark(int numtris)
812 // make sure shadowmark is big enough for this volume
813 if (maxshadowmark < numtris)
815 maxshadowmark = numtris;
817 Mem_Free(shadowmark);
819 Mem_Free(shadowmarklist);
820 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
821 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
825 // if shadowmarkcount wrapped we clear the array and adjust accordingly
826 if (shadowmarkcount == 0)
829 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
834 void R_Shadow_PrepareShadowSides(int numtris)
836 if (maxshadowsides < numtris)
838 maxshadowsides = numtris;
840 Mem_Free(shadowsides);
842 Mem_Free(shadowsideslist);
843 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
844 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
849 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
851 // p1, p2, p3 are in the cubemap's local coordinate system
852 // bias = border/(size - border)
855 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
856 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
857 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
858 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
860 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
861 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
862 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
863 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
865 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
866 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
867 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
869 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
870 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
871 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
872 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
874 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
875 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
876 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
877 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
879 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
880 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
881 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
883 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
884 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
885 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
886 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
888 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
889 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
890 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
891 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
893 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
894 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
895 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
900 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
902 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
903 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
906 VectorSubtract(maxs, mins, radius);
907 VectorScale(radius, 0.5f, radius);
908 VectorAdd(mins, radius, center);
909 Matrix4x4_Transform(worldtolight, center, lightcenter);
910 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
911 VectorSubtract(lightcenter, lightradius, pmin);
912 VectorAdd(lightcenter, lightradius, pmax);
914 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
915 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
916 if(ap1 > bias*an1 && ap2 > bias*an2)
918 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
919 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
920 if(an1 > bias*ap1 && an2 > bias*ap2)
922 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
923 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
925 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
926 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
927 if(ap1 > bias*an1 && ap2 > bias*an2)
929 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
930 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
931 if(an1 > bias*ap1 && an2 > bias*ap2)
933 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
934 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
936 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
937 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
938 if(ap1 > bias*an1 && ap2 > bias*an2)
940 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
941 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
942 if(an1 > bias*ap1 && an2 > bias*ap2)
944 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
945 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
950 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
952 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
954 // p is in the cubemap's local coordinate system
955 // bias = border/(size - border)
956 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
957 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
958 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
960 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
961 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
962 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
963 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
964 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
965 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
969 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
973 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
974 float scale = (size - 2*border)/size, len;
975 float bias = border / (float)(size - border), dp, dn, ap, an;
976 // check if cone enclosing side would cross frustum plane
977 scale = 2 / (scale*scale + 2);
978 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
979 for (i = 0;i < 5;i++)
981 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
983 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
984 len = scale*VectorLength2(n);
985 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
986 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
987 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
989 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
991 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
992 len = scale*VectorLength2(n);
993 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
994 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
995 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
997 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
998 // check if frustum corners/origin cross plane sides
1000 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1001 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1002 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1003 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1004 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1005 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1006 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1007 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1008 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1009 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1010 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1011 for (i = 0;i < 4;i++)
1013 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1014 VectorSubtract(n, p, n);
1015 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1016 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1017 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1018 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1019 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1020 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1021 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1022 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1023 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1026 // finite version, assumes corners are a finite distance from origin dependent on far plane
1027 for (i = 0;i < 5;i++)
1029 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1030 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1031 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1032 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1033 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1034 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1035 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1036 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1037 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1038 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1041 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1044 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)
1052 int mask, surfacemask = 0;
1053 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1055 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1056 tend = firsttriangle + numtris;
1057 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1059 // surface box entirely inside light box, no box cull
1060 if (projectdirection)
1062 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1064 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1065 TriangleNormal(v[0], v[1], v[2], normal);
1066 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1068 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1069 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1070 surfacemask |= mask;
1073 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;
1074 shadowsides[numshadowsides] = mask;
1075 shadowsideslist[numshadowsides++] = t;
1082 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1084 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1085 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1087 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1088 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1089 surfacemask |= mask;
1092 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;
1093 shadowsides[numshadowsides] = mask;
1094 shadowsideslist[numshadowsides++] = t;
1102 // surface box not entirely inside light box, cull each triangle
1103 if (projectdirection)
1105 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1107 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1108 TriangleNormal(v[0], v[1], v[2], normal);
1109 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1110 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1112 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1113 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1114 surfacemask |= mask;
1117 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;
1118 shadowsides[numshadowsides] = mask;
1119 shadowsideslist[numshadowsides++] = t;
1126 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1128 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1129 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1130 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1132 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1133 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1134 surfacemask |= mask;
1137 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;
1138 shadowsides[numshadowsides] = mask;
1139 shadowsideslist[numshadowsides++] = t;
1148 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)
1150 int i, j, outtriangles = 0;
1151 int *outelement3i[6];
1152 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1154 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1155 // make sure shadowelements is big enough for this mesh
1156 if (maxshadowtriangles < outtriangles)
1157 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1159 // compute the offset and size of the separate index lists for each cubemap side
1161 for (i = 0;i < 6;i++)
1163 outelement3i[i] = shadowelements + outtriangles * 3;
1164 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1165 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1166 outtriangles += sidetotals[i];
1169 // gather up the (sparse) triangles into separate index lists for each cubemap side
1170 for (i = 0;i < numsidetris;i++)
1172 const int *element = elements + sidetris[i] * 3;
1173 for (j = 0;j < 6;j++)
1175 if (sides[i] & (1 << j))
1177 outelement3i[j][0] = element[0];
1178 outelement3i[j][1] = element[1];
1179 outelement3i[j][2] = element[2];
1180 outelement3i[j] += 3;
1185 Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1188 static void R_Shadow_MakeTextures_MakeCorona(void)
1192 unsigned char pixels[32][32][4];
1193 for (y = 0;y < 32;y++)
1195 dy = (y - 15.5f) * (1.0f / 16.0f);
1196 for (x = 0;x < 32;x++)
1198 dx = (x - 15.5f) * (1.0f / 16.0f);
1199 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1200 a = bound(0, a, 255);
1201 pixels[y][x][0] = a;
1202 pixels[y][x][1] = a;
1203 pixels[y][x][2] = a;
1204 pixels[y][x][3] = 255;
1207 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1210 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1212 float dist = sqrt(x*x+y*y+z*z);
1213 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1214 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1215 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1218 static void R_Shadow_MakeTextures(void)
1221 float intensity, dist;
1223 R_Shadow_FreeShadowMaps();
1224 R_FreeTexturePool(&r_shadow_texturepool);
1225 r_shadow_texturepool = R_AllocTexturePool();
1226 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1227 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1228 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1229 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1230 for (x = 0;x <= ATTENTABLESIZE;x++)
1232 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1233 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1234 r_shadow_attentable[x] = bound(0, intensity, 1);
1236 // 1D gradient texture
1237 for (x = 0;x < ATTEN1DSIZE;x++)
1238 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1239 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1242 R_Shadow_MakeTextures_MakeCorona();
1244 // Editor light sprites
1245 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1262 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1263 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1280 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1281 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1298 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1299 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1316 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1317 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1334 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1335 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1352 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1355 void R_Shadow_RenderMode_Begin(void)
1362 if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1363 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1364 R_Shadow_MakeTextures();
1367 R_Mesh_ResetTextureState();
1368 GL_BlendFunc(GL_ONE, GL_ZERO);
1369 GL_DepthRange(0, 1);
1370 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1372 GL_DepthMask(false);
1373 GL_Color(0, 0, 0, 1);
1374 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1376 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1377 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1381 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1382 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1383 r_shadow_drawbuffer = drawbuffer;
1384 r_shadow_readbuffer = readbuffer;
1386 r_shadow_cullface_front = r_refdef.view.cullface_front;
1387 r_shadow_cullface_back = r_refdef.view.cullface_back;
1390 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1392 rsurface.rtlight = rtlight;
1395 void R_Shadow_RenderMode_Reset(void)
1397 R_Mesh_ResetTextureState();
1398 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1399 R_SetViewport(&r_refdef.view.viewport);
1400 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1401 GL_DepthRange(0, 1);
1403 GL_DepthMask(false);
1404 GL_DepthFunc(GL_LEQUAL);
1405 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1406 r_refdef.view.cullface_front = r_shadow_cullface_front;
1407 r_refdef.view.cullface_back = r_shadow_cullface_back;
1408 GL_CullFace(r_refdef.view.cullface_back);
1409 GL_Color(1, 1, 1, 1);
1410 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1411 GL_BlendFunc(GL_ONE, GL_ZERO);
1412 R_SetupShader_Generic_NoTexture(false, false);
1413 r_shadow_usingshadowmap2d = false;
1416 void R_Shadow_ClearStencil(void)
1418 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1419 r_refdef.stats[r_stat_lights_clears]++;
1422 static void R_Shadow_MakeVSDCT(void)
1424 // maps to a 2x3 texture rectangle with normalized coordinates
1429 // stores abs(dir.xy), offset.xy/2.5
1430 unsigned char data[4*6] =
1432 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1433 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1434 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1435 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1436 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1437 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1439 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1442 static void R_Shadow_MakeShadowMap(int texturesize)
1444 switch (r_shadow_shadowmode)
1446 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1447 if (r_shadow_shadowmap2ddepthtexture) return;
1448 if (r_fb.usedepthtextures)
1450 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);
1451 r_shadow_shadowmap2ddepthbuffer = NULL;
1452 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1456 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1457 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1458 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1466 void R_Shadow_ClearShadowMapTexture(void)
1468 r_viewport_t viewport;
1469 float clearcolor[4];
1471 // if they don't exist, create our textures now
1472 if (!r_shadow_shadowmap2ddepthtexture)
1473 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1474 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1475 R_Shadow_MakeVSDCT();
1477 // we're setting up to render shadowmaps, so change rendermode
1478 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1480 R_Mesh_ResetTextureState();
1481 R_Shadow_RenderMode_Reset();
1482 if (r_shadow_shadowmap2ddepthbuffer)
1483 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1485 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1486 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1487 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1491 // we have to set a viewport to clear anything in some renderpaths (D3D)
1492 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1493 R_SetViewport(&viewport);
1494 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1495 if (r_shadow_shadowmap2ddepthbuffer)
1496 GL_ColorMask(1, 1, 1, 1);
1498 GL_ColorMask(0, 0, 0, 0);
1499 switch (vid.renderpath)
1501 case RENDERPATH_GL32:
1502 case RENDERPATH_GLES2:
1503 GL_CullFace(r_refdef.view.cullface_back);
1506 Vector4Set(clearcolor, 1, 1, 1, 1);
1507 if (r_shadow_shadowmap2ddepthbuffer)
1508 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1510 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1513 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1515 int size = rsurface.rtlight->shadowmapatlassidesize;
1516 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1517 float farclip = 1.0f;
1518 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1519 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1520 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1521 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1522 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1523 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1524 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1525 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1526 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1527 if (r_shadow_shadowmap2ddepthbuffer)
1529 // completely different meaning than in depthtexture approach
1530 r_shadow_lightshadowmap_parameters[1] = 0;
1531 r_shadow_lightshadowmap_parameters[3] = -bias;
1535 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1537 float nearclip, farclip, bias;
1538 r_viewport_t viewport;
1540 float clearcolor[4];
1542 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1544 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1546 R_Mesh_ResetTextureState();
1547 R_Shadow_RenderMode_Reset();
1548 if (r_shadow_shadowmap2ddepthbuffer)
1549 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1551 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1552 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1553 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1558 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1560 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1562 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1563 R_SetViewport(&viewport);
1564 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1565 flipped = (side & 1) ^ (side >> 2);
1566 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1567 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1569 Vector4Set(clearcolor, 1,1,1,1);
1570 if (r_shadow_shadowmap2ddepthbuffer)
1571 GL_ColorMask(1,1,1,1);
1573 GL_ColorMask(0,0,0,0);
1574 switch(vid.renderpath)
1576 case RENDERPATH_GL32:
1577 case RENDERPATH_GLES2:
1578 GL_CullFace(r_refdef.view.cullface_back);
1582 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1583 r_shadow_shadowmapside = side;
1586 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1588 R_Mesh_ResetTextureState();
1591 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1592 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1593 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1594 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1597 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1598 R_Shadow_RenderMode_Reset();
1599 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1601 GL_DepthFunc(GL_EQUAL);
1602 // do global setup needed for the chosen lighting mode
1603 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1604 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1605 r_shadow_usingshadowmap2d = shadowmapping;
1606 r_shadow_rendermode = r_shadow_lightingrendermode;
1609 static const unsigned short bboxelements[36] =
1619 static const float bboxpoints[8][3] =
1631 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1634 float vertex3f[8*3];
1635 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1636 // do global setup needed for the chosen lighting mode
1637 R_Shadow_RenderMode_Reset();
1638 r_shadow_rendermode = r_shadow_lightingrendermode;
1639 R_EntityMatrix(&identitymatrix);
1640 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1641 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1642 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1644 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1646 r_shadow_usingshadowmap2d = shadowmapping;
1648 // render the lighting
1649 R_SetupShader_DeferredLight(rsurface.rtlight);
1650 for (i = 0;i < 8;i++)
1651 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1652 GL_ColorMask(1,1,1,1);
1653 GL_DepthMask(false);
1654 GL_DepthRange(0, 1);
1655 GL_PolygonOffset(0, 0);
1657 GL_DepthFunc(GL_GREATER);
1658 GL_CullFace(r_refdef.view.cullface_back);
1659 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1660 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1663 #define MAXBOUNCEGRIDSPLATSIZE 7
1664 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
1666 // these are temporary data per-frame, sorted and performed in a more
1667 // cache-friendly order than the original photons
1668 typedef struct r_shadow_bouncegrid_splatpath_s
1674 vec_t splatintensity;
1675 vec_t splatsize_current;
1676 vec_t splatsize_perstep;
1677 int remainingsplats;
1679 r_shadow_bouncegrid_splatpath_t;
1681 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
1691 r_shadow_bouncegrid_splatpath_t *path;
1693 // cull paths that fail R_CullBox in dynamic mode
1694 if (!r_shadow_bouncegrid_state.settings.staticmode
1695 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
1697 vec3_t cullmins, cullmaxs;
1698 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
1699 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
1700 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
1701 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
1702 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
1703 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
1704 if (R_CullBox(cullmins, cullmaxs))
1708 // if the light path is going upward, reverse it - we always draw down.
1709 if (originalend[2] < originalstart[2])
1711 VectorCopy(originalend, start);
1712 VectorCopy(originalstart, end);
1716 VectorCopy(originalstart, start);
1717 VectorCopy(originalend, end);
1720 // transform to texture pixels
1721 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1722 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1723 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1724 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1725 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1726 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1728 // check if we need to grow the splatpaths array
1729 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
1731 // double the limit, this will persist from frame to frame so we don't
1732 // make the same mistake each time
1733 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
1734 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
1735 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
1736 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);
1739 // divide a series of splats along the length using the maximum axis
1740 VectorSubtract(end, start, diff);
1741 // pick the best axis to trace along
1743 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
1745 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
1747 len = fabs(diff[bestaxis]);
1749 numsplats = (int)(floor(len + 0.5f));
1751 numsplats = bound(0, numsplats, 1024);
1753 VectorSubtract(originalstart, originalend, originaldir);
1754 VectorNormalize(originaldir);
1756 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
1757 VectorCopy(start, path->point);
1758 VectorScale(diff, ilen, path->step);
1759 VectorCopy(color, path->splatcolor);
1760 VectorCopy(originaldir, path->splatdir);
1761 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
1762 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
1763 path->splatintensity = VectorLength(color);
1764 path->remainingsplats = numsplats;
1767 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1769 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1776 // see if there are really any lights to render...
1777 if (enable && r_shadow_bouncegrid_static.integer)
1780 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1781 for (lightindex = 0;lightindex < range;lightindex++)
1783 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1784 if (!light || !(light->flags & flag))
1786 rtlight = &light->rtlight;
1787 // when static, we skip styled lights because they tend to change...
1788 if (rtlight->style > 0)
1790 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1791 if (!VectorLength2(lightcolor))
1801 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1803 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1804 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1805 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1806 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1808 // prevent any garbage in alignment padded areas as we'll be using memcmp
1809 memset(settings, 0, sizeof(*settings));
1811 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1812 settings->staticmode = s;
1813 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1814 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1815 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
1816 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
1817 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
1818 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1819 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1820 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1821 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1822 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1823 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1824 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1825 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
1826 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1827 settings->energyperphoton = spacing * spacing / quality;
1828 settings->spacing[0] = spacing;
1829 settings->spacing[1] = spacing;
1830 settings->spacing[2] = spacing;
1831 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1832 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1833 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1834 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1835 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1837 // bound the values for sanity
1838 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1839 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1840 settings->maxbounce = bound(0, settings->maxbounce, 16);
1841 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1842 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1843 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1846 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1857 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1859 // get the spacing values
1860 spacing[0] = settings->spacing[0];
1861 spacing[1] = settings->spacing[1];
1862 spacing[2] = settings->spacing[2];
1863 ispacing[0] = 1.0f / spacing[0];
1864 ispacing[1] = 1.0f / spacing[1];
1865 ispacing[2] = 1.0f / spacing[2];
1867 // calculate texture size enclosing entire world bounds at the spacing
1868 if (r_refdef.scene.worldmodel)
1872 qboolean bounds_set = false;
1876 // calculate bounds enclosing world lights as they should be noticably tighter
1877 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1878 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1879 for (lightindex = 0;lightindex < range;lightindex++)
1881 const vec_t *rtlmins, *rtlmaxs;
1883 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1887 rtlight = &light->rtlight;
1888 rtlmins = rtlight->cullmins;
1889 rtlmaxs = rtlight->cullmaxs;
1893 VectorCopy(rtlmins, mins);
1894 VectorCopy(rtlmaxs, maxs);
1899 mins[0] = min(mins[0], rtlmins[0]);
1900 mins[1] = min(mins[1], rtlmins[1]);
1901 mins[2] = min(mins[2], rtlmins[2]);
1902 maxs[0] = max(maxs[0], rtlmaxs[0]);
1903 maxs[1] = max(maxs[1], rtlmaxs[1]);
1904 maxs[2] = max(maxs[2], rtlmaxs[2]);
1908 // limit to no larger than the world bounds
1909 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1910 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1911 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1912 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1913 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1914 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1916 VectorMA(mins, -2.0f, spacing, mins);
1917 VectorMA(maxs, 2.0f, spacing, maxs);
1921 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1922 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1924 VectorSubtract(maxs, mins, size);
1925 // now we can calculate the resolution we want
1926 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1927 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1928 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1929 // figure out the exact texture size (honoring power of 2 if required)
1930 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1931 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1932 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1933 size[0] = spacing[0] * resolution[0];
1934 size[1] = spacing[1] * resolution[1];
1935 size[2] = spacing[2] * resolution[2];
1937 // if dynamic we may or may not want to use the world bounds
1938 // if the dynamic size is smaller than the world bounds, use it instead
1939 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]))
1941 // we know the resolution we want
1942 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1943 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1944 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1945 // now we can calculate the texture size
1946 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1947 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1948 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1949 size[0] = spacing[0] * resolution[0];
1950 size[1] = spacing[1] * resolution[1];
1951 size[2] = spacing[2] * resolution[2];
1952 // center the rendering on the view
1953 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1954 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1955 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1958 // recalculate the maxs in case the resolution was not satisfactory
1959 VectorAdd(mins, size, maxs);
1961 // check if this changed the texture size
1962 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);
1963 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1964 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1965 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1966 VectorCopy(size, r_shadow_bouncegrid_state.size);
1967 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1968 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1969 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1971 // reallocate pixels for this update if needed...
1972 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1973 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1974 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1975 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1976 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1978 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1980 r_shadow_bouncegrid_state.highpixels = NULL;
1982 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1983 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1984 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1985 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1986 if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
1988 r_shadow_bouncegrid_state.maxsplatpaths = 0;
1989 r_shadow_bouncegrid_state.numpixels = numpixels;
1992 // update the bouncegrid matrix to put it in the world properly
1993 memset(m, 0, sizeof(m));
1994 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1995 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1996 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1997 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1998 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1999 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2001 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2004 // enumerate world rtlights and sum the overall amount of light in the world,
2005 // from that we can calculate a scaling factor to fairly distribute photons
2006 // to all the lights
2008 // this modifies rtlight->photoncolor and rtlight->photons
2009 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2011 float normalphotonscaling;
2012 float photonscaling;
2013 float photonintensity;
2014 float photoncount = 0.0f;
2015 float lightintensity;
2021 unsigned int lightindex;
2024 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2025 for (lightindex = 0;lightindex < range2;lightindex++)
2027 if (lightindex < range)
2029 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2032 rtlight = &light->rtlight;
2033 VectorClear(rtlight->bouncegrid_photoncolor);
2034 rtlight->bouncegrid_photons = 0;
2035 rtlight->bouncegrid_hits = 0;
2036 rtlight->bouncegrid_traces = 0;
2037 rtlight->bouncegrid_effectiveradius = 0;
2038 if (!(light->flags & flag))
2040 if (settings->staticmode)
2042 // when static, we skip styled lights because they tend to change...
2043 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2046 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2051 rtlight = r_refdef.scene.lights[lightindex - range];
2052 VectorClear(rtlight->bouncegrid_photoncolor);
2053 rtlight->bouncegrid_photons = 0;
2054 rtlight->bouncegrid_hits = 0;
2055 rtlight->bouncegrid_traces = 0;
2056 rtlight->bouncegrid_effectiveradius = 0;
2058 // draw only visible lights (major speedup)
2059 radius = rtlight->radius * settings->lightradiusscale;
2060 cullmins[0] = rtlight->shadoworigin[0] - radius;
2061 cullmins[1] = rtlight->shadoworigin[1] - radius;
2062 cullmins[2] = rtlight->shadoworigin[2] - radius;
2063 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2064 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2065 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2066 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2067 if (!settings->staticmode)
2069 // skip if the expanded light box does not touch any visible leafs
2070 if (r_refdef.scene.worldmodel
2071 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2072 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2074 // skip if the expanded light box is not visible to traceline
2075 // note that PrepareLight already did this check but for a smaller box, so we
2076 // end up casting more traces per frame per light when using bouncegrid, which
2077 // is probably fine (and they use the same timer)
2078 if (r_shadow_culllights_trace.integer)
2080 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))
2081 rtlight->trace_timer = realtime;
2082 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2085 // skip if expanded light box is offscreen
2086 if (R_CullBox(cullmins, cullmaxs))
2088 // skip if overall light intensity is zero
2089 if (w * VectorLength2(rtlight->color) == 0.0f)
2092 // a light that does not emit any light before style is applied, can be
2093 // skipped entirely (it may just be a corona)
2094 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2096 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2097 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2098 // skip lights that will emit no photons
2099 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2101 // shoot particles from this light
2102 // use a calculation for the number of particles that will not
2103 // vary with lightstyle, otherwise we get randomized particle
2104 // distribution, the seeded random is only consistent for a
2105 // consistent number of particles on this light...
2106 s = rtlight->radius;
2107 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2108 if (lightindex >= range)
2109 lightintensity *= settings->dlightparticlemultiplier;
2110 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2111 photoncount += rtlight->bouncegrid_photons;
2112 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2113 // if the lightstyle happens to be off right now, we can skip actually
2114 // firing the photons, but we did have to count them in the total.
2115 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2116 // rtlight->bouncegrid_photons = 0;
2118 // the user provided an energyperphoton value which we try to use
2119 // if that results in too many photons to shoot this frame, then we cap it
2120 // which causes photons to appear/disappear from frame to frame, so we don't
2121 // like doing that in the typical case
2122 photonscaling = 1.0f;
2123 photonintensity = 1.0f;
2124 if (photoncount > settings->maxphotons)
2126 photonscaling = settings->maxphotons / photoncount;
2127 photonintensity = 1.0f / photonscaling;
2130 // modify the lights to reflect our computed scaling
2131 for (lightindex = 0; lightindex < range2; lightindex++)
2133 if (lightindex < range)
2135 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2138 rtlight = &light->rtlight;
2141 rtlight = r_refdef.scene.lights[lightindex - range];
2142 rtlight->bouncegrid_photons *= photonscaling;
2143 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2147 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2149 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2150 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2151 // we only really care about sorting by Z
2152 if (a->point[2] < b->point[2])
2154 if (a->point[2] > b->point[2])
2159 static void R_Shadow_BounceGrid_ClearPixels(void)
2161 // clear the highpixels array we'll be accumulating into
2162 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2163 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2164 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2165 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2166 r_shadow_bouncegrid_state.highpixels_index = 0;
2167 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2168 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2171 static void R_Shadow_BounceGrid_PerformSplats(void)
2173 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2174 r_shadow_bouncegrid_splatpath_t *splatpath;
2175 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2176 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2181 vec_t lightpathsize_current;
2182 vec_t lightpathsize_perstep;
2183 float splatcolor[32];
2185 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2186 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2190 // hush warnings about uninitialized data - pixelbands doesn't change but...
2191 memset(splatcolor, 0, sizeof(splatcolor));
2193 // we use this a lot, so get a local copy
2194 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2196 // sort the splats before we execute them, to reduce cache misses
2197 if (r_shadow_bouncegrid_sortlightpaths.integer)
2198 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2200 splatpath = splatpaths;
2201 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2203 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2204 // accumulate average shotcolor
2205 VectorCopy(splatpath->splatdir, dir);
2206 splatcolor[ 0] = splatpath->splatcolor[0];
2207 splatcolor[ 1] = splatpath->splatcolor[1];
2208 splatcolor[ 2] = splatpath->splatcolor[2];
2209 splatcolor[ 3] = 0.0f;
2212 // store bentnormal in case the shader has a use for it,
2213 // bentnormal is an intensity-weighted average of the directions,
2214 // and will be normalized on conversion to texture pixels.
2215 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2216 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2217 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2218 splatcolor[ 7] = splatpath->splatintensity;
2219 // for each color component (R, G, B) calculate the amount that a
2220 // direction contributes
2221 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2222 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2223 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2224 splatcolor[11] = 0.0f;
2225 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2226 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2227 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2228 splatcolor[15] = 0.0f;
2229 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2230 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2231 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2232 splatcolor[19] = 0.0f;
2233 // and do the same for negative directions
2234 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2235 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2236 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2237 splatcolor[23] = 0.0f;
2238 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2239 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2240 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2241 splatcolor[27] = 0.0f;
2242 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2243 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2244 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2245 splatcolor[31] = 0.0f;
2247 // calculate the number of steps we need to traverse this distance
2248 VectorCopy(splatpath->point, steppos);
2249 VectorCopy(splatpath->step, stepdelta);
2250 numsteps = splatpath->remainingsplats;
2251 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
2252 lightpathsize_perstep = splatpath->splatsize_perstep;
2253 for (step = 0;step < numsteps;step++)
2255 // the middle row/column/layer of each splat are full intensity
2258 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
2259 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
2260 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
2261 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
2262 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
2263 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
2264 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
2265 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
2266 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
2268 // it is within bounds... do the real work now
2269 int xi, yi, zi, band, row;
2273 float colorscale = 1.0f / lightpathsize_current;
2274 r_refdef.stats[r_stat_bouncegrid_splats]++;
2275 // accumulate light onto the pixels
2276 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
2278 pixelpos[2] = zi + 0.5f;
2279 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
2281 pixelpos[1] = yi + 0.5f;
2282 row = (zi*resolution[1] + yi)*resolution[0];
2283 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
2285 pixelpos[0] = xi + 0.5f;
2286 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
2287 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
2293 p = highpixels + 4 * (row + xi);
2294 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
2296 // add to the pixel color
2297 p[0] += splatcolor[band * 4 + 0] * w;
2298 p[1] += splatcolor[band * 4 + 1] * w;
2299 p[2] += splatcolor[band * 4 + 2] * w;
2300 p[3] += splatcolor[band * 4 + 3] * w;
2307 VectorAdd(steppos, stepdelta, steppos);
2308 lightpathsize_current += lightpathsize_perstep;
2313 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2315 const float *inpixel;
2317 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2320 unsigned int x, y, z;
2321 unsigned int resolution[3];
2322 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2323 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2325 for (z = 1;z < resolution[2]-1;z++)
2327 for (y = 1;y < resolution[1]-1;y++)
2330 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2331 inpixel = inpixels + 4*index;
2332 outpixel = outpixels + 4*index;
2333 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2335 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2336 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2337 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2338 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2345 static void R_Shadow_BounceGrid_BlurPixels(void)
2348 unsigned int resolution[3];
2350 if (!r_shadow_bouncegrid_state.settings.blur)
2353 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2355 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2356 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2357 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2358 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2361 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2363 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2365 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2367 // toggle the state, highpixels now points to pixels[3] result
2368 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2369 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2372 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2374 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2375 unsigned char *pixelsbgra8 = NULL;
2376 unsigned char *pixelbgra8;
2377 unsigned short *pixelsrgba16f = NULL;
2378 unsigned short *pixelrgba16f;
2379 float *pixelsrgba32f = NULL;
2380 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2383 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2384 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2385 unsigned int pixelband;
2386 unsigned int x, y, z;
2387 unsigned int index, bandindex;
2388 unsigned int resolution[3];
2390 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2392 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2394 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2395 r_shadow_bouncegrid_state.texture = NULL;
2398 // if bentnormals exist, we need to normalize and bias them for the shader
2402 for (z = 0;z < resolution[2]-1;z++)
2404 for (y = 0;y < resolution[1]-1;y++)
2407 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2408 highpixel = highpixels + 4*index;
2409 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2411 // only convert pixels that were hit by photons
2412 if (highpixel[3] != 0.0f)
2413 VectorNormalize(highpixel);
2414 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2415 highpixel[pixelsperband * 4 + 3] = 1.0f;
2421 // start by clearing the pixels array - we won't be writing to all of it
2423 // then process only the pixels that have at least some color, skipping
2424 // the higher bands for speed on pixels that are black
2425 switch (floatcolors)
2428 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2429 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2430 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2431 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2434 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2436 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2438 for (z = 1;z < resolution[2]-1;z++)
2440 for (y = 1;y < resolution[1]-1;y++)
2444 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2445 highpixel = highpixels + 4*index;
2446 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2448 // only convert pixels that were hit by photons
2449 if (VectorLength2(highpixel))
2451 // normalize the bentnormal now
2454 VectorNormalize(highpixel + pixelsperband * 4);
2455 highpixel[pixelsperband * 4 + 3] = 1.0f;
2457 // process all of the pixelbands for this pixel
2458 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2460 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2461 bandpixel = highpixels + 4*bandindex;
2462 c[0] = (int)(bandpixel[0]*256.0f);
2463 c[1] = (int)(bandpixel[1]*256.0f);
2464 c[2] = (int)(bandpixel[2]*256.0f);
2465 c[3] = (int)(bandpixel[3]*256.0f);
2466 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2467 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2468 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2469 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2476 if (!r_shadow_bouncegrid_state.createtexture)
2477 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2479 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);
2482 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2483 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2484 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2485 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2486 for (z = 1;z < resolution[2]-1;z++)
2488 for (y = 1;y < resolution[1]-1;y++)
2492 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2493 highpixel = highpixels + 4*index;
2494 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2496 // only convert pixels that were hit by photons
2497 if (VectorLength2(highpixel))
2499 // process all of the pixelbands for this pixel
2500 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2502 // time to have fun with IEEE 754 bit hacking...
2505 unsigned int raw[4];
2507 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2508 bandpixel = highpixels + 4*bandindex;
2509 VectorCopy4(bandpixel, u.f);
2510 VectorCopy4(u.raw, c);
2511 // this math supports negative numbers, snaps denormals to zero
2512 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2513 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2514 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2515 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2516 // this math does not support negative
2517 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2518 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2519 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2520 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2527 if (!r_shadow_bouncegrid_state.createtexture)
2528 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2530 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);
2533 // our native format happens to match, so this is easy.
2534 pixelsrgba32f = highpixels;
2536 if (!r_shadow_bouncegrid_state.createtexture)
2537 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2539 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);
2543 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2546 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2548 vec3_t bouncerandom[10];
2551 int hitsupercontentsmask;
2552 int skipsupercontentsmask;
2553 int skipmaterialflagsmask;
2557 float bounceminimumintensity2;
2559 //trace_t cliptrace2;
2560 //trace_t cliptrace3;
2561 unsigned int lightindex;
2563 randomseed_t randomseed;
2565 vec3_t baseshotcolor;
2571 vec_t distancetraveled;
2575 // compute a seed for the unstable random modes
2576 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2577 seed = realtime * 1000.0;
2579 r_shadow_bouncegrid_state.numsplatpaths = 0;
2581 // figure out what we want to interact with
2582 if (settings.hitmodels)
2583 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2585 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2586 skipsupercontentsmask = 0;
2587 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
2588 maxbounce = settings.maxbounce;
2590 for (lightindex = 0;lightindex < range2;lightindex++)
2592 if (lightindex < range)
2594 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2597 rtlight = &light->rtlight;
2600 rtlight = r_refdef.scene.lights[lightindex - range];
2601 // note that this code used to keep track of residual photons and
2602 // distribute them evenly to achieve exactly a desired photon count,
2603 // but that caused unwanted flickering in dynamic mode
2604 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2605 // skip if we won't be shooting any photons
2606 if (!shootparticles)
2608 radius = rtlight->radius * settings.lightradiusscale;
2609 //s = settings.particleintensity / shootparticles;
2610 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2611 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2612 if (VectorLength2(baseshotcolor) <= 0.0f)
2614 r_refdef.stats[r_stat_bouncegrid_lights]++;
2615 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2616 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2617 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
2619 // for seeded random we start the RNG with the position of the light
2620 if (settings.rng_seed >= 0)
2628 u.f[0] = rtlight->shadoworigin[0];
2629 u.f[1] = rtlight->shadoworigin[1];
2630 u.f[2] = rtlight->shadoworigin[2];
2632 switch (settings.rng_type)
2636 // we have to shift the seed provided by the user because the result must be odd
2637 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
2640 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
2645 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2647 VectorCopy(baseshotcolor, shotcolor);
2648 VectorCopy(rtlight->shadoworigin, clipstart);
2649 switch (settings.rng_type)
2653 VectorLehmerRandom(&randomseed, clipend);
2654 if (settings.bounceanglediffuse)
2656 // we want random to be stable, so we still have to do all the random we would have done
2657 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2658 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
2662 VectorCheeseRandom(seed, clipend);
2663 if (settings.bounceanglediffuse)
2665 // we want random to be stable, so we still have to do all the random we would have done
2666 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2667 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
2672 // we want a uniform distribution spherically, not merely within the sphere
2673 if (settings.normalizevectors)
2674 VectorNormalize(clipend);
2676 VectorMA(clipstart, radius, clipend, clipend);
2677 distancetraveled = 0.0f;
2678 for (bouncecount = 0;;bouncecount++)
2680 r_refdef.stats[r_stat_bouncegrid_traces]++;
2681 rtlight->bouncegrid_traces++;
2682 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2683 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2684 if (settings.staticmode || settings.rng_seed < 0)
2686 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2687 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2688 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);
2692 // dynamic mode fires many rays and most will match the cache from the previous frame
2693 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
2695 if (bouncecount > 0 || settings.includedirectlighting)
2698 VectorCopy(cliptrace.endpos, hitpos);
2699 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
2701 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
2702 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
2703 if (rtlight->bouncegrid_effectiveradius < s)
2704 rtlight->bouncegrid_effectiveradius = s;
2705 if (cliptrace.fraction >= 1.0f)
2707 r_refdef.stats[r_stat_bouncegrid_hits]++;
2708 rtlight->bouncegrid_hits++;
2709 if (bouncecount >= maxbounce)
2711 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2712 // also clamp the resulting color to never add energy, even if the user requests extreme values
2713 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2714 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2716 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2717 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2718 surfcolor[0] = min(surfcolor[0], 1.0f);
2719 surfcolor[1] = min(surfcolor[1], 1.0f);
2720 surfcolor[2] = min(surfcolor[2], 1.0f);
2721 VectorMultiply(shotcolor, surfcolor, shotcolor);
2722 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
2724 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2725 if (settings.bounceanglediffuse)
2727 // random direction, primarily along plane normal
2728 s = VectorDistance(cliptrace.endpos, clipend);
2729 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
2730 VectorNormalize(clipend);
2731 VectorScale(clipend, s, clipend);
2735 // reflect the remaining portion of the line across plane normal
2736 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2737 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2739 // calculate the new line start and end
2740 VectorCopy(cliptrace.endpos, clipstart);
2741 VectorAdd(clipstart, clipend, clipend);
2747 void R_Shadow_UpdateBounceGridTexture(void)
2749 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2750 r_shadow_bouncegrid_settings_t settings;
2751 qboolean enable = false;
2752 qboolean settingschanged;
2753 unsigned int range; // number of world lights
2754 unsigned int range1; // number of dynamic lights (or zero if disabled)
2755 unsigned int range2; // range+range1
2757 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2759 R_Shadow_BounceGrid_GenerateSettings(&settings);
2761 // changing intensity does not require an update
2762 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2764 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2766 // when settings change, we free everything as it is just simpler that way.
2767 if (settingschanged || !enable)
2769 // not enabled, make sure we free anything we don't need anymore.
2770 if (r_shadow_bouncegrid_state.texture)
2772 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2773 r_shadow_bouncegrid_state.texture = NULL;
2775 r_shadow_bouncegrid_state.highpixels = NULL;
2776 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2777 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2778 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2779 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2780 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2781 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2782 r_shadow_bouncegrid_state.numpixels = 0;
2783 r_shadow_bouncegrid_state.directional = false;
2789 // if all the settings seem identical to the previous update, return
2790 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2793 // store the new settings
2794 r_shadow_bouncegrid_state.settings = settings;
2796 R_Shadow_BounceGrid_UpdateSpacing();
2798 // get the range of light numbers we'll be looping over:
2799 // range = static lights
2800 // range1 = dynamic lights (optional)
2801 // range2 = range + range1
2802 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2803 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2804 range2 = range + range1;
2806 // calculate weighting factors for distributing photons among the lights
2807 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
2808 R_TimeReport("bouncegrid_assignphotons");
2810 // trace the photons from lights and accumulate illumination
2811 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
2812 R_TimeReport("bouncegrid_tracephotons");
2814 // clear the texture
2815 R_Shadow_BounceGrid_ClearPixels();
2816 R_TimeReport("bouncegrid_cleartex");
2818 // accumulate the light splatting into texture
2819 R_Shadow_BounceGrid_PerformSplats();
2820 R_TimeReport("bouncegrid_lighttex");
2822 // apply a mild blur filter to the texture
2823 R_Shadow_BounceGrid_BlurPixels();
2824 R_TimeReport("bouncegrid_blurtex");
2826 // convert the pixels to lower precision and upload the texture
2827 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2828 R_TimeReport("bouncegrid_uploadtex");
2830 // after we compute the static lighting we don't need to keep the highpixels array around
2831 if (settings.staticmode)
2833 r_shadow_bouncegrid_state.highpixels = NULL;
2834 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2835 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2836 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2837 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2838 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2839 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2843 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2845 R_Shadow_RenderMode_Reset();
2846 GL_BlendFunc(GL_ONE, GL_ONE);
2847 GL_DepthRange(0, 1);
2848 GL_DepthTest(r_showlighting.integer < 2);
2849 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2851 GL_DepthFunc(GL_EQUAL);
2852 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2855 void R_Shadow_RenderMode_End(void)
2857 R_Shadow_RenderMode_Reset();
2858 R_Shadow_RenderMode_ActiveLight(NULL);
2860 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2861 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2864 int bboxedges[12][2] =
2883 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2885 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2887 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2888 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2889 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2890 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2893 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2894 return true; // invisible
2895 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2896 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2897 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2898 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2899 r_refdef.stats[r_stat_lights_scissored]++;
2903 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2905 // used to display how many times a surface is lit for level design purposes
2906 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2907 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2911 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])
2913 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2914 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2918 extern cvar_t gl_lightmaps;
2919 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2922 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2923 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2924 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2925 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2926 if (!r_shadow_usenormalmap.integer)
2928 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2929 VectorClear(diffusecolor);
2930 VectorClear(specularcolor);
2932 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2933 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2934 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2935 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2937 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2940 VectorNegate(ambientcolor, ambientcolor);
2941 VectorNegate(diffusecolor, diffusecolor);
2942 VectorNegate(specularcolor, specularcolor);
2943 GL_BlendEquationSubtract(true);
2945 RSurf_SetupDepthAndCulling();
2946 switch (r_shadow_rendermode)
2948 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2949 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2950 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2952 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2953 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2956 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2960 GL_BlendEquationSubtract(false);
2963 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)
2965 matrix4x4_t tempmatrix = *matrix;
2966 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2968 // if this light has been compiled before, free the associated data
2969 R_RTLight_Uncompile(rtlight);
2971 // clear it completely to avoid any lingering data
2972 memset(rtlight, 0, sizeof(*rtlight));
2974 // copy the properties
2975 rtlight->matrix_lighttoworld = tempmatrix;
2976 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2977 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2978 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2979 VectorCopy(color, rtlight->color);
2980 rtlight->cubemapname[0] = 0;
2981 if (cubemapname && cubemapname[0])
2982 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2983 rtlight->shadow = shadow;
2984 rtlight->corona = corona;
2985 rtlight->style = style;
2986 rtlight->isstatic = isstatic;
2987 rtlight->coronasizescale = coronasizescale;
2988 rtlight->ambientscale = ambientscale;
2989 rtlight->diffusescale = diffusescale;
2990 rtlight->specularscale = specularscale;
2991 rtlight->flags = flags;
2993 // compute derived data
2994 //rtlight->cullradius = rtlight->radius;
2995 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2996 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2997 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2998 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2999 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3000 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3001 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3004 // compiles rtlight geometry
3005 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3006 void R_RTLight_Compile(rtlight_t *rtlight)
3009 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3010 int lighttris, shadowtris;
3011 entity_render_t *ent = r_refdef.scene.worldentity;
3012 dp_model_t *model = r_refdef.scene.worldmodel;
3013 unsigned char *data;
3015 // compile the light
3016 rtlight->compiled = true;
3017 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3018 rtlight->static_numleafs = 0;
3019 rtlight->static_numleafpvsbytes = 0;
3020 rtlight->static_leaflist = NULL;
3021 rtlight->static_leafpvs = NULL;
3022 rtlight->static_numsurfaces = 0;
3023 rtlight->static_surfacelist = NULL;
3024 rtlight->static_shadowmap_receivers = 0x3F;
3025 rtlight->static_shadowmap_casters = 0x3F;
3026 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3027 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3028 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3029 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3030 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3031 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3033 if (model && model->GetLightInfo)
3035 // this variable must be set for the CompileShadowMap code
3036 r_shadow_compilingrtlight = rtlight;
3037 R_FrameData_SetMark();
3038 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);
3039 R_FrameData_ReturnToMark();
3040 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3041 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3042 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3043 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3044 rtlight->static_numsurfaces = numsurfaces;
3045 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3046 rtlight->static_numleafs = numleafs;
3047 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3048 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3049 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3050 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3051 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3052 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3053 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3054 if (rtlight->static_numsurfaces)
3055 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3056 if (rtlight->static_numleafs)
3057 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3058 if (rtlight->static_numleafpvsbytes)
3059 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3060 if (rtlight->static_numshadowtrispvsbytes)
3061 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3062 if (rtlight->static_numlighttrispvsbytes)
3063 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3064 R_FrameData_SetMark();
3065 if (model->CompileShadowMap && rtlight->shadow)
3066 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3067 R_FrameData_ReturnToMark();
3068 // now we're done compiling the rtlight
3069 r_shadow_compilingrtlight = NULL;
3073 // use smallest available cullradius - box radius or light radius
3074 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3075 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3078 if (rtlight->static_numlighttrispvsbytes)
3079 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3080 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3084 if (rtlight->static_numshadowtrispvsbytes)
3085 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3086 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3089 if (developer_extra.integer)
3090 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);
3093 void R_RTLight_Uncompile(rtlight_t *rtlight)
3095 if (rtlight->compiled)
3097 if (rtlight->static_meshchain_shadow_shadowmap)
3098 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3099 rtlight->static_meshchain_shadow_shadowmap = NULL;
3100 // these allocations are grouped
3101 if (rtlight->static_surfacelist)
3102 Mem_Free(rtlight->static_surfacelist);
3103 rtlight->static_numleafs = 0;
3104 rtlight->static_numleafpvsbytes = 0;
3105 rtlight->static_leaflist = NULL;
3106 rtlight->static_leafpvs = NULL;
3107 rtlight->static_numsurfaces = 0;
3108 rtlight->static_surfacelist = NULL;
3109 rtlight->static_numshadowtrispvsbytes = 0;
3110 rtlight->static_shadowtrispvs = NULL;
3111 rtlight->static_numlighttrispvsbytes = 0;
3112 rtlight->static_lighttrispvs = NULL;
3113 rtlight->compiled = false;
3117 void R_Shadow_UncompileWorldLights(void)
3121 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3122 for (lightindex = 0;lightindex < range;lightindex++)
3124 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3127 R_RTLight_Uncompile(&light->rtlight);
3131 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3135 // reset the count of frustum planes
3136 // see rtlight->cached_frustumplanes definition for how much this array
3138 rtlight->cached_numfrustumplanes = 0;
3140 if (r_trippy.integer)
3143 // haven't implemented a culling path for ortho rendering
3144 if (!r_refdef.view.useperspective)
3146 // check if the light is on screen and copy the 4 planes if it is
3147 for (i = 0;i < 4;i++)
3148 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3151 for (i = 0;i < 4;i++)
3152 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3157 // generate a deformed frustum that includes the light origin, this is
3158 // used to cull shadow casting surfaces that can not possibly cast a
3159 // shadow onto the visible light-receiving surfaces, which can be a
3162 // if the light origin is onscreen the result will be 4 planes exactly
3163 // if the light origin is offscreen on only one axis the result will
3164 // be exactly 5 planes (split-side case)
3165 // if the light origin is offscreen on two axes the result will be
3166 // exactly 4 planes (stretched corner case)
3167 for (i = 0;i < 4;i++)
3169 // quickly reject standard frustum planes that put the light
3170 // origin outside the frustum
3171 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3174 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3176 // if all the standard frustum planes were accepted, the light is onscreen
3177 // otherwise we need to generate some more planes below...
3178 if (rtlight->cached_numfrustumplanes < 4)
3180 // at least one of the stock frustum planes failed, so we need to
3181 // create one or two custom planes to enclose the light origin
3182 for (i = 0;i < 4;i++)
3184 // create a plane using the view origin and light origin, and a
3185 // single point from the frustum corner set
3186 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3187 VectorNormalize(plane.normal);
3188 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3189 // see if this plane is backwards and flip it if so
3190 for (j = 0;j < 4;j++)
3191 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3195 VectorNegate(plane.normal, plane.normal);
3197 // flipped plane, test again to see if it is now valid
3198 for (j = 0;j < 4;j++)
3199 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3201 // if the plane is still not valid, then it is dividing the
3202 // frustum and has to be rejected
3206 // we have created a valid plane, compute extra info
3207 PlaneClassify(&plane);
3209 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3211 // if we've found 5 frustum planes then we have constructed a
3212 // proper split-side case and do not need to keep searching for
3213 // planes to enclose the light origin
3214 if (rtlight->cached_numfrustumplanes == 5)
3222 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3224 plane = rtlight->cached_frustumplanes[i];
3225 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));
3230 // now add the light-space box planes if the light box is rotated, as any
3231 // caster outside the oriented light box is irrelevant (even if it passed
3232 // the worldspace light box, which is axial)
3233 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3235 for (i = 0;i < 6;i++)
3239 v[i >> 1] = (i & 1) ? -1 : 1;
3240 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3241 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3242 plane.dist = VectorNormalizeLength(plane.normal);
3243 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3244 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3250 // add the world-space reduced box planes
3251 for (i = 0;i < 6;i++)
3253 VectorClear(plane.normal);
3254 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3255 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3256 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3265 // reduce all plane distances to tightly fit the rtlight cull box, which
3267 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3268 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3269 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3270 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3271 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3272 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3273 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3274 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3275 oldnum = rtlight->cached_numfrustumplanes;
3276 rtlight->cached_numfrustumplanes = 0;
3277 for (j = 0;j < oldnum;j++)
3279 // find the nearest point on the box to this plane
3280 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3281 for (i = 1;i < 8;i++)
3283 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3284 if (bestdist > dist)
3287 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);
3288 // if the nearest point is near or behind the plane, we want this
3289 // plane, otherwise the plane is useless as it won't cull anything
3290 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3292 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3293 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3300 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3302 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3304 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3306 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3307 if (mesh->sidetotals[r_shadow_shadowmapside])
3310 GL_CullFace(GL_NONE);
3311 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3312 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3313 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);
3317 else if (r_refdef.scene.worldentity->model)
3318 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);
3320 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3323 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3325 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3326 vec_t relativeshadowradius;
3327 RSurf_ActiveModelEntity(ent, false, false, false);
3328 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3329 // we need to re-init the shader for each entity because the matrix changed
3330 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3331 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3332 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3333 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3334 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3335 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3336 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3337 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3338 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3341 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3343 // set up properties for rendering light onto this entity
3344 RSurf_ActiveModelEntity(ent, true, true, false);
3345 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3346 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3347 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3348 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3351 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3353 if (!r_refdef.scene.worldmodel->DrawLight)
3356 // set up properties for rendering light onto this entity
3357 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3358 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3359 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3360 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3361 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3363 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3365 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3368 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3370 dp_model_t *model = ent->model;
3371 if (!model->DrawLight)
3374 R_Shadow_SetupEntityLight(ent);
3376 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3378 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3381 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3385 int numleafs, numsurfaces;
3386 int *leaflist, *surfacelist;
3387 unsigned char *leafpvs;
3388 unsigned char *shadowtrispvs;
3389 unsigned char *lighttrispvs;
3390 //unsigned char *surfacesides;
3391 int numlightentities;
3392 int numlightentities_noselfshadow;
3393 int numshadowentities;
3394 int numshadowentities_noselfshadow;
3395 // FIXME: bounds check lightentities and shadowentities, etc.
3396 static entity_render_t *lightentities[MAX_EDICTS];
3397 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3398 static entity_render_t *shadowentities[MAX_EDICTS];
3399 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3401 qboolean castshadows;
3403 rtlight->draw = false;
3404 rtlight->cached_numlightentities = 0;
3405 rtlight->cached_numlightentities_noselfshadow = 0;
3406 rtlight->cached_numshadowentities = 0;
3407 rtlight->cached_numshadowentities_noselfshadow = 0;
3408 rtlight->cached_numsurfaces = 0;
3409 rtlight->cached_lightentities = NULL;
3410 rtlight->cached_lightentities_noselfshadow = NULL;
3411 rtlight->cached_shadowentities = NULL;
3412 rtlight->cached_shadowentities_noselfshadow = NULL;
3413 rtlight->cached_shadowtrispvs = NULL;
3414 rtlight->cached_lighttrispvs = NULL;
3415 rtlight->cached_surfacelist = NULL;
3416 rtlight->shadowmapsidesize = 0;
3418 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3419 // skip lights that are basically invisible (color 0 0 0)
3420 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3422 // loading is done before visibility checks because loading should happen
3423 // all at once at the start of a level, not when it stalls gameplay.
3424 // (especially important to benchmarks)
3426 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3428 if (rtlight->compiled)
3429 R_RTLight_Uncompile(rtlight);
3430 R_RTLight_Compile(rtlight);
3434 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3436 // look up the light style value at this time
3437 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3438 VectorScale(rtlight->color, f, rtlight->currentcolor);
3440 if (rtlight->selected)
3442 f = 2 + sin(realtime * M_PI * 4.0);
3443 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3447 // skip if lightstyle is currently off
3448 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3451 // skip processing on corona-only lights
3455 // skip if the light box is not touching any visible leafs
3456 if (r_shadow_culllights_pvs.integer
3457 && r_refdef.scene.worldmodel
3458 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3459 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3462 // skip if the light box is not visible to traceline
3463 if (r_shadow_culllights_trace.integer)
3465 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))
3466 rtlight->trace_timer = realtime;
3467 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3471 // skip if the light box is off screen
3472 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3475 // in the typical case this will be quickly replaced by GetLightInfo
3476 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3477 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3479 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3481 // 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
3482 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3485 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3487 // compiled light, world available and can receive realtime lighting
3488 // retrieve leaf information
3489 numleafs = rtlight->static_numleafs;
3490 leaflist = rtlight->static_leaflist;
3491 leafpvs = rtlight->static_leafpvs;
3492 numsurfaces = rtlight->static_numsurfaces;
3493 surfacelist = rtlight->static_surfacelist;
3494 //surfacesides = NULL;
3495 shadowtrispvs = rtlight->static_shadowtrispvs;
3496 lighttrispvs = rtlight->static_lighttrispvs;
3498 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3500 // dynamic light, world available and can receive realtime lighting
3501 // calculate lit surfaces and leafs
3502 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);
3503 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3504 leaflist = r_shadow_buffer_leaflist;
3505 leafpvs = r_shadow_buffer_leafpvs;
3506 surfacelist = r_shadow_buffer_surfacelist;
3507 //surfacesides = r_shadow_buffer_surfacesides;
3508 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3509 lighttrispvs = r_shadow_buffer_lighttrispvs;
3510 // if the reduced leaf bounds are offscreen, skip it
3511 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3522 //surfacesides = NULL;
3523 shadowtrispvs = NULL;
3524 lighttrispvs = NULL;
3526 // check if light is illuminating any visible leafs
3529 for (i = 0; i < numleafs; i++)
3530 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3536 // make a list of lit entities and shadow casting entities
3537 numlightentities = 0;
3538 numlightentities_noselfshadow = 0;
3539 numshadowentities = 0;
3540 numshadowentities_noselfshadow = 0;
3542 // add dynamic entities that are lit by the light
3543 for (i = 0; i < r_refdef.scene.numentities; i++)
3546 entity_render_t *ent = r_refdef.scene.entities[i];
3548 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3550 // skip the object entirely if it is not within the valid
3551 // shadow-casting region (which includes the lit region)
3552 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3554 if (!(model = ent->model))
3556 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3558 // this entity wants to receive light, is visible, and is
3559 // inside the light box
3560 // TODO: check if the surfaces in the model can receive light
3561 // so now check if it's in a leaf seen by the light
3562 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))
3564 if (ent->flags & RENDER_NOSELFSHADOW)
3565 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3567 lightentities[numlightentities++] = ent;
3568 // since it is lit, it probably also casts a shadow...
3569 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3570 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3571 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3573 // note: exterior models without the RENDER_NOSELFSHADOW
3574 // flag still create a RENDER_NOSELFSHADOW shadow but
3575 // are lit normally, this means that they are
3576 // self-shadowing but do not shadow other
3577 // RENDER_NOSELFSHADOW entities such as the gun
3578 // (very weird, but keeps the player shadow off the gun)
3579 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3580 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3582 shadowentities[numshadowentities++] = ent;
3585 else if (ent->flags & RENDER_SHADOW)
3587 // this entity is not receiving light, but may still need to
3589 // TODO: check if the surfaces in the model can cast shadow
3590 // now check if it is in a leaf seen by the light
3591 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))
3593 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3594 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3595 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3597 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3598 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3600 shadowentities[numshadowentities++] = ent;
3605 // return if there's nothing at all to light
3606 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3609 // count this light in the r_speeds
3610 r_refdef.stats[r_stat_lights]++;
3612 // flag it as worth drawing later
3613 rtlight->draw = true;
3615 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3616 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3618 numshadowentities = numshadowentities_noselfshadow = 0;
3619 rtlight->castshadows = castshadows;
3621 // cache all the animated entities that cast a shadow but are not visible
3622 for (i = 0; i < numshadowentities; i++)
3623 R_AnimCache_GetEntity(shadowentities[i], false, false);
3624 for (i = 0; i < numshadowentities_noselfshadow; i++)
3625 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3627 // 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)
3628 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3630 for (i = 0; i < numshadowentities_noselfshadow; i++)
3631 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3632 numshadowentities_noselfshadow = 0;
3635 // we can convert noselfshadow to regular if there are no casters of that type
3636 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3638 for (i = 0; i < numlightentities_noselfshadow; i++)
3639 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3640 numlightentities_noselfshadow = 0;
3643 // allocate some temporary memory for rendering this light later in the frame
3644 // reusable buffers need to be copied, static data can be used as-is
3645 rtlight->cached_numlightentities = numlightentities;
3646 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3647 rtlight->cached_numshadowentities = numshadowentities;
3648 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3649 rtlight->cached_numsurfaces = numsurfaces;
3650 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3651 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3652 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3653 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3654 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3656 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3657 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3658 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3659 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3660 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3664 // compiled light data
3665 rtlight->cached_shadowtrispvs = shadowtrispvs;
3666 rtlight->cached_lighttrispvs = lighttrispvs;
3667 rtlight->cached_surfacelist = surfacelist;
3670 if (R_Shadow_ShadowMappingEnabled())
3672 // figure out the shadowmapping parameters for this light
3673 vec3_t nearestpoint;
3676 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3677 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3678 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3679 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3680 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3681 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3682 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3683 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3684 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3688 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3692 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3693 int numlightentities;
3694 int numlightentities_noselfshadow;
3695 int numshadowentities;
3696 int numshadowentities_noselfshadow;
3697 entity_render_t **lightentities;
3698 entity_render_t **lightentities_noselfshadow;
3699 entity_render_t **shadowentities;
3700 entity_render_t **shadowentities_noselfshadow;
3702 static unsigned char entitysides[MAX_EDICTS];
3703 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3709 matrix4x4_t radiustolight;
3711 // check if we cached this light this frame (meaning it is worth drawing)
3712 if (!rtlight->draw || !rtlight->castshadows)
3715 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3716 if (rtlight->shadowmapatlassidesize == 0)
3718 rtlight->castshadows = false;
3722 // set up a scissor rectangle for this light
3723 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3726 // don't let sound skip if going slow
3727 if (r_refdef.scene.extraupdate)
3730 numlightentities = rtlight->cached_numlightentities;
3731 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3732 numshadowentities = rtlight->cached_numshadowentities;
3733 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3734 numsurfaces = rtlight->cached_numsurfaces;
3735 lightentities = rtlight->cached_lightentities;
3736 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3737 shadowentities = rtlight->cached_shadowentities;
3738 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3739 shadowtrispvs = rtlight->cached_shadowtrispvs;
3740 lighttrispvs = rtlight->cached_lighttrispvs;
3741 surfacelist = rtlight->cached_surfacelist;
3743 // make this the active rtlight for rendering purposes
3744 R_Shadow_RenderMode_ActiveLight(rtlight);
3746 radiustolight = rtlight->matrix_worldtolight;
3747 Matrix4x4_Abs(&radiustolight);
3749 size = rtlight->shadowmapatlassidesize;
3750 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3752 surfacesides = NULL;
3757 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3759 castermask = rtlight->static_shadowmap_casters;
3760 receivermask = rtlight->static_shadowmap_receivers;
3764 surfacesides = r_shadow_buffer_surfacesides;
3765 for (i = 0; i < numsurfaces; i++)
3767 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3768 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3769 castermask |= surfacesides[i];
3770 receivermask |= surfacesides[i];
3775 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3776 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3777 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3778 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3780 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3784 for (i = 0; i < numshadowentities; i++)
3785 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3786 for (i = 0; i < numshadowentities_noselfshadow; i++)
3787 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3790 // there is no need to render shadows for sides that have no receivers...
3791 castermask &= receivermask;
3793 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3795 // render shadow casters into shadowmaps for this light
3796 for (side = 0; side < 6; side++)
3798 int bit = 1 << side;
3799 if (castermask & bit)
3801 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3803 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3804 for (i = 0; i < numshadowentities; i++)
3805 if (entitysides[i] & bit)
3806 R_Shadow_DrawEntityShadow(shadowentities[i]);
3807 for (i = 0; i < numshadowentities_noselfshadow; i++)
3808 if (entitysides_noselfshadow[i] & bit)
3809 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3812 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3813 if (numshadowentities_noselfshadow)
3815 for (side = 0; side < 6; side++)
3817 int bit = 1 << side;
3818 if (castermask & bit)
3820 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3822 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3823 for (i = 0; i < numshadowentities; i++)
3824 if (entitysides[i] & bit)
3825 R_Shadow_DrawEntityShadow(shadowentities[i]);
3831 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3835 unsigned char *shadowtrispvs, *lighttrispvs;
3836 int numlightentities;
3837 int numlightentities_noselfshadow;
3838 int numshadowentities;
3839 int numshadowentities_noselfshadow;
3840 entity_render_t **lightentities;
3841 entity_render_t **lightentities_noselfshadow;
3842 entity_render_t **shadowentities;
3843 entity_render_t **shadowentities_noselfshadow;
3845 qboolean castshadows;
3847 // check if we cached this light this frame (meaning it is worth drawing)
3851 // set up a scissor rectangle for this light
3852 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3855 // don't let sound skip if going slow
3856 if (r_refdef.scene.extraupdate)
3859 numlightentities = rtlight->cached_numlightentities;
3860 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3861 numshadowentities = rtlight->cached_numshadowentities;
3862 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3863 numsurfaces = rtlight->cached_numsurfaces;
3864 lightentities = rtlight->cached_lightentities;
3865 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3866 shadowentities = rtlight->cached_shadowentities;
3867 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3868 shadowtrispvs = rtlight->cached_shadowtrispvs;
3869 lighttrispvs = rtlight->cached_lighttrispvs;
3870 surfacelist = rtlight->cached_surfacelist;
3871 castshadows = rtlight->castshadows;
3873 // make this the active rtlight for rendering purposes
3874 R_Shadow_RenderMode_ActiveLight(rtlight);
3876 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3878 // optionally draw the illuminated areas
3879 // for performance analysis by level designers
3880 R_Shadow_RenderMode_VisibleLighting(false);
3882 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3883 for (i = 0;i < numlightentities;i++)
3884 R_Shadow_DrawEntityLight(lightentities[i]);
3885 for (i = 0;i < numlightentities_noselfshadow;i++)
3886 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3889 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3893 float shadowmapoffsetnoselfshadow = 0;
3894 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3895 Matrix4x4_Abs(&radiustolight);
3897 size = rtlight->shadowmapatlassidesize;
3898 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3900 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3902 if (rtlight->cached_numshadowentities_noselfshadow)
3903 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3905 // render lighting using the depth texture as shadowmap
3906 // draw lighting in the unmasked areas
3907 if (numsurfaces + numlightentities)
3909 R_Shadow_RenderMode_Lighting(false, true, false);
3910 // draw lighting in the unmasked areas
3912 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3913 for (i = 0; i < numlightentities; i++)
3914 R_Shadow_DrawEntityLight(lightentities[i]);
3916 // offset to the noselfshadow part of the atlas and draw those too
3917 if (numlightentities_noselfshadow)
3919 R_Shadow_RenderMode_Lighting(false, true, true);
3920 for (i = 0; i < numlightentities_noselfshadow; i++)
3921 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3924 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3925 if (r_shadow_usingdeferredprepass)
3926 R_Shadow_RenderMode_DrawDeferredLight(true);
3930 // draw lighting in the unmasked areas
3931 R_Shadow_RenderMode_Lighting(false, false, false);
3933 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3934 for (i = 0;i < numlightentities;i++)
3935 R_Shadow_DrawEntityLight(lightentities[i]);
3936 for (i = 0;i < numlightentities_noselfshadow;i++)
3937 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3939 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3940 if (r_shadow_usingdeferredprepass)
3941 R_Shadow_RenderMode_DrawDeferredLight(false);
3945 static void R_Shadow_FreeDeferred(void)
3947 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3948 r_shadow_prepassgeometryfbo = 0;
3950 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3951 r_shadow_prepasslightingdiffusespecularfbo = 0;
3953 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3954 r_shadow_prepasslightingdiffusefbo = 0;
3956 if (r_shadow_prepassgeometrydepthbuffer)
3957 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3958 r_shadow_prepassgeometrydepthbuffer = NULL;
3960 if (r_shadow_prepassgeometrynormalmaptexture)
3961 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3962 r_shadow_prepassgeometrynormalmaptexture = NULL;
3964 if (r_shadow_prepasslightingdiffusetexture)
3965 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3966 r_shadow_prepasslightingdiffusetexture = NULL;
3968 if (r_shadow_prepasslightingspeculartexture)
3969 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3970 r_shadow_prepasslightingspeculartexture = NULL;
3973 void R_Shadow_DrawPrepass(void)
3977 entity_render_t *ent;
3978 float clearcolor[4];
3980 R_Mesh_ResetTextureState();
3982 GL_ColorMask(1,1,1,1);
3983 GL_BlendFunc(GL_ONE, GL_ZERO);
3986 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3987 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3988 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3989 if (r_timereport_active)
3990 R_TimeReport("prepasscleargeom");
3992 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3993 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3994 if (r_timereport_active)
3995 R_TimeReport("prepassworld");
3997 for (i = 0;i < r_refdef.scene.numentities;i++)
3999 if (!r_refdef.viewcache.entityvisible[i])
4001 ent = r_refdef.scene.entities[i];
4002 if (ent->model && ent->model->DrawPrepass != NULL)
4003 ent->model->DrawPrepass(ent);
4006 if (r_timereport_active)
4007 R_TimeReport("prepassmodels");
4009 GL_DepthMask(false);
4010 GL_ColorMask(1,1,1,1);
4013 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4014 Vector4Set(clearcolor, 0, 0, 0, 0);
4015 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4016 if (r_timereport_active)
4017 R_TimeReport("prepassclearlit");
4019 R_Shadow_RenderMode_Begin();
4021 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4022 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4024 R_Shadow_RenderMode_End();
4026 if (r_timereport_active)
4027 R_TimeReport("prepasslights");
4030 #define MAX_SCENELIGHTS 65536
4031 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4033 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4035 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4037 r_shadow_scenemaxlights *= 2;
4038 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4039 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4041 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4045 void R_Shadow_DrawLightSprites(void);
4046 void R_Shadow_PrepareLights(void)
4055 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4056 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4057 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4059 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4060 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4061 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4062 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4063 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4064 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4065 r_shadow_shadowmapborder != shadowmapborder ||
4066 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4067 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4068 R_Shadow_FreeShadowMaps();
4070 r_shadow_usingshadowmaportho = false;
4072 switch (vid.renderpath)
4074 case RENDERPATH_GL32:
4076 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4078 r_shadow_usingdeferredprepass = false;
4079 if (r_shadow_prepass_width)
4080 R_Shadow_FreeDeferred();
4081 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4085 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4087 R_Shadow_FreeDeferred();
4089 r_shadow_usingdeferredprepass = true;
4090 r_shadow_prepass_width = vid.width;
4091 r_shadow_prepass_height = vid.height;
4092 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4093 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);
4094 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);
4095 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);
4097 // set up the geometry pass fbo (depth + normalmap)
4098 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4099 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4100 // render depth into a renderbuffer and other important properties into the normalmap texture
4102 // set up the lighting pass fbo (diffuse + specular)
4103 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4104 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4105 // render diffuse into one texture and specular into another,
4106 // with depth and normalmap bound as textures,
4107 // with depth bound as attachment as well
4109 // set up the lighting pass fbo (diffuse)
4110 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4111 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4112 // render diffuse into one texture,
4113 // with depth and normalmap bound as textures,
4114 // with depth bound as attachment as well
4118 case RENDERPATH_GLES2:
4119 r_shadow_usingdeferredprepass = false;
4123 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);
4125 r_shadow_scenenumlights = 0;
4126 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4127 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4128 for (lightindex = 0; lightindex < range; lightindex++)
4130 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4131 if (light && (light->flags & flag))
4133 R_Shadow_PrepareLight(&light->rtlight);
4134 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4137 if (r_refdef.scene.rtdlight)
4139 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4141 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4142 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4145 else if (gl_flashblend.integer)
4147 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4149 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4150 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4151 VectorScale(rtlight->color, f, rtlight->currentcolor);
4155 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4156 if (r_shadow_debuglight.integer >= 0)
4158 r_shadow_scenenumlights = 0;
4159 lightindex = r_shadow_debuglight.integer;
4160 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4163 R_Shadow_PrepareLight(&light->rtlight);
4164 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4168 // if we're doing shadowmaps we need to prepare the atlas layout now
4169 if (R_Shadow_ShadowMappingEnabled())
4173 // allocate shadowmaps in the atlas now
4174 // 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...
4175 for (lod = 0; lod < 16; lod++)
4177 int packing_success = 0;
4178 int packing_failure = 0;
4179 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4180 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4181 if (r_shadow_shadowmapatlas_modelshadows_size)
4182 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);
4183 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4185 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4186 int size = rtlight->shadowmapsidesize >> lod;
4188 if (!rtlight->castshadows)
4190 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4193 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4194 if (rtlight->cached_numshadowentities_noselfshadow)
4196 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4198 rtlight->shadowmapatlassidesize = size;
4203 // note down that we failed to pack this one, it will have to disable shadows
4204 rtlight->shadowmapatlassidesize = 0;
4208 // generally everything fits and we stop here on the first iteration
4209 if (packing_failure == 0)
4214 if (r_editlights.integer)
4215 R_Shadow_DrawLightSprites();
4218 void R_Shadow_DrawShadowMaps(void)
4220 R_Shadow_RenderMode_Begin();
4221 R_Shadow_RenderMode_ActiveLight(NULL);
4223 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4224 R_Shadow_ClearShadowMapTexture();
4226 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4227 if (r_shadow_shadowmapatlas_modelshadows_size)
4229 R_Shadow_DrawModelShadowMaps();
4230 // don't let sound skip if going slow
4231 if (r_refdef.scene.extraupdate)
4235 if (R_Shadow_ShadowMappingEnabled())
4238 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4239 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4242 R_Shadow_RenderMode_End();
4245 void R_Shadow_DrawLights(void)
4249 R_Shadow_RenderMode_Begin();
4251 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4252 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4254 R_Shadow_RenderMode_End();
4257 #define MAX_MODELSHADOWS 1024
4258 static int r_shadow_nummodelshadows;
4259 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4261 void R_Shadow_PrepareModelShadows(void)
4264 float scale, size, radius, dot1, dot2;
4265 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4266 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4267 entity_render_t *ent;
4269 r_shadow_nummodelshadows = 0;
4270 r_shadow_shadowmapatlas_modelshadows_size = 0;
4272 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4275 size = r_shadow_shadowmaptexturesize / 4;
4276 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4277 radius = 0.5f * size / scale;
4279 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4280 VectorCopy(prvmshadowdir, shadowdir);
4281 VectorNormalize(shadowdir);
4282 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4283 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4284 if (fabs(dot1) <= fabs(dot2))
4285 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4287 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4288 VectorNormalize(shadowforward);
4289 CrossProduct(shadowdir, shadowforward, shadowright);
4290 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4291 VectorCopy(prvmshadowfocus, shadowfocus);
4292 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4293 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4294 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4295 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4296 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4298 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4300 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4301 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4302 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4303 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4304 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4305 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4307 for (i = 0; i < r_refdef.scene.numentities; i++)
4309 ent = r_refdef.scene.entities[i];
4310 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4312 // cast shadows from anything of the map (submodels are optional)
4313 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4315 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4317 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4318 R_AnimCache_GetEntity(ent, false, false);
4322 if (r_shadow_nummodelshadows)
4324 r_shadow_shadowmapatlas_modelshadows_x = 0;
4325 r_shadow_shadowmapatlas_modelshadows_y = 0;
4326 r_shadow_shadowmapatlas_modelshadows_size = size;
4330 static void R_Shadow_DrawModelShadowMaps(void)
4333 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4334 entity_render_t *ent;
4335 vec3_t relativelightorigin;
4336 vec3_t relativelightdirection, relativeforward, relativeright;
4337 vec3_t relativeshadowmins, relativeshadowmaxs;
4338 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4339 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4341 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4342 r_viewport_t viewport;
4344 size = r_shadow_shadowmapatlas_modelshadows_size;
4345 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4346 radius = 0.5f / scale;
4347 nearclip = -r_shadows_throwdistance.value;
4348 farclip = r_shadows_throwdistance.value;
4349 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);
4351 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4352 r_shadow_modelshadowmap_parameters[0] = size;
4353 r_shadow_modelshadowmap_parameters[1] = size;
4354 r_shadow_modelshadowmap_parameters[2] = 1.0;
4355 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4356 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4357 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4358 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4359 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4360 r_shadow_usingshadowmaportho = true;
4362 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4363 VectorCopy(prvmshadowdir, shadowdir);
4364 VectorNormalize(shadowdir);
4365 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4366 VectorCopy(prvmshadowfocus, shadowfocus);
4367 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4368 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4369 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4370 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4371 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4372 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4373 if (fabs(dot1) <= fabs(dot2))
4374 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4376 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4377 VectorNormalize(shadowforward);
4378 VectorM(scale, shadowforward, &m[0]);
4379 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4381 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4382 CrossProduct(shadowdir, shadowforward, shadowright);
4383 VectorM(scale, shadowright, &m[4]);
4384 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4385 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4386 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4387 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4388 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4389 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);
4390 R_SetViewport(&viewport);
4392 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4394 // render into a slightly restricted region so that the borders of the
4395 // shadowmap area fade away, rather than streaking across everything
4396 // outside the usable area
4397 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4399 for (i = 0;i < r_shadow_nummodelshadows;i++)
4401 ent = r_shadow_modelshadows[i];
4402 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4403 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4404 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4405 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4406 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4407 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4408 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4409 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4410 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4411 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4412 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4413 RSurf_ActiveModelEntity(ent, false, false, false);
4414 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4415 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4421 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4423 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4425 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4426 Cvar_SetValueQuick(&r_test, 0);
4431 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4432 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4433 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4434 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4435 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4436 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4439 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4442 vec3_t centerorigin;
4446 // if it's too close, skip it
4447 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4449 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4452 if (usequery && r_numqueries + 2 <= r_maxqueries)
4454 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4455 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4456 // 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
4457 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4459 switch(vid.renderpath)
4461 case RENDERPATH_GL32:
4462 case RENDERPATH_GLES2:
4465 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4466 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4467 GL_DepthFunc(GL_ALWAYS);
4468 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4469 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4470 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4471 qglEndQuery(GL_SAMPLES_PASSED);
4472 GL_DepthFunc(GL_LEQUAL);
4473 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4474 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4475 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4476 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4477 qglEndQuery(GL_SAMPLES_PASSED);
4483 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4486 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4488 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4491 unsigned int occlude = 0;
4493 // now we have to check the query result
4494 if (rtlight->corona_queryindex_visiblepixels)
4496 switch(vid.renderpath)
4498 case RENDERPATH_GL32:
4499 case RENDERPATH_GLES2:
4501 // store the pixel counts into a uniform buffer for the shader to
4502 // use - we'll never know the results on the cpu without
4503 // synchronizing and we don't want that
4504 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4505 if (!r_shadow_occlusion_buf) {
4506 qglGenBuffers(1, &r_shadow_occlusion_buf);
4507 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4508 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4510 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4512 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4513 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4514 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4515 occlude = MATERIALFLAG_OCCLUDE;
4516 cscale *= rtlight->corona_visibility;
4526 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4529 VectorScale(rtlight->currentcolor, cscale, color);
4530 if (VectorLength(color) > (1.0f / 256.0f))
4533 qboolean negated = (color[0] + color[1] + color[2] < 0);
4536 VectorNegate(color, color);
4537 GL_BlendEquationSubtract(true);
4539 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4540 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);
4541 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4543 GL_BlendEquationSubtract(false);
4547 void R_Shadow_DrawCoronas(void)
4550 qboolean usequery = false;
4555 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4557 if (r_fb.water.renderingscene)
4559 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4560 R_EntityMatrix(&identitymatrix);
4562 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4564 // check occlusion of coronas, using occlusion queries or raytraces
4566 switch (vid.renderpath)
4568 case RENDERPATH_GL32:
4569 case RENDERPATH_GLES2:
4570 usequery = r_coronas_occlusionquery.integer;
4574 GL_ColorMask(0,0,0,0);
4575 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4576 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4579 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4580 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4582 qglGenQueries(r_maxqueries - i, r_queries + i);
4585 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4586 GL_BlendFunc(GL_ONE, GL_ZERO);
4587 GL_CullFace(GL_NONE);
4588 GL_DepthMask(false);
4589 GL_DepthRange(0, 1);
4590 GL_PolygonOffset(0, 0);
4592 R_Mesh_ResetTextureState();
4593 R_SetupShader_Generic_NoTexture(false, false);
4598 for (lightindex = 0;lightindex < range;lightindex++)
4600 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4603 rtlight = &light->rtlight;
4604 rtlight->corona_visibility = 0;
4605 rtlight->corona_queryindex_visiblepixels = 0;
4606 rtlight->corona_queryindex_allpixels = 0;
4607 if (!(rtlight->flags & flag))
4609 if (rtlight->corona <= 0)
4611 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4613 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4615 for (i = 0;i < r_refdef.scene.numlights;i++)
4617 rtlight = r_refdef.scene.lights[i];
4618 rtlight->corona_visibility = 0;
4619 rtlight->corona_queryindex_visiblepixels = 0;
4620 rtlight->corona_queryindex_allpixels = 0;
4621 if (!(rtlight->flags & flag))
4623 if (rtlight->corona <= 0)
4625 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4628 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4630 // now draw the coronas using the query data for intensity info
4631 for (lightindex = 0;lightindex < range;lightindex++)
4633 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4636 rtlight = &light->rtlight;
4637 if (rtlight->corona_visibility <= 0)
4639 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4641 for (i = 0;i < r_refdef.scene.numlights;i++)
4643 rtlight = r_refdef.scene.lights[i];
4644 if (rtlight->corona_visibility <= 0)
4646 if (gl_flashblend.integer)
4647 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4649 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4655 static dlight_t *R_Shadow_NewWorldLight(void)
4657 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4660 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)
4664 // 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
4666 // validate parameters
4670 // copy to light properties
4671 VectorCopy(origin, light->origin);
4672 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4673 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4674 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4676 light->color[0] = max(color[0], 0);
4677 light->color[1] = max(color[1], 0);
4678 light->color[2] = max(color[2], 0);
4680 light->color[0] = color[0];
4681 light->color[1] = color[1];
4682 light->color[2] = color[2];
4683 light->radius = max(radius, 0);
4684 light->style = style;
4685 light->shadow = shadowenable;
4686 light->corona = corona;
4687 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4688 light->coronasizescale = coronasizescale;
4689 light->ambientscale = ambientscale;
4690 light->diffusescale = diffusescale;
4691 light->specularscale = specularscale;
4692 light->flags = flags;
4694 // update renderable light data
4695 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4696 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);
4699 static void R_Shadow_FreeWorldLight(dlight_t *light)
4701 if (r_shadow_selectedlight == light)
4702 r_shadow_selectedlight = NULL;
4703 R_RTLight_Uncompile(&light->rtlight);
4704 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4707 void R_Shadow_ClearWorldLights(void)
4711 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4712 for (lightindex = 0;lightindex < range;lightindex++)
4714 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4716 R_Shadow_FreeWorldLight(light);
4718 r_shadow_selectedlight = NULL;
4721 static void R_Shadow_SelectLight(dlight_t *light)
4723 if (r_shadow_selectedlight)
4724 r_shadow_selectedlight->selected = false;
4725 r_shadow_selectedlight = light;
4726 if (r_shadow_selectedlight)
4727 r_shadow_selectedlight->selected = true;
4730 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4732 // this is never batched (there can be only one)
4734 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4735 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4736 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4739 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4744 skinframe_t *skinframe;
4747 // this is never batched (due to the ent parameter changing every time)
4748 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4749 const dlight_t *light = (dlight_t *)ent;
4752 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4755 VectorScale(light->color, intensity, spritecolor);
4756 if (VectorLength(spritecolor) < 0.1732f)
4757 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4758 if (VectorLength(spritecolor) > 1.0f)
4759 VectorNormalize(spritecolor);
4761 // draw light sprite
4762 if (light->cubemapname[0] && !light->shadow)
4763 skinframe = r_editlights_sprcubemapnoshadowlight;
4764 else if (light->cubemapname[0])
4765 skinframe = r_editlights_sprcubemaplight;
4766 else if (!light->shadow)
4767 skinframe = r_editlights_sprnoshadowlight;
4769 skinframe = r_editlights_sprlight;
4771 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);
4772 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4774 // draw selection sprite if light is selected
4775 if (light->selected)
4777 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4778 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4779 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4783 void R_Shadow_DrawLightSprites(void)
4787 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4788 for (lightindex = 0;lightindex < range;lightindex++)
4790 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4792 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4794 if (!r_editlights_lockcursor)
4795 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4798 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4803 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4804 if (lightindex >= range)
4806 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4809 rtlight = &light->rtlight;
4810 //if (!(rtlight->flags & flag))
4812 VectorCopy(rtlight->shadoworigin, origin);
4813 *radius = rtlight->radius;
4814 VectorCopy(rtlight->color, color);
4818 static void R_Shadow_SelectLightInView(void)
4820 float bestrating, rating, temp[3];
4824 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4828 if (r_editlights_lockcursor)
4830 for (lightindex = 0;lightindex < range;lightindex++)
4832 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4835 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4836 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4839 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4840 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)
4842 bestrating = rating;
4847 R_Shadow_SelectLight(best);
4850 void R_Shadow_LoadWorldLights(void)
4852 int n, a, style, shadow, flags;
4853 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4854 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4855 if (cl.worldmodel == NULL)
4857 Con_Print("No map loaded.\n");
4860 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4861 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4871 for (;COM_Parse(t, true) && strcmp(
4872 if (COM_Parse(t, true))
4874 if (com_token[0] == '!')
4877 origin[0] = atof(com_token+1);
4880 origin[0] = atof(com_token);
4885 while (*s && *s != '\n' && *s != '\r')
4891 // check for modifier flags
4898 #if _MSC_VER >= 1400
4899 #define sscanf sscanf_s
4901 cubemapname[sizeof(cubemapname)-1] = 0;
4902 #if MAX_QPATH != 128
4903 #error update this code if MAX_QPATH changes
4905 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
4906 #if _MSC_VER >= 1400
4907 , (unsigned int)sizeof(cubemapname)
4909 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4912 flags = LIGHTFLAG_REALTIMEMODE;
4920 coronasizescale = 0.25f;
4922 VectorClear(angles);
4925 if (a < 9 || !strcmp(cubemapname, "\"\""))
4927 // remove quotes on cubemapname
4928 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4931 namelen = strlen(cubemapname) - 2;
4932 memmove(cubemapname, cubemapname + 1, namelen);
4933 cubemapname[namelen] = '\0';
4937 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);
4940 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4948 Con_Printf("invalid rtlights file \"%s\"\n", name);
4949 Mem_Free(lightsstring);
4953 void R_Shadow_SaveWorldLights(void)
4957 size_t bufchars, bufmaxchars;
4959 char name[MAX_QPATH];
4960 char line[MAX_INPUTLINE];
4961 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4962 // I hate lines which are 3 times my screen size :( --blub
4965 if (cl.worldmodel == NULL)
4967 Con_Print("No map loaded.\n");
4970 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4971 bufchars = bufmaxchars = 0;
4973 for (lightindex = 0;lightindex < range;lightindex++)
4975 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4978 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4979 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);
4980 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4981 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]);
4983 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);
4984 if (bufchars + strlen(line) > bufmaxchars)
4986 bufmaxchars = bufchars + strlen(line) + 2048;
4988 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4992 memcpy(buf, oldbuf, bufchars);
4998 memcpy(buf + bufchars, line, strlen(line));
4999 bufchars += strlen(line);
5003 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5008 void R_Shadow_LoadLightsFile(void)
5011 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5012 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5013 if (cl.worldmodel == NULL)
5015 Con_Print("No map loaded.\n");
5018 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5019 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5027 while (*s && *s != '\n' && *s != '\r')
5033 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);
5037 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);
5040 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5041 radius = bound(15, radius, 4096);
5042 VectorScale(color, (2.0f / (8388608.0f)), color);
5043 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5051 Con_Printf("invalid lights file \"%s\"\n", name);
5052 Mem_Free(lightsstring);
5056 // tyrlite/hmap2 light types in the delay field
5057 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5059 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5071 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5072 char key[256], value[MAX_INPUTLINE];
5075 if (cl.worldmodel == NULL)
5077 Con_Print("No map loaded.\n");
5080 // try to load a .ent file first
5081 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5082 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5083 // and if that is not found, fall back to the bsp file entity string
5085 data = cl.worldmodel->brush.entities;
5088 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5090 type = LIGHTTYPE_MINUSX;
5091 origin[0] = origin[1] = origin[2] = 0;
5092 originhack[0] = originhack[1] = originhack[2] = 0;
5093 angles[0] = angles[1] = angles[2] = 0;
5094 color[0] = color[1] = color[2] = 1;
5095 light[0] = light[1] = light[2] = 1;light[3] = 300;
5096 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5106 if (!COM_ParseToken_Simple(&data, false, false, true))
5108 if (com_token[0] == '}')
5109 break; // end of entity
5110 if (com_token[0] == '_')
5111 strlcpy(key, com_token + 1, sizeof(key));
5113 strlcpy(key, com_token, sizeof(key));
5114 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5115 key[strlen(key)-1] = 0;
5116 if (!COM_ParseToken_Simple(&data, false, false, true))
5118 strlcpy(value, com_token, sizeof(value));
5120 // now that we have the key pair worked out...
5121 if (!strcmp("light", key))
5123 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5127 light[0] = vec[0] * (1.0f / 256.0f);
5128 light[1] = vec[0] * (1.0f / 256.0f);
5129 light[2] = vec[0] * (1.0f / 256.0f);
5135 light[0] = vec[0] * (1.0f / 255.0f);
5136 light[1] = vec[1] * (1.0f / 255.0f);
5137 light[2] = vec[2] * (1.0f / 255.0f);
5141 else if (!strcmp("delay", key))
5143 else if (!strcmp("origin", key))
5144 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5145 else if (!strcmp("angle", key))
5146 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5147 else if (!strcmp("angles", key))
5148 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5149 else if (!strcmp("color", key))
5150 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5151 else if (!strcmp("wait", key))
5152 fadescale = atof(value);
5153 else if (!strcmp("classname", key))
5155 if (!strncmp(value, "light", 5))
5158 if (!strcmp(value, "light_fluoro"))
5163 overridecolor[0] = 1;
5164 overridecolor[1] = 1;
5165 overridecolor[2] = 1;
5167 if (!strcmp(value, "light_fluorospark"))
5172 overridecolor[0] = 1;
5173 overridecolor[1] = 1;
5174 overridecolor[2] = 1;
5176 if (!strcmp(value, "light_globe"))
5181 overridecolor[0] = 1;
5182 overridecolor[1] = 0.8;
5183 overridecolor[2] = 0.4;
5185 if (!strcmp(value, "light_flame_large_yellow"))
5190 overridecolor[0] = 1;
5191 overridecolor[1] = 0.5;
5192 overridecolor[2] = 0.1;
5194 if (!strcmp(value, "light_flame_small_yellow"))
5199 overridecolor[0] = 1;
5200 overridecolor[1] = 0.5;
5201 overridecolor[2] = 0.1;
5203 if (!strcmp(value, "light_torch_small_white"))
5208 overridecolor[0] = 1;
5209 overridecolor[1] = 0.5;
5210 overridecolor[2] = 0.1;
5212 if (!strcmp(value, "light_torch_small_walltorch"))
5217 overridecolor[0] = 1;
5218 overridecolor[1] = 0.5;
5219 overridecolor[2] = 0.1;
5223 else if (!strcmp("style", key))
5224 style = atoi(value);
5225 else if (!strcmp("skin", key))
5226 skin = (int)atof(value);
5227 else if (!strcmp("pflags", key))
5228 pflags = (int)atof(value);
5229 //else if (!strcmp("effects", key))
5230 // effects = (int)atof(value);
5231 else if (cl.worldmodel->type == mod_brushq3)
5233 if (!strcmp("scale", key))
5234 lightscale = atof(value);
5235 if (!strcmp("fade", key))
5236 fadescale = atof(value);
5241 if (lightscale <= 0)
5245 if (color[0] == color[1] && color[0] == color[2])
5247 color[0] *= overridecolor[0];
5248 color[1] *= overridecolor[1];
5249 color[2] *= overridecolor[2];
5251 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5252 color[0] = color[0] * light[0];
5253 color[1] = color[1] * light[1];
5254 color[2] = color[2] * light[2];
5257 case LIGHTTYPE_MINUSX:
5259 case LIGHTTYPE_RECIPX:
5261 VectorScale(color, (1.0f / 16.0f), color);
5263 case LIGHTTYPE_RECIPXX:
5265 VectorScale(color, (1.0f / 16.0f), color);
5268 case LIGHTTYPE_NONE:
5272 case LIGHTTYPE_MINUSXX:
5275 VectorAdd(origin, originhack, origin);
5277 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);
5280 Mem_Free(entfiledata);
5284 static void R_Shadow_SetCursorLocationForView(void)
5287 vec3_t dest, endpos;
5289 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5290 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5291 if (trace.fraction < 1)
5293 dist = trace.fraction * r_editlights_cursordistance.value;
5294 push = r_editlights_cursorpushback.value;
5298 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5299 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5303 VectorClear( endpos );
5305 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5306 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5307 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5310 void R_Shadow_UpdateWorldLightSelection(void)
5312 if (r_editlights.integer)
5314 R_Shadow_SetCursorLocationForView();
5315 R_Shadow_SelectLightInView();
5318 R_Shadow_SelectLight(NULL);
5321 static void R_Shadow_EditLights_Clear_f(void)
5323 R_Shadow_ClearWorldLights();
5326 void R_Shadow_EditLights_Reload_f(void)
5330 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5331 R_Shadow_ClearWorldLights();
5332 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5334 R_Shadow_LoadWorldLights();
5335 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5336 R_Shadow_LoadLightsFile();
5338 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5340 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5341 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5345 static void R_Shadow_EditLights_Save_f(void)
5349 R_Shadow_SaveWorldLights();
5352 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5354 R_Shadow_ClearWorldLights();
5355 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5358 static void R_Shadow_EditLights_ImportLightsFile_f(void)
5360 R_Shadow_ClearWorldLights();
5361 R_Shadow_LoadLightsFile();
5364 static void R_Shadow_EditLights_Spawn_f(void)
5367 if (!r_editlights.integer)
5369 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5372 if (Cmd_Argc() != 1)
5374 Con_Print("r_editlights_spawn does not take parameters\n");
5377 color[0] = color[1] = color[2] = 1;
5378 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5381 static void R_Shadow_EditLights_Edit_f(void)
5383 vec3_t origin, angles, color;
5384 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5385 int style, shadows, flags, normalmode, realtimemode;
5386 char cubemapname[MAX_INPUTLINE];
5387 if (!r_editlights.integer)
5389 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5392 if (!r_shadow_selectedlight)
5394 Con_Print("No selected light.\n");
5397 VectorCopy(r_shadow_selectedlight->origin, origin);
5398 VectorCopy(r_shadow_selectedlight->angles, angles);
5399 VectorCopy(r_shadow_selectedlight->color, color);
5400 radius = r_shadow_selectedlight->radius;
5401 style = r_shadow_selectedlight->style;
5402 if (r_shadow_selectedlight->cubemapname)
5403 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5406 shadows = r_shadow_selectedlight->shadow;
5407 corona = r_shadow_selectedlight->corona;
5408 coronasizescale = r_shadow_selectedlight->coronasizescale;
5409 ambientscale = r_shadow_selectedlight->ambientscale;
5410 diffusescale = r_shadow_selectedlight->diffusescale;
5411 specularscale = r_shadow_selectedlight->specularscale;
5412 flags = r_shadow_selectedlight->flags;
5413 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5414 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5415 if (!strcmp(Cmd_Argv(1), "origin"))
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), "originscale"))
5428 if (Cmd_Argc() != 5)
5430 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5433 origin[0] *= atof(Cmd_Argv(2));
5434 origin[1] *= atof(Cmd_Argv(3));
5435 origin[2] *= atof(Cmd_Argv(4));
5437 else if (!strcmp(Cmd_Argv(1), "originx"))
5439 if (Cmd_Argc() != 3)
5441 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5444 origin[0] = atof(Cmd_Argv(2));
5446 else if (!strcmp(Cmd_Argv(1), "originy"))
5448 if (Cmd_Argc() != 3)
5450 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5453 origin[1] = atof(Cmd_Argv(2));
5455 else if (!strcmp(Cmd_Argv(1), "originz"))
5457 if (Cmd_Argc() != 3)
5459 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5462 origin[2] = atof(Cmd_Argv(2));
5464 else if (!strcmp(Cmd_Argv(1), "move"))
5466 if (Cmd_Argc() != 5)
5468 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5471 origin[0] += atof(Cmd_Argv(2));
5472 origin[1] += atof(Cmd_Argv(3));
5473 origin[2] += atof(Cmd_Argv(4));
5475 else if (!strcmp(Cmd_Argv(1), "movex"))
5477 if (Cmd_Argc() != 3)
5479 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5482 origin[0] += atof(Cmd_Argv(2));
5484 else if (!strcmp(Cmd_Argv(1), "movey"))
5486 if (Cmd_Argc() != 3)
5488 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5491 origin[1] += atof(Cmd_Argv(2));
5493 else if (!strcmp(Cmd_Argv(1), "movez"))
5495 if (Cmd_Argc() != 3)
5497 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5500 origin[2] += atof(Cmd_Argv(2));
5502 else if (!strcmp(Cmd_Argv(1), "angles"))
5504 if (Cmd_Argc() != 5)
5506 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5509 angles[0] = atof(Cmd_Argv(2));
5510 angles[1] = atof(Cmd_Argv(3));
5511 angles[2] = atof(Cmd_Argv(4));
5513 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5515 if (Cmd_Argc() != 3)
5517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5520 angles[0] = atof(Cmd_Argv(2));
5522 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5524 if (Cmd_Argc() != 3)
5526 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5529 angles[1] = atof(Cmd_Argv(2));
5531 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5533 if (Cmd_Argc() != 3)
5535 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5538 angles[2] = atof(Cmd_Argv(2));
5540 else if (!strcmp(Cmd_Argv(1), "color"))
5542 if (Cmd_Argc() != 5)
5544 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5547 color[0] = atof(Cmd_Argv(2));
5548 color[1] = atof(Cmd_Argv(3));
5549 color[2] = atof(Cmd_Argv(4));
5551 else if (!strcmp(Cmd_Argv(1), "radius"))
5553 if (Cmd_Argc() != 3)
5555 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5558 radius = atof(Cmd_Argv(2));
5560 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5562 if (Cmd_Argc() == 3)
5564 double scale = atof(Cmd_Argv(2));
5571 if (Cmd_Argc() != 5)
5573 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5576 color[0] *= atof(Cmd_Argv(2));
5577 color[1] *= atof(Cmd_Argv(3));
5578 color[2] *= atof(Cmd_Argv(4));
5581 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5583 if (Cmd_Argc() != 3)
5585 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5588 radius *= atof(Cmd_Argv(2));
5590 else if (!strcmp(Cmd_Argv(1), "style"))
5592 if (Cmd_Argc() != 3)
5594 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5597 style = atoi(Cmd_Argv(2));
5599 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5603 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5606 if (Cmd_Argc() == 3)
5607 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5611 else if (!strcmp(Cmd_Argv(1), "shadows"))
5613 if (Cmd_Argc() != 3)
5615 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5618 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5620 else if (!strcmp(Cmd_Argv(1), "corona"))
5622 if (Cmd_Argc() != 3)
5624 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5627 corona = atof(Cmd_Argv(2));
5629 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5631 if (Cmd_Argc() != 3)
5633 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5636 coronasizescale = atof(Cmd_Argv(2));
5638 else if (!strcmp(Cmd_Argv(1), "ambient"))
5640 if (Cmd_Argc() != 3)
5642 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5645 ambientscale = atof(Cmd_Argv(2));
5647 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5649 if (Cmd_Argc() != 3)
5651 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5654 diffusescale = atof(Cmd_Argv(2));
5656 else if (!strcmp(Cmd_Argv(1), "specular"))
5658 if (Cmd_Argc() != 3)
5660 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5663 specularscale = atof(Cmd_Argv(2));
5665 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5667 if (Cmd_Argc() != 3)
5669 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5672 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5674 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5676 if (Cmd_Argc() != 3)
5678 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5681 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5685 Con_Print("usage: r_editlights_edit [property] [value]\n");
5686 Con_Print("Selected light's properties:\n");
5687 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5688 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5689 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5690 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5691 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5692 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5693 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5694 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5695 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5696 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5697 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5698 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5699 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5700 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5703 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5704 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5707 static void R_Shadow_EditLights_EditAll_f(void)
5710 dlight_t *light, *oldselected;
5713 if (!r_editlights.integer)
5715 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5719 oldselected = r_shadow_selectedlight;
5720 // EditLights doesn't seem to have a "remove" command or something so:
5721 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5722 for (lightindex = 0;lightindex < range;lightindex++)
5724 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5727 R_Shadow_SelectLight(light);
5728 R_Shadow_EditLights_Edit_f();
5730 // return to old selected (to not mess editing once selection is locked)
5731 R_Shadow_SelectLight(oldselected);
5734 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5736 int lightnumber, lightcount;
5737 size_t lightindex, range;
5742 if (!r_editlights.integer)
5745 // update cvars so QC can query them
5746 if (r_shadow_selectedlight)
5748 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5749 Cvar_SetQuick(&r_editlights_current_origin, temp);
5750 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5751 Cvar_SetQuick(&r_editlights_current_angles, temp);
5752 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5753 Cvar_SetQuick(&r_editlights_current_color, temp);
5754 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5755 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5756 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5757 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5758 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5759 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5760 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5761 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5762 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5763 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5764 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5767 // draw properties on screen
5768 if (!r_editlights_drawproperties.integer)
5770 x = vid_conwidth.value - 320;
5772 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5775 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5776 for (lightindex = 0;lightindex < range;lightindex++)
5778 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5781 if (light == r_shadow_selectedlight)
5782 lightnumber = (int)lightindex;
5785 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;
5786 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;
5788 if (r_shadow_selectedlight == NULL)
5790 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;
5791 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;
5792 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;
5793 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;
5794 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;
5795 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;
5796 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;
5797 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;
5798 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;
5799 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;
5800 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;
5801 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;
5802 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;
5803 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;
5804 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;
5806 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;
5807 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;
5808 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;
5809 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;
5810 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;
5811 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;
5812 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;
5813 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;
5814 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;
5815 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;
5818 static void R_Shadow_EditLights_ToggleShadow_f(void)
5820 if (!r_editlights.integer)
5822 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5825 if (!r_shadow_selectedlight)
5827 Con_Print("No selected light.\n");
5830 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);
5833 static void R_Shadow_EditLights_ToggleCorona_f(void)
5835 if (!r_editlights.integer)
5837 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5840 if (!r_shadow_selectedlight)
5842 Con_Print("No selected light.\n");
5845 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);
5848 static void R_Shadow_EditLights_Remove_f(void)
5850 if (!r_editlights.integer)
5852 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5855 if (!r_shadow_selectedlight)
5857 Con_Print("No selected light.\n");
5860 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5861 r_shadow_selectedlight = NULL;
5864 static void R_Shadow_EditLights_Help_f(void)
5867 "Documentation on r_editlights system:\n"
5869 "r_editlights : enable/disable editing mode\n"
5870 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5871 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5872 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5873 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5874 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5876 "r_editlights_help : this help\n"
5877 "r_editlights_clear : remove all lights\n"
5878 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5879 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5880 "r_editlights_save : save to .rtlights file\n"
5881 "r_editlights_spawn : create a light with default settings\n"
5882 "r_editlights_edit command : edit selected light - more documentation below\n"
5883 "r_editlights_remove : remove selected light\n"
5884 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5885 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5886 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5888 "origin x y z : set light location\n"
5889 "originx x: set x component of light location\n"
5890 "originy y: set y component of light location\n"
5891 "originz z: set z component of light location\n"
5892 "move x y z : adjust light location\n"
5893 "movex x: adjust x component of light location\n"
5894 "movey y: adjust y component of light location\n"
5895 "movez z: adjust z component of light location\n"
5896 "angles x y z : set light angles\n"
5897 "anglesx x: set x component of light angles\n"
5898 "anglesy y: set y component of light angles\n"
5899 "anglesz z: set z component of light angles\n"
5900 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5901 "radius radius : set radius (size) of light\n"
5902 "colorscale grey : multiply color of light (1 does nothing)\n"
5903 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5904 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5905 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5906 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5907 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5908 "cubemap basename : set filter cubemap of light\n"
5909 "shadows 1/0 : turn on/off shadows\n"
5910 "corona n : set corona intensity\n"
5911 "coronasize n : set corona size (0-1)\n"
5912 "ambient n : set ambient intensity (0-1)\n"
5913 "diffuse n : set diffuse intensity (0-1)\n"
5914 "specular n : set specular intensity (0-1)\n"
5915 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5916 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5917 "<nothing> : print light properties to console\n"
5921 static void R_Shadow_EditLights_CopyInfo_f(void)
5923 if (!r_editlights.integer)
5925 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5928 if (!r_shadow_selectedlight)
5930 Con_Print("No selected light.\n");
5933 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5934 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5935 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5936 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5937 if (r_shadow_selectedlight->cubemapname)
5938 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5940 r_shadow_bufferlight.cubemapname[0] = 0;
5941 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5942 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5943 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5944 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5945 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5946 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5947 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5950 static void R_Shadow_EditLights_PasteInfo_f(void)
5952 if (!r_editlights.integer)
5954 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5957 if (!r_shadow_selectedlight)
5959 Con_Print("No selected light.\n");
5962 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);
5965 static void R_Shadow_EditLights_Lock_f(void)
5967 if (!r_editlights.integer)
5969 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5972 if (r_editlights_lockcursor)
5974 r_editlights_lockcursor = false;
5977 if (!r_shadow_selectedlight)
5979 Con_Print("No selected light to lock on.\n");
5982 r_editlights_lockcursor = true;
5985 static void R_Shadow_EditLights_Init(void)
5987 Cvar_RegisterVariable(&r_editlights);
5988 Cvar_RegisterVariable(&r_editlights_cursordistance);
5989 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5990 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5991 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5992 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5993 Cvar_RegisterVariable(&r_editlights_drawproperties);
5994 Cvar_RegisterVariable(&r_editlights_current_origin);
5995 Cvar_RegisterVariable(&r_editlights_current_angles);
5996 Cvar_RegisterVariable(&r_editlights_current_color);
5997 Cvar_RegisterVariable(&r_editlights_current_radius);
5998 Cvar_RegisterVariable(&r_editlights_current_corona);
5999 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6000 Cvar_RegisterVariable(&r_editlights_current_style);
6001 Cvar_RegisterVariable(&r_editlights_current_shadows);
6002 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6003 Cvar_RegisterVariable(&r_editlights_current_ambient);
6004 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6005 Cvar_RegisterVariable(&r_editlights_current_specular);
6006 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6007 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6008 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6009 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6010 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)");
6011 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6012 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6013 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6014 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)");
6015 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6016 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6017 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6018 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6019 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6020 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6021 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)");
6022 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6028 =============================================================================
6032 =============================================================================
6035 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6037 int i, numlights, flag, q;
6040 float relativepoint[3];
6045 float sa[3], sx[3], sy[3], sz[3], sd[3];
6048 // use first order spherical harmonics to combine directional lights
6049 for (q = 0; q < 3; q++)
6050 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6052 if (flags & LP_LIGHTMAP)
6054 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6056 float tempambient[3];
6057 for (q = 0; q < 3; q++)
6058 tempambient[q] = color[q] = relativepoint[q] = 0;
6059 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6060 // calculate a weighted average light direction as well
6061 intensity = VectorLength(color);
6062 for (q = 0; q < 3; q++)
6064 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6065 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6066 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6067 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6068 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6073 // unlit map - fullbright but scaled by lightmapintensity
6074 for (q = 0; q < 3; q++)
6075 sa[q] += lightmapintensity;
6079 if (flags & LP_RTWORLD)
6081 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6082 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6083 for (i = 0; i < numlights; i++)
6085 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6088 light = &dlight->rtlight;
6089 if (!(light->flags & flag))
6092 lightradius2 = light->radius * light->radius;
6093 VectorSubtract(light->shadoworigin, p, relativepoint);
6094 dist2 = VectorLength2(relativepoint);
6095 if (dist2 >= lightradius2)
6097 dist = sqrt(dist2) / light->radius;
6098 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6099 if (intensity <= 0.0f)
6101 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)
6103 for (q = 0; q < 3; q++)
6104 color[q] = light->currentcolor[q] * intensity;
6105 intensity = VectorLength(color);
6106 VectorNormalize(relativepoint);
6107 for (q = 0; q < 3; q++)
6109 sa[q] += 0.5f * color[q];
6110 sx[q] += relativepoint[0] * color[q];
6111 sy[q] += relativepoint[1] * color[q];
6112 sz[q] += relativepoint[2] * color[q];
6113 sd[q] += intensity * relativepoint[q];
6116 // FIXME: sample bouncegrid too!
6119 if (flags & LP_DYNLIGHT)
6122 for (i = 0;i < r_refdef.scene.numlights;i++)
6124 light = r_refdef.scene.lights[i];
6126 lightradius2 = light->radius * light->radius;
6127 VectorSubtract(light->shadoworigin, p, relativepoint);
6128 dist2 = VectorLength2(relativepoint);
6129 if (dist2 >= lightradius2)
6131 dist = sqrt(dist2) / light->radius;
6132 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6133 if (intensity <= 0.0f)
6135 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)
6137 for (q = 0; q < 3; q++)
6138 color[q] = light->currentcolor[q] * intensity;
6139 intensity = VectorLength(color);
6140 VectorNormalize(relativepoint);
6141 for (q = 0; q < 3; q++)
6143 sa[q] += 0.5f * color[q];
6144 sx[q] += relativepoint[0] * color[q];
6145 sy[q] += relativepoint[1] * color[q];
6146 sz[q] += relativepoint[2] * color[q];
6147 sd[q] += intensity * relativepoint[q];
6152 // calculate the weighted-average light direction (bentnormal)
6153 for (q = 0; q < 3; q++)
6154 lightdir[q] = sd[q];
6155 VectorNormalize(lightdir);
6156 for (q = 0; q < 3; q++)
6158 // extract the diffuse color along the chosen direction and scale it
6159 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6160 // subtract some of diffuse from ambient
6161 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;