3 #include "cl_collision.h"
7 static void R_Shadow_EditLights_Init(void);
9 typedef enum r_shadow_rendermode_e
11 R_SHADOW_RENDERMODE_NONE,
12 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
13 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
14 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
15 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
16 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
17 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
18 R_SHADOW_RENDERMODE_LIGHT_GLSL,
19 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
20 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
21 R_SHADOW_RENDERMODE_SHADOWMAP2D
23 r_shadow_rendermode_t;
25 typedef enum r_shadow_shadowmode_e
27 R_SHADOW_SHADOWMODE_SHADOWMAP2D
29 r_shadow_shadowmode_t;
31 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
32 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
33 int r_shadow_scenemaxlights;
34 int r_shadow_scenenumlights;
35 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
36 qboolean r_shadow_usingshadowmap2d;
37 qboolean r_shadow_usingshadowmaportho;
38 int r_shadow_shadowmapside;
39 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
40 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
41 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
42 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
44 int r_shadow_drawbuffer;
45 int r_shadow_readbuffer;
47 int r_shadow_cullface_front, r_shadow_cullface_back;
48 GLuint r_shadow_fbo2d;
49 r_shadow_shadowmode_t r_shadow_shadowmode;
50 int r_shadow_shadowmapfilterquality;
51 int r_shadow_shadowmapdepthbits;
52 int r_shadow_shadowmapmaxsize;
53 int r_shadow_shadowmaptexturesize;
54 qboolean r_shadow_shadowmapvsdct;
55 qboolean r_shadow_shadowmapsampler;
56 qboolean r_shadow_shadowmapshadowsampler;
57 int r_shadow_shadowmappcf;
58 int r_shadow_shadowmapborder;
59 matrix4x4_t r_shadow_shadowmapmatrix;
60 int r_shadow_lightscissor[4];
61 qboolean r_shadow_usingdeferredprepass;
62 qboolean r_shadow_shadowmapdepthtexture;
63 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
64 int r_shadow_shadowmapatlas_modelshadows_x;
65 int r_shadow_shadowmapatlas_modelshadows_y;
66 int r_shadow_shadowmapatlas_modelshadows_size;
67 int maxshadowtriangles;
70 int maxshadowvertices;
71 float *shadowvertex3f;
81 unsigned char *shadowsides;
89 int r_shadow_buffer_numleafpvsbytes;
90 unsigned char *r_shadow_buffer_visitingleafpvs;
91 unsigned char *r_shadow_buffer_leafpvs;
92 int *r_shadow_buffer_leaflist;
94 int r_shadow_buffer_numsurfacepvsbytes;
95 unsigned char *r_shadow_buffer_surfacepvs;
96 int *r_shadow_buffer_surfacelist;
97 unsigned char *r_shadow_buffer_surfacesides;
99 int r_shadow_buffer_numshadowtrispvsbytes;
100 unsigned char *r_shadow_buffer_shadowtrispvs;
101 int r_shadow_buffer_numlighttrispvsbytes;
102 unsigned char *r_shadow_buffer_lighttrispvs;
104 rtexturepool_t *r_shadow_texturepool;
105 rtexture_t *r_shadow_attenuationgradienttexture;
106 skinframe_t *r_shadow_lightcorona;
107 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
108 rtexture_t *r_shadow_shadowmap2ddepthtexture;
109 rtexture_t *r_shadow_shadowmapvsdcttexture;
111 GLuint r_shadow_prepassgeometryfbo;
112 GLuint r_shadow_prepasslightingdiffusespecularfbo;
113 GLuint r_shadow_prepasslightingdiffusefbo;
114 int r_shadow_prepass_width;
115 int r_shadow_prepass_height;
116 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
117 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
118 rtexture_t *r_shadow_prepasslightingdiffusetexture;
119 rtexture_t *r_shadow_prepasslightingspeculartexture;
121 int r_shadow_viewfbo;
122 rtexture_t *r_shadow_viewdepthtexture;
123 rtexture_t *r_shadow_viewcolortexture;
126 int r_shadow_viewwidth;
127 int r_shadow_viewheight;
129 // lights are reloaded when this changes
130 char r_shadow_mapname[MAX_QPATH];
132 // buffer for doing corona fading
133 unsigned int r_shadow_occlusion_buf = 0;
135 // used only for light filters (cubemaps)
136 rtexturepool_t *r_shadow_filters_texturepool;
138 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
139 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
140 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
141 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
142 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
143 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
144 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
145 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
146 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
147 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
148 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
149 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
150 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
151 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
152 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
153 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
154 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
155 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
156 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
157 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
158 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
159 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
160 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
161 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
162 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
163 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
164 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
165 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
166 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
167 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
168 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
169 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
170 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
171 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
172 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
173 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
174 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
175 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
176 cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
177 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
178 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
179 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
180 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
181 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
182 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
183 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
184 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
185 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
186 cvar_t r_shadow_culllights_pvs = {CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
187 cvar_t r_shadow_culllights_trace = {CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
188 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
189 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
190 cvar_t r_shadow_culllights_trace_expand = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
191 cvar_t r_shadow_culllights_trace_pad = {CVAR_SAVE, "r_shadow_culllights_trace_pad", "8", "accept traces that hit within this many units of the light bounds"};
192 cvar_t r_shadow_culllights_trace_samples = {CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
193 cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"};
194 cvar_t r_shadow_culllights_trace_delay = {CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
195 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
196 cvar_t r_shadow_bouncegrid_blur = {CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
197 cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"};
198 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color" };
199 cvar_t r_shadow_bouncegrid_dynamic_culllightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_culllightpaths", "1", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
200 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
201 cvar_t r_shadow_bouncegrid_dynamic_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_dlightparticlemultiplier", "1", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
202 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
203 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
204 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
205 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxphotons", "25000", "upper bound on photons to shoot per update, divided proportionately between lights - normally the number of photons is calculated by energyperphoton"};
206 cvar_t r_shadow_bouncegrid_dynamic_quality = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_quality", "1", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)"};
207 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
208 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
209 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
210 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
211 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
212 cvar_t r_shadow_bouncegrid_floatcolors = {CVAR_SAVE, "r_shadow_bouncegrid_floatcolors", "1", "upload texture as RGBA16F (or RGBA32F when set to 2) rather than RGBA8 format - this gives more dynamic range and accuracy"};
213 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
214 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
215 cvar_t r_shadow_bouncegrid_lightpathsize_conespread = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_conespread", "0.015625", "increase lightpathsize over distance at this rate per grid cell"};
216 cvar_t r_shadow_bouncegrid_lightpathsize_initial = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_initial", "0.5", "width (in grid cells) of the light path for accumulation of light in the bouncegrid texture"};
217 cvar_t r_shadow_bouncegrid_normalizevectors = { CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)" };
218 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "2", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
219 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
220 cvar_t r_shadow_bouncegrid_rng_seed = { CVAR_SAVE, "r_shadow_bouncegrid_rng_seed", "0", "0+ = use this number as RNG seed, -1 = use time instead for disco-like craziness in dynamic mode" };
221 cvar_t r_shadow_bouncegrid_rng_type = { CVAR_SAVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)" };
222 cvar_t r_shadow_bouncegrid_sortlightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_sortlightpaths", "1", "sort light paths before accumulating them into the bouncegrid texture, this reduces cpu cache misses"};
223 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
224 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color" };
225 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
226 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
227 cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
228 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
229 cvar_t r_shadow_bouncegrid_static_quality = { CVAR_SAVE, "r_shadow_bouncegrid_static_quality", "16", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)" };
230 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
231 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
232 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
233 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"};
234 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
235 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
236 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
237 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
238 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
239 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
240 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
241 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
242 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
243 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
244 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
245 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
246 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
247 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
248 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
249 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
250 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
251 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
252 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
253 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
254 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
255 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
257 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
259 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
260 #define ATTENTABLESIZE 256
261 // 1D gradient, 2D circle and 3D sphere attenuation textures
262 #define ATTEN1DSIZE 32
263 #define ATTEN2DSIZE 64
264 #define ATTEN3DSIZE 32
266 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
267 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
268 static float r_shadow_attentable[ATTENTABLESIZE+1];
270 rtlight_t *r_shadow_compilingrtlight;
271 static memexpandablearray_t r_shadow_worldlightsarray;
272 dlight_t *r_shadow_selectedlight;
273 dlight_t r_shadow_bufferlight;
274 vec3_t r_editlights_cursorlocation;
275 qboolean r_editlights_lockcursor;
277 extern int con_vislines;
279 void R_Shadow_UncompileWorldLights(void);
280 void R_Shadow_ClearWorldLights(void);
281 void R_Shadow_SaveWorldLights(void);
282 void R_Shadow_LoadWorldLights(void);
283 void R_Shadow_LoadLightsFile(void);
284 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
285 void R_Shadow_EditLights_Reload_f(void);
286 static void R_Shadow_MakeTextures(void);
288 #define EDLIGHTSPRSIZE 8
289 skinframe_t *r_editlights_sprcursor;
290 skinframe_t *r_editlights_sprlight;
291 skinframe_t *r_editlights_sprnoshadowlight;
292 skinframe_t *r_editlights_sprcubemaplight;
293 skinframe_t *r_editlights_sprcubemapnoshadowlight;
294 skinframe_t *r_editlights_sprselection;
296 static void R_Shadow_DrawModelShadowMaps(void);
297 static void R_Shadow_MakeShadowMap(int texturesize);
298 static void R_Shadow_MakeVSDCT(void);
299 static void R_Shadow_SetShadowMode(void)
301 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
302 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
303 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
304 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
305 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
306 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
307 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
308 r_shadow_shadowmapsampler = false;
309 r_shadow_shadowmappcf = 0;
310 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
311 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
312 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
313 if (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)
315 switch(vid.renderpath)
317 case RENDERPATH_GL32:
318 if(r_shadow_shadowmapfilterquality < 0)
320 if (!r_fb.usedepthtextures)
321 r_shadow_shadowmappcf = 1;
322 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
324 r_shadow_shadowmapsampler = true;
325 r_shadow_shadowmappcf = 1;
327 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
328 r_shadow_shadowmappcf = 1;
329 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
330 r_shadow_shadowmappcf = 1;
332 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
336 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
337 switch (r_shadow_shadowmapfilterquality)
342 r_shadow_shadowmappcf = 1;
345 r_shadow_shadowmappcf = 1;
348 r_shadow_shadowmappcf = 2;
352 if (!r_fb.usedepthtextures)
353 r_shadow_shadowmapsampler = false;
354 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
356 case RENDERPATH_GLES2:
361 if(R_CompileShader_CheckStaticParms())
365 qboolean R_Shadow_ShadowMappingEnabled(void)
367 switch (r_shadow_shadowmode)
369 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
376 static void R_Shadow_FreeShadowMaps(void)
378 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
380 R_Shadow_SetShadowMode();
382 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
386 if (r_shadow_shadowmap2ddepthtexture)
387 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
388 r_shadow_shadowmap2ddepthtexture = NULL;
390 if (r_shadow_shadowmap2ddepthbuffer)
391 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
392 r_shadow_shadowmap2ddepthbuffer = NULL;
394 if (r_shadow_shadowmapvsdcttexture)
395 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
396 r_shadow_shadowmapvsdcttexture = NULL;
399 static void r_shadow_start(void)
401 // allocate vertex processing arrays
402 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
403 r_shadow_attenuationgradienttexture = NULL;
404 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
405 r_shadow_shadowmap2ddepthtexture = NULL;
406 r_shadow_shadowmap2ddepthbuffer = NULL;
407 r_shadow_shadowmapvsdcttexture = NULL;
408 r_shadow_shadowmapmaxsize = 0;
409 r_shadow_shadowmaptexturesize = 0;
410 r_shadow_shadowmapfilterquality = -1;
411 r_shadow_shadowmapdepthbits = 0;
412 r_shadow_shadowmapvsdct = false;
413 r_shadow_shadowmapsampler = false;
414 r_shadow_shadowmappcf = 0;
417 R_Shadow_FreeShadowMaps();
419 r_shadow_texturepool = NULL;
420 r_shadow_filters_texturepool = NULL;
421 R_Shadow_MakeTextures();
422 r_shadow_scenemaxlights = 0;
423 r_shadow_scenenumlights = 0;
424 r_shadow_scenelightlist = NULL;
425 maxshadowtriangles = 0;
426 shadowelements = NULL;
427 maxshadowvertices = 0;
428 shadowvertex3f = NULL;
436 shadowmarklist = NULL;
441 shadowsideslist = NULL;
442 r_shadow_buffer_numleafpvsbytes = 0;
443 r_shadow_buffer_visitingleafpvs = NULL;
444 r_shadow_buffer_leafpvs = NULL;
445 r_shadow_buffer_leaflist = NULL;
446 r_shadow_buffer_numsurfacepvsbytes = 0;
447 r_shadow_buffer_surfacepvs = NULL;
448 r_shadow_buffer_surfacelist = NULL;
449 r_shadow_buffer_surfacesides = NULL;
450 r_shadow_buffer_numshadowtrispvsbytes = 0;
451 r_shadow_buffer_shadowtrispvs = NULL;
452 r_shadow_buffer_numlighttrispvsbytes = 0;
453 r_shadow_buffer_lighttrispvs = NULL;
455 r_shadow_usingdeferredprepass = false;
456 r_shadow_prepass_width = r_shadow_prepass_height = 0;
458 // determine renderpath specific capabilities, we don't need to figure
459 // these out per frame...
460 switch(vid.renderpath)
462 case RENDERPATH_GL32:
463 r_shadow_bouncegrid_state.allowdirectionalshading = true;
464 r_shadow_bouncegrid_state.capable = true;
466 case RENDERPATH_GLES2:
467 // for performance reasons, do not use directional shading on GLES devices
468 r_shadow_bouncegrid_state.capable = true;
473 static void R_Shadow_FreeDeferred(void);
474 static void r_shadow_shutdown(void)
477 R_Shadow_UncompileWorldLights();
479 R_Shadow_FreeShadowMaps();
481 r_shadow_usingdeferredprepass = false;
482 if (r_shadow_prepass_width)
483 R_Shadow_FreeDeferred();
484 r_shadow_prepass_width = r_shadow_prepass_height = 0;
487 r_shadow_scenemaxlights = 0;
488 r_shadow_scenenumlights = 0;
489 if (r_shadow_scenelightlist)
490 Mem_Free(r_shadow_scenelightlist);
491 r_shadow_scenelightlist = NULL;
492 r_shadow_bouncegrid_state.highpixels = NULL;
493 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
494 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
495 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
496 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
497 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
498 r_shadow_bouncegrid_state.maxsplatpaths = 0;
499 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
500 r_shadow_attenuationgradienttexture = NULL;
501 R_FreeTexturePool(&r_shadow_texturepool);
502 R_FreeTexturePool(&r_shadow_filters_texturepool);
503 maxshadowtriangles = 0;
505 Mem_Free(shadowelements);
506 shadowelements = NULL;
508 Mem_Free(shadowvertex3f);
509 shadowvertex3f = NULL;
512 Mem_Free(vertexupdate);
515 Mem_Free(vertexremap);
521 Mem_Free(shadowmark);
524 Mem_Free(shadowmarklist);
525 shadowmarklist = NULL;
530 Mem_Free(shadowsides);
533 Mem_Free(shadowsideslist);
534 shadowsideslist = NULL;
535 r_shadow_buffer_numleafpvsbytes = 0;
536 if (r_shadow_buffer_visitingleafpvs)
537 Mem_Free(r_shadow_buffer_visitingleafpvs);
538 r_shadow_buffer_visitingleafpvs = NULL;
539 if (r_shadow_buffer_leafpvs)
540 Mem_Free(r_shadow_buffer_leafpvs);
541 r_shadow_buffer_leafpvs = NULL;
542 if (r_shadow_buffer_leaflist)
543 Mem_Free(r_shadow_buffer_leaflist);
544 r_shadow_buffer_leaflist = NULL;
545 r_shadow_buffer_numsurfacepvsbytes = 0;
546 if (r_shadow_buffer_surfacepvs)
547 Mem_Free(r_shadow_buffer_surfacepvs);
548 r_shadow_buffer_surfacepvs = NULL;
549 if (r_shadow_buffer_surfacelist)
550 Mem_Free(r_shadow_buffer_surfacelist);
551 r_shadow_buffer_surfacelist = NULL;
552 if (r_shadow_buffer_surfacesides)
553 Mem_Free(r_shadow_buffer_surfacesides);
554 r_shadow_buffer_surfacesides = NULL;
555 r_shadow_buffer_numshadowtrispvsbytes = 0;
556 if (r_shadow_buffer_shadowtrispvs)
557 Mem_Free(r_shadow_buffer_shadowtrispvs);
558 r_shadow_buffer_numlighttrispvsbytes = 0;
559 if (r_shadow_buffer_lighttrispvs)
560 Mem_Free(r_shadow_buffer_lighttrispvs);
563 static void r_shadow_newmap(void)
565 r_shadow_bouncegrid_state.highpixels = NULL;
566 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
567 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
568 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
569 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
570 if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
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);
2809 // trace the photons from lights and accumulate illumination
2810 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
2812 // clear the texture
2813 R_Shadow_BounceGrid_ClearPixels();
2815 // accumulate the light splatting into texture
2816 R_Shadow_BounceGrid_PerformSplats();
2818 // apply a mild blur filter to the texture
2819 R_Shadow_BounceGrid_BlurPixels();
2821 // convert the pixels to lower precision and upload the texture
2822 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2824 // after we compute the static lighting we don't need to keep the highpixels array around
2825 if (settings.staticmode)
2827 r_shadow_bouncegrid_state.highpixels = NULL;
2828 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2829 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2830 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2831 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2832 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2833 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2837 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2839 R_Shadow_RenderMode_Reset();
2840 GL_BlendFunc(GL_ONE, GL_ONE);
2841 GL_DepthRange(0, 1);
2842 GL_DepthTest(r_showlighting.integer < 2);
2843 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2845 GL_DepthFunc(GL_EQUAL);
2846 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2849 void R_Shadow_RenderMode_End(void)
2851 R_Shadow_RenderMode_Reset();
2852 R_Shadow_RenderMode_ActiveLight(NULL);
2854 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2855 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2858 int bboxedges[12][2] =
2877 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2879 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2881 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2882 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2883 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2884 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2887 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2888 return true; // invisible
2889 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2890 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2891 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2892 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2893 r_refdef.stats[r_stat_lights_scissored]++;
2897 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2899 // used to display how many times a surface is lit for level design purposes
2900 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2901 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2905 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])
2907 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2908 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2912 extern cvar_t gl_lightmaps;
2913 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2916 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2917 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2918 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2919 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2920 if (!r_shadow_usenormalmap.integer)
2922 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2923 VectorClear(diffusecolor);
2924 VectorClear(specularcolor);
2926 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2927 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2928 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2929 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2931 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2934 VectorNegate(ambientcolor, ambientcolor);
2935 VectorNegate(diffusecolor, diffusecolor);
2936 VectorNegate(specularcolor, specularcolor);
2937 GL_BlendEquationSubtract(true);
2939 RSurf_SetupDepthAndCulling();
2940 switch (r_shadow_rendermode)
2942 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2943 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2944 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2946 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2947 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2950 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2954 GL_BlendEquationSubtract(false);
2957 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)
2959 matrix4x4_t tempmatrix = *matrix;
2960 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2962 // if this light has been compiled before, free the associated data
2963 R_RTLight_Uncompile(rtlight);
2965 // clear it completely to avoid any lingering data
2966 memset(rtlight, 0, sizeof(*rtlight));
2968 // copy the properties
2969 rtlight->matrix_lighttoworld = tempmatrix;
2970 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2971 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2972 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2973 VectorCopy(color, rtlight->color);
2974 rtlight->cubemapname[0] = 0;
2975 if (cubemapname && cubemapname[0])
2976 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2977 rtlight->shadow = shadow;
2978 rtlight->corona = corona;
2979 rtlight->style = style;
2980 rtlight->isstatic = isstatic;
2981 rtlight->coronasizescale = coronasizescale;
2982 rtlight->ambientscale = ambientscale;
2983 rtlight->diffusescale = diffusescale;
2984 rtlight->specularscale = specularscale;
2985 rtlight->flags = flags;
2987 // compute derived data
2988 //rtlight->cullradius = rtlight->radius;
2989 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2990 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2991 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2992 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2993 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2994 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2995 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2998 // compiles rtlight geometry
2999 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3000 void R_RTLight_Compile(rtlight_t *rtlight)
3003 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3004 int lighttris, shadowtris;
3005 entity_render_t *ent = r_refdef.scene.worldentity;
3006 dp_model_t *model = r_refdef.scene.worldmodel;
3007 unsigned char *data;
3009 // compile the light
3010 rtlight->compiled = true;
3011 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3012 rtlight->static_numleafs = 0;
3013 rtlight->static_numleafpvsbytes = 0;
3014 rtlight->static_leaflist = NULL;
3015 rtlight->static_leafpvs = NULL;
3016 rtlight->static_numsurfaces = 0;
3017 rtlight->static_surfacelist = NULL;
3018 rtlight->static_shadowmap_receivers = 0x3F;
3019 rtlight->static_shadowmap_casters = 0x3F;
3020 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3021 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3022 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3023 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3024 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3025 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3027 if (model && model->GetLightInfo)
3029 // this variable must be set for the CompileShadowMap code
3030 r_shadow_compilingrtlight = rtlight;
3031 R_FrameData_SetMark();
3032 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);
3033 R_FrameData_ReturnToMark();
3034 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3035 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3036 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3037 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3038 rtlight->static_numsurfaces = numsurfaces;
3039 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3040 rtlight->static_numleafs = numleafs;
3041 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3042 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3043 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3044 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3045 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3046 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3047 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3048 if (rtlight->static_numsurfaces)
3049 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3050 if (rtlight->static_numleafs)
3051 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3052 if (rtlight->static_numleafpvsbytes)
3053 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3054 if (rtlight->static_numshadowtrispvsbytes)
3055 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3056 if (rtlight->static_numlighttrispvsbytes)
3057 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3058 R_FrameData_SetMark();
3059 if (model->CompileShadowMap && rtlight->shadow)
3060 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3061 R_FrameData_ReturnToMark();
3062 // now we're done compiling the rtlight
3063 r_shadow_compilingrtlight = NULL;
3067 // use smallest available cullradius - box radius or light radius
3068 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3069 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3072 if (rtlight->static_numlighttrispvsbytes)
3073 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3074 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3078 if (rtlight->static_numshadowtrispvsbytes)
3079 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3080 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3083 if (developer_extra.integer)
3084 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);
3087 void R_RTLight_Uncompile(rtlight_t *rtlight)
3089 if (rtlight->compiled)
3091 if (rtlight->static_meshchain_shadow_shadowmap)
3092 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3093 rtlight->static_meshchain_shadow_shadowmap = NULL;
3094 // these allocations are grouped
3095 if (rtlight->static_surfacelist)
3096 Mem_Free(rtlight->static_surfacelist);
3097 rtlight->static_numleafs = 0;
3098 rtlight->static_numleafpvsbytes = 0;
3099 rtlight->static_leaflist = NULL;
3100 rtlight->static_leafpvs = NULL;
3101 rtlight->static_numsurfaces = 0;
3102 rtlight->static_surfacelist = NULL;
3103 rtlight->static_numshadowtrispvsbytes = 0;
3104 rtlight->static_shadowtrispvs = NULL;
3105 rtlight->static_numlighttrispvsbytes = 0;
3106 rtlight->static_lighttrispvs = NULL;
3107 rtlight->compiled = false;
3111 void R_Shadow_UncompileWorldLights(void)
3115 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3116 for (lightindex = 0;lightindex < range;lightindex++)
3118 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3121 R_RTLight_Uncompile(&light->rtlight);
3125 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3129 // reset the count of frustum planes
3130 // see rtlight->cached_frustumplanes definition for how much this array
3132 rtlight->cached_numfrustumplanes = 0;
3134 if (r_trippy.integer)
3137 // haven't implemented a culling path for ortho rendering
3138 if (!r_refdef.view.useperspective)
3140 // check if the light is on screen and copy the 4 planes if it is
3141 for (i = 0;i < 4;i++)
3142 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3145 for (i = 0;i < 4;i++)
3146 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3151 // generate a deformed frustum that includes the light origin, this is
3152 // used to cull shadow casting surfaces that can not possibly cast a
3153 // shadow onto the visible light-receiving surfaces, which can be a
3156 // if the light origin is onscreen the result will be 4 planes exactly
3157 // if the light origin is offscreen on only one axis the result will
3158 // be exactly 5 planes (split-side case)
3159 // if the light origin is offscreen on two axes the result will be
3160 // exactly 4 planes (stretched corner case)
3161 for (i = 0;i < 4;i++)
3163 // quickly reject standard frustum planes that put the light
3164 // origin outside the frustum
3165 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3168 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3170 // if all the standard frustum planes were accepted, the light is onscreen
3171 // otherwise we need to generate some more planes below...
3172 if (rtlight->cached_numfrustumplanes < 4)
3174 // at least one of the stock frustum planes failed, so we need to
3175 // create one or two custom planes to enclose the light origin
3176 for (i = 0;i < 4;i++)
3178 // create a plane using the view origin and light origin, and a
3179 // single point from the frustum corner set
3180 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3181 VectorNormalize(plane.normal);
3182 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3183 // see if this plane is backwards and flip it if so
3184 for (j = 0;j < 4;j++)
3185 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3189 VectorNegate(plane.normal, plane.normal);
3191 // flipped plane, test again to see if it is now valid
3192 for (j = 0;j < 4;j++)
3193 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3195 // if the plane is still not valid, then it is dividing the
3196 // frustum and has to be rejected
3200 // we have created a valid plane, compute extra info
3201 PlaneClassify(&plane);
3203 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3205 // if we've found 5 frustum planes then we have constructed a
3206 // proper split-side case and do not need to keep searching for
3207 // planes to enclose the light origin
3208 if (rtlight->cached_numfrustumplanes == 5)
3216 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3218 plane = rtlight->cached_frustumplanes[i];
3219 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));
3224 // now add the light-space box planes if the light box is rotated, as any
3225 // caster outside the oriented light box is irrelevant (even if it passed
3226 // the worldspace light box, which is axial)
3227 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3229 for (i = 0;i < 6;i++)
3233 v[i >> 1] = (i & 1) ? -1 : 1;
3234 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3235 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3236 plane.dist = VectorNormalizeLength(plane.normal);
3237 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3238 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3244 // add the world-space reduced box planes
3245 for (i = 0;i < 6;i++)
3247 VectorClear(plane.normal);
3248 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3249 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3250 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3259 // reduce all plane distances to tightly fit the rtlight cull box, which
3261 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3262 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3263 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3264 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3265 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3266 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3267 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3268 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3269 oldnum = rtlight->cached_numfrustumplanes;
3270 rtlight->cached_numfrustumplanes = 0;
3271 for (j = 0;j < oldnum;j++)
3273 // find the nearest point on the box to this plane
3274 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3275 for (i = 1;i < 8;i++)
3277 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3278 if (bestdist > dist)
3281 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);
3282 // if the nearest point is near or behind the plane, we want this
3283 // plane, otherwise the plane is useless as it won't cull anything
3284 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3286 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3287 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3294 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3296 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3298 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3300 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3301 if (mesh->sidetotals[r_shadow_shadowmapside])
3304 GL_CullFace(GL_NONE);
3305 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3306 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3307 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);
3311 else if (r_refdef.scene.worldentity->model)
3312 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);
3314 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3317 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3319 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3320 vec_t relativeshadowradius;
3321 RSurf_ActiveModelEntity(ent, false, false, false);
3322 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3323 // we need to re-init the shader for each entity because the matrix changed
3324 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3325 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3326 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3327 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3328 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3329 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3330 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3331 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3332 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3335 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3337 // set up properties for rendering light onto this entity
3338 RSurf_ActiveModelEntity(ent, true, true, false);
3339 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3340 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3341 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3342 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3345 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3347 if (!r_refdef.scene.worldmodel->DrawLight)
3350 // set up properties for rendering light onto this entity
3351 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3352 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3353 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3354 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3355 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3357 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3359 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3362 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3364 dp_model_t *model = ent->model;
3365 if (!model->DrawLight)
3368 R_Shadow_SetupEntityLight(ent);
3370 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3372 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3375 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3379 int numleafs, numsurfaces;
3380 int *leaflist, *surfacelist;
3381 unsigned char *leafpvs;
3382 unsigned char *shadowtrispvs;
3383 unsigned char *lighttrispvs;
3384 //unsigned char *surfacesides;
3385 int numlightentities;
3386 int numlightentities_noselfshadow;
3387 int numshadowentities;
3388 int numshadowentities_noselfshadow;
3389 // FIXME: bounds check lightentities and shadowentities, etc.
3390 static entity_render_t *lightentities[MAX_EDICTS];
3391 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3392 static entity_render_t *shadowentities[MAX_EDICTS];
3393 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3395 qboolean castshadows;
3397 rtlight->draw = false;
3398 rtlight->cached_numlightentities = 0;
3399 rtlight->cached_numlightentities_noselfshadow = 0;
3400 rtlight->cached_numshadowentities = 0;
3401 rtlight->cached_numshadowentities_noselfshadow = 0;
3402 rtlight->cached_numsurfaces = 0;
3403 rtlight->cached_lightentities = NULL;
3404 rtlight->cached_lightentities_noselfshadow = NULL;
3405 rtlight->cached_shadowentities = NULL;
3406 rtlight->cached_shadowentities_noselfshadow = NULL;
3407 rtlight->cached_shadowtrispvs = NULL;
3408 rtlight->cached_lighttrispvs = NULL;
3409 rtlight->cached_surfacelist = NULL;
3410 rtlight->shadowmapsidesize = 0;
3412 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3413 // skip lights that are basically invisible (color 0 0 0)
3414 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3416 // loading is done before visibility checks because loading should happen
3417 // all at once at the start of a level, not when it stalls gameplay.
3418 // (especially important to benchmarks)
3420 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3422 if (rtlight->compiled)
3423 R_RTLight_Uncompile(rtlight);
3424 R_RTLight_Compile(rtlight);
3428 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3430 // look up the light style value at this time
3431 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3432 VectorScale(rtlight->color, f, rtlight->currentcolor);
3434 if (rtlight->selected)
3436 f = 2 + sin(realtime * M_PI * 4.0);
3437 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3441 // skip if lightstyle is currently off
3442 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3445 // skip processing on corona-only lights
3449 // skip if the light box is not touching any visible leafs
3450 if (r_shadow_culllights_pvs.integer
3451 && r_refdef.scene.worldmodel
3452 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3453 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3456 // skip if the light box is not visible to traceline
3457 if (r_shadow_culllights_trace.integer)
3459 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))
3460 rtlight->trace_timer = realtime;
3461 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3465 // skip if the light box is off screen
3466 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3469 // in the typical case this will be quickly replaced by GetLightInfo
3470 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3471 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3473 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3475 // 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
3476 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3479 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3481 // compiled light, world available and can receive realtime lighting
3482 // retrieve leaf information
3483 numleafs = rtlight->static_numleafs;
3484 leaflist = rtlight->static_leaflist;
3485 leafpvs = rtlight->static_leafpvs;
3486 numsurfaces = rtlight->static_numsurfaces;
3487 surfacelist = rtlight->static_surfacelist;
3488 //surfacesides = NULL;
3489 shadowtrispvs = rtlight->static_shadowtrispvs;
3490 lighttrispvs = rtlight->static_lighttrispvs;
3492 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3494 // dynamic light, world available and can receive realtime lighting
3495 // calculate lit surfaces and leafs
3496 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);
3497 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3498 leaflist = r_shadow_buffer_leaflist;
3499 leafpvs = r_shadow_buffer_leafpvs;
3500 surfacelist = r_shadow_buffer_surfacelist;
3501 //surfacesides = r_shadow_buffer_surfacesides;
3502 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3503 lighttrispvs = r_shadow_buffer_lighttrispvs;
3504 // if the reduced leaf bounds are offscreen, skip it
3505 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3516 //surfacesides = NULL;
3517 shadowtrispvs = NULL;
3518 lighttrispvs = NULL;
3520 // check if light is illuminating any visible leafs
3523 for (i = 0; i < numleafs; i++)
3524 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3530 // make a list of lit entities and shadow casting entities
3531 numlightentities = 0;
3532 numlightentities_noselfshadow = 0;
3533 numshadowentities = 0;
3534 numshadowentities_noselfshadow = 0;
3536 // add dynamic entities that are lit by the light
3537 for (i = 0; i < r_refdef.scene.numentities; i++)
3540 entity_render_t *ent = r_refdef.scene.entities[i];
3542 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3544 // skip the object entirely if it is not within the valid
3545 // shadow-casting region (which includes the lit region)
3546 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3548 if (!(model = ent->model))
3550 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3552 // this entity wants to receive light, is visible, and is
3553 // inside the light box
3554 // TODO: check if the surfaces in the model can receive light
3555 // so now check if it's in a leaf seen by the light
3556 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))
3558 if (ent->flags & RENDER_NOSELFSHADOW)
3559 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3561 lightentities[numlightentities++] = ent;
3562 // since it is lit, it probably also casts a shadow...
3563 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3564 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3565 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3567 // note: exterior models without the RENDER_NOSELFSHADOW
3568 // flag still create a RENDER_NOSELFSHADOW shadow but
3569 // are lit normally, this means that they are
3570 // self-shadowing but do not shadow other
3571 // RENDER_NOSELFSHADOW entities such as the gun
3572 // (very weird, but keeps the player shadow off the gun)
3573 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3574 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3576 shadowentities[numshadowentities++] = ent;
3579 else if (ent->flags & RENDER_SHADOW)
3581 // this entity is not receiving light, but may still need to
3583 // TODO: check if the surfaces in the model can cast shadow
3584 // now check if it is in a leaf seen by the light
3585 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))
3587 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3588 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3589 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3591 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3592 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3594 shadowentities[numshadowentities++] = ent;
3599 // return if there's nothing at all to light
3600 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3603 // count this light in the r_speeds
3604 r_refdef.stats[r_stat_lights]++;
3606 // flag it as worth drawing later
3607 rtlight->draw = true;
3609 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3610 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3612 numshadowentities = numshadowentities_noselfshadow = 0;
3613 rtlight->castshadows = castshadows;
3615 // cache all the animated entities that cast a shadow but are not visible
3616 for (i = 0; i < numshadowentities; i++)
3617 R_AnimCache_GetEntity(shadowentities[i], false, false);
3618 for (i = 0; i < numshadowentities_noselfshadow; i++)
3619 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3621 // 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)
3622 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3624 for (i = 0; i < numshadowentities_noselfshadow; i++)
3625 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3626 numshadowentities_noselfshadow = 0;
3629 // we can convert noselfshadow to regular if there are no casters of that type
3630 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3632 for (i = 0; i < numlightentities_noselfshadow; i++)
3633 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3634 numlightentities_noselfshadow = 0;
3637 // allocate some temporary memory for rendering this light later in the frame
3638 // reusable buffers need to be copied, static data can be used as-is
3639 rtlight->cached_numlightentities = numlightentities;
3640 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3641 rtlight->cached_numshadowentities = numshadowentities;
3642 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3643 rtlight->cached_numsurfaces = numsurfaces;
3644 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3645 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3646 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3647 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3648 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3650 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3651 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3652 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3653 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3654 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3658 // compiled light data
3659 rtlight->cached_shadowtrispvs = shadowtrispvs;
3660 rtlight->cached_lighttrispvs = lighttrispvs;
3661 rtlight->cached_surfacelist = surfacelist;
3664 if (R_Shadow_ShadowMappingEnabled())
3666 // figure out the shadowmapping parameters for this light
3667 vec3_t nearestpoint;
3670 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3671 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3672 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3673 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3674 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3675 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3676 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3677 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3678 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3682 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3686 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3687 int numlightentities;
3688 int numlightentities_noselfshadow;
3689 int numshadowentities;
3690 int numshadowentities_noselfshadow;
3691 entity_render_t **lightentities;
3692 entity_render_t **lightentities_noselfshadow;
3693 entity_render_t **shadowentities;
3694 entity_render_t **shadowentities_noselfshadow;
3696 static unsigned char entitysides[MAX_EDICTS];
3697 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3703 matrix4x4_t radiustolight;
3705 // check if we cached this light this frame (meaning it is worth drawing)
3706 if (!rtlight->draw || !rtlight->castshadows)
3709 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3710 if (rtlight->shadowmapatlassidesize == 0)
3712 rtlight->castshadows = false;
3716 // set up a scissor rectangle for this light
3717 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3720 // don't let sound skip if going slow
3721 if (r_refdef.scene.extraupdate)
3724 numlightentities = rtlight->cached_numlightentities;
3725 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3726 numshadowentities = rtlight->cached_numshadowentities;
3727 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3728 numsurfaces = rtlight->cached_numsurfaces;
3729 lightentities = rtlight->cached_lightentities;
3730 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3731 shadowentities = rtlight->cached_shadowentities;
3732 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3733 shadowtrispvs = rtlight->cached_shadowtrispvs;
3734 lighttrispvs = rtlight->cached_lighttrispvs;
3735 surfacelist = rtlight->cached_surfacelist;
3737 // make this the active rtlight for rendering purposes
3738 R_Shadow_RenderMode_ActiveLight(rtlight);
3740 radiustolight = rtlight->matrix_worldtolight;
3741 Matrix4x4_Abs(&radiustolight);
3743 size = rtlight->shadowmapatlassidesize;
3744 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3746 surfacesides = NULL;
3751 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3753 castermask = rtlight->static_shadowmap_casters;
3754 receivermask = rtlight->static_shadowmap_receivers;
3758 surfacesides = r_shadow_buffer_surfacesides;
3759 for (i = 0; i < numsurfaces; i++)
3761 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3762 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3763 castermask |= surfacesides[i];
3764 receivermask |= surfacesides[i];
3769 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3770 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3771 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3772 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3774 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3778 for (i = 0; i < numshadowentities; i++)
3779 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3780 for (i = 0; i < numshadowentities_noselfshadow; i++)
3781 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3784 // there is no need to render shadows for sides that have no receivers...
3785 castermask &= receivermask;
3787 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3789 // render shadow casters into shadowmaps for this light
3790 for (side = 0; side < 6; side++)
3792 int bit = 1 << side;
3793 if (castermask & bit)
3795 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3797 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3798 for (i = 0; i < numshadowentities; i++)
3799 if (entitysides[i] & bit)
3800 R_Shadow_DrawEntityShadow(shadowentities[i]);
3801 for (i = 0; i < numshadowentities_noselfshadow; i++)
3802 if (entitysides_noselfshadow[i] & bit)
3803 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3806 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3807 if (numshadowentities_noselfshadow)
3809 for (side = 0; side < 6; side++)
3811 int bit = 1 << side;
3812 if (castermask & bit)
3814 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3816 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3817 for (i = 0; i < numshadowentities; i++)
3818 if (entitysides[i] & bit)
3819 R_Shadow_DrawEntityShadow(shadowentities[i]);
3825 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3829 unsigned char *shadowtrispvs, *lighttrispvs;
3830 int numlightentities;
3831 int numlightentities_noselfshadow;
3832 int numshadowentities;
3833 int numshadowentities_noselfshadow;
3834 entity_render_t **lightentities;
3835 entity_render_t **lightentities_noselfshadow;
3836 entity_render_t **shadowentities;
3837 entity_render_t **shadowentities_noselfshadow;
3839 qboolean castshadows;
3841 // check if we cached this light this frame (meaning it is worth drawing)
3845 // set up a scissor rectangle for this light
3846 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3849 // don't let sound skip if going slow
3850 if (r_refdef.scene.extraupdate)
3853 numlightentities = rtlight->cached_numlightentities;
3854 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3855 numshadowentities = rtlight->cached_numshadowentities;
3856 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3857 numsurfaces = rtlight->cached_numsurfaces;
3858 lightentities = rtlight->cached_lightentities;
3859 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3860 shadowentities = rtlight->cached_shadowentities;
3861 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3862 shadowtrispvs = rtlight->cached_shadowtrispvs;
3863 lighttrispvs = rtlight->cached_lighttrispvs;
3864 surfacelist = rtlight->cached_surfacelist;
3865 castshadows = rtlight->castshadows;
3867 // make this the active rtlight for rendering purposes
3868 R_Shadow_RenderMode_ActiveLight(rtlight);
3870 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3872 // optionally draw the illuminated areas
3873 // for performance analysis by level designers
3874 R_Shadow_RenderMode_VisibleLighting(false);
3876 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3877 for (i = 0;i < numlightentities;i++)
3878 R_Shadow_DrawEntityLight(lightentities[i]);
3879 for (i = 0;i < numlightentities_noselfshadow;i++)
3880 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3883 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3887 float shadowmapoffsetnoselfshadow = 0;
3888 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3889 Matrix4x4_Abs(&radiustolight);
3891 size = rtlight->shadowmapatlassidesize;
3892 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3894 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3896 if (rtlight->cached_numshadowentities_noselfshadow)
3897 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3899 // render lighting using the depth texture as shadowmap
3900 // draw lighting in the unmasked areas
3901 if (numsurfaces + numlightentities)
3903 R_Shadow_RenderMode_Lighting(false, true, false);
3904 // draw lighting in the unmasked areas
3906 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3907 for (i = 0; i < numlightentities; i++)
3908 R_Shadow_DrawEntityLight(lightentities[i]);
3910 // offset to the noselfshadow part of the atlas and draw those too
3911 if (numlightentities_noselfshadow)
3913 R_Shadow_RenderMode_Lighting(false, true, true);
3914 for (i = 0; i < numlightentities_noselfshadow; i++)
3915 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3918 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3919 if (r_shadow_usingdeferredprepass)
3920 R_Shadow_RenderMode_DrawDeferredLight(true);
3924 // draw lighting in the unmasked areas
3925 R_Shadow_RenderMode_Lighting(false, false, false);
3927 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3928 for (i = 0;i < numlightentities;i++)
3929 R_Shadow_DrawEntityLight(lightentities[i]);
3930 for (i = 0;i < numlightentities_noselfshadow;i++)
3931 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3933 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3934 if (r_shadow_usingdeferredprepass)
3935 R_Shadow_RenderMode_DrawDeferredLight(false);
3939 static void R_Shadow_FreeDeferred(void)
3941 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3942 r_shadow_prepassgeometryfbo = 0;
3944 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3945 r_shadow_prepasslightingdiffusespecularfbo = 0;
3947 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3948 r_shadow_prepasslightingdiffusefbo = 0;
3950 if (r_shadow_prepassgeometrydepthbuffer)
3951 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3952 r_shadow_prepassgeometrydepthbuffer = NULL;
3954 if (r_shadow_prepassgeometrynormalmaptexture)
3955 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3956 r_shadow_prepassgeometrynormalmaptexture = NULL;
3958 if (r_shadow_prepasslightingdiffusetexture)
3959 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3960 r_shadow_prepasslightingdiffusetexture = NULL;
3962 if (r_shadow_prepasslightingspeculartexture)
3963 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3964 r_shadow_prepasslightingspeculartexture = NULL;
3967 void R_Shadow_DrawPrepass(void)
3971 entity_render_t *ent;
3972 float clearcolor[4];
3974 R_Mesh_ResetTextureState();
3976 GL_ColorMask(1,1,1,1);
3977 GL_BlendFunc(GL_ONE, GL_ZERO);
3980 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3981 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3982 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3983 if (r_timereport_active)
3984 R_TimeReport("prepasscleargeom");
3986 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3987 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3988 if (r_timereport_active)
3989 R_TimeReport("prepassworld");
3991 for (i = 0;i < r_refdef.scene.numentities;i++)
3993 if (!r_refdef.viewcache.entityvisible[i])
3995 ent = r_refdef.scene.entities[i];
3996 if (ent->model && ent->model->DrawPrepass != NULL)
3997 ent->model->DrawPrepass(ent);
4000 if (r_timereport_active)
4001 R_TimeReport("prepassmodels");
4003 GL_DepthMask(false);
4004 GL_ColorMask(1,1,1,1);
4007 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4008 Vector4Set(clearcolor, 0, 0, 0, 0);
4009 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4010 if (r_timereport_active)
4011 R_TimeReport("prepassclearlit");
4013 R_Shadow_RenderMode_Begin();
4015 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4016 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4018 R_Shadow_RenderMode_End();
4020 if (r_timereport_active)
4021 R_TimeReport("prepasslights");
4024 #define MAX_SCENELIGHTS 65536
4025 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4027 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4029 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4031 r_shadow_scenemaxlights *= 2;
4032 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4033 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4035 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4039 void R_Shadow_DrawLightSprites(void);
4040 void R_Shadow_PrepareLights(void)
4049 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4050 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4051 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4053 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4054 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4055 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4056 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4057 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4058 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4059 r_shadow_shadowmapborder != shadowmapborder ||
4060 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4061 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4062 R_Shadow_FreeShadowMaps();
4064 r_shadow_usingshadowmaportho = false;
4066 switch (vid.renderpath)
4068 case RENDERPATH_GL32:
4070 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4072 r_shadow_usingdeferredprepass = false;
4073 if (r_shadow_prepass_width)
4074 R_Shadow_FreeDeferred();
4075 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4079 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4081 R_Shadow_FreeDeferred();
4083 r_shadow_usingdeferredprepass = true;
4084 r_shadow_prepass_width = vid.width;
4085 r_shadow_prepass_height = vid.height;
4086 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4087 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);
4088 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);
4089 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);
4091 // set up the geometry pass fbo (depth + normalmap)
4092 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4093 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4094 // render depth into a renderbuffer and other important properties into the normalmap texture
4096 // set up the lighting pass fbo (diffuse + specular)
4097 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4098 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4099 // render diffuse into one texture and specular into another,
4100 // with depth and normalmap bound as textures,
4101 // with depth bound as attachment as well
4103 // set up the lighting pass fbo (diffuse)
4104 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4105 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4106 // render diffuse into one texture,
4107 // with depth and normalmap bound as textures,
4108 // with depth bound as attachment as well
4112 case RENDERPATH_GLES2:
4113 r_shadow_usingdeferredprepass = false;
4117 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);
4119 r_shadow_scenenumlights = 0;
4120 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4121 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4122 for (lightindex = 0; lightindex < range; lightindex++)
4124 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4125 if (light && (light->flags & flag))
4127 R_Shadow_PrepareLight(&light->rtlight);
4128 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4131 if (r_refdef.scene.rtdlight)
4133 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4135 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4136 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4139 else if (gl_flashblend.integer)
4141 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4143 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4144 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4145 VectorScale(rtlight->color, f, rtlight->currentcolor);
4149 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4150 if (r_shadow_debuglight.integer >= 0)
4152 r_shadow_scenenumlights = 0;
4153 lightindex = r_shadow_debuglight.integer;
4154 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4157 R_Shadow_PrepareLight(&light->rtlight);
4158 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4162 // if we're doing shadowmaps we need to prepare the atlas layout now
4163 if (R_Shadow_ShadowMappingEnabled())
4167 // allocate shadowmaps in the atlas now
4168 // 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...
4169 for (lod = 0; lod < 16; lod++)
4171 int packing_success = 0;
4172 int packing_failure = 0;
4173 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4174 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4175 if (r_shadow_shadowmapatlas_modelshadows_size)
4176 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);
4177 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4179 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4180 int size = rtlight->shadowmapsidesize >> lod;
4182 if (!rtlight->castshadows)
4184 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4187 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4188 if (rtlight->cached_numshadowentities_noselfshadow)
4190 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4192 rtlight->shadowmapatlassidesize = size;
4197 // note down that we failed to pack this one, it will have to disable shadows
4198 rtlight->shadowmapatlassidesize = 0;
4202 // generally everything fits and we stop here on the first iteration
4203 if (packing_failure == 0)
4208 if (r_editlights.integer)
4209 R_Shadow_DrawLightSprites();
4212 void R_Shadow_DrawShadowMaps(void)
4214 R_Shadow_RenderMode_Begin();
4215 R_Shadow_RenderMode_ActiveLight(NULL);
4217 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4218 R_Shadow_ClearShadowMapTexture();
4220 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4221 if (r_shadow_shadowmapatlas_modelshadows_size)
4223 R_Shadow_DrawModelShadowMaps();
4224 // don't let sound skip if going slow
4225 if (r_refdef.scene.extraupdate)
4229 if (R_Shadow_ShadowMappingEnabled())
4232 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4233 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4236 R_Shadow_RenderMode_End();
4239 void R_Shadow_DrawLights(void)
4243 R_Shadow_RenderMode_Begin();
4245 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4246 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4248 R_Shadow_RenderMode_End();
4251 #define MAX_MODELSHADOWS 1024
4252 static int r_shadow_nummodelshadows;
4253 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4255 void R_Shadow_PrepareModelShadows(void)
4258 float scale, size, radius, dot1, dot2;
4259 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4260 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4261 entity_render_t *ent;
4263 r_shadow_nummodelshadows = 0;
4264 r_shadow_shadowmapatlas_modelshadows_size = 0;
4266 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4269 size = r_shadow_shadowmaptexturesize / 4;
4270 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4271 radius = 0.5f * size / scale;
4273 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4274 VectorCopy(prvmshadowdir, shadowdir);
4275 VectorNormalize(shadowdir);
4276 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4277 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4278 if (fabs(dot1) <= fabs(dot2))
4279 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4281 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4282 VectorNormalize(shadowforward);
4283 CrossProduct(shadowdir, shadowforward, shadowright);
4284 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4285 VectorCopy(prvmshadowfocus, shadowfocus);
4286 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4287 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4288 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4289 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4290 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4292 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4294 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4295 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4296 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4297 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4298 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4299 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4301 for (i = 0; i < r_refdef.scene.numentities; i++)
4303 ent = r_refdef.scene.entities[i];
4304 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4306 // cast shadows from anything of the map (submodels are optional)
4307 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4309 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4311 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4312 R_AnimCache_GetEntity(ent, false, false);
4316 if (r_shadow_nummodelshadows)
4318 r_shadow_shadowmapatlas_modelshadows_x = 0;
4319 r_shadow_shadowmapatlas_modelshadows_y = 0;
4320 r_shadow_shadowmapatlas_modelshadows_size = size;
4324 static void R_Shadow_DrawModelShadowMaps(void)
4327 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4328 entity_render_t *ent;
4329 vec3_t relativelightorigin;
4330 vec3_t relativelightdirection, relativeforward, relativeright;
4331 vec3_t relativeshadowmins, relativeshadowmaxs;
4332 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4333 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4335 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4336 r_viewport_t viewport;
4338 size = r_shadow_shadowmapatlas_modelshadows_size;
4339 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4340 radius = 0.5f / scale;
4341 nearclip = -r_shadows_throwdistance.value;
4342 farclip = r_shadows_throwdistance.value;
4343 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);
4345 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4346 r_shadow_modelshadowmap_parameters[0] = size;
4347 r_shadow_modelshadowmap_parameters[1] = size;
4348 r_shadow_modelshadowmap_parameters[2] = 1.0;
4349 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4350 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4351 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4352 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4353 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4354 r_shadow_usingshadowmaportho = true;
4356 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4357 VectorCopy(prvmshadowdir, shadowdir);
4358 VectorNormalize(shadowdir);
4359 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4360 VectorCopy(prvmshadowfocus, shadowfocus);
4361 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4362 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4363 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4364 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4365 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4366 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4367 if (fabs(dot1) <= fabs(dot2))
4368 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4370 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4371 VectorNormalize(shadowforward);
4372 VectorM(scale, shadowforward, &m[0]);
4373 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4375 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4376 CrossProduct(shadowdir, shadowforward, shadowright);
4377 VectorM(scale, shadowright, &m[4]);
4378 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4379 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4380 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4381 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4382 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4383 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);
4384 R_SetViewport(&viewport);
4386 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4388 // render into a slightly restricted region so that the borders of the
4389 // shadowmap area fade away, rather than streaking across everything
4390 // outside the usable area
4391 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4393 for (i = 0;i < r_shadow_nummodelshadows;i++)
4395 ent = r_shadow_modelshadows[i];
4396 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4397 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4398 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4399 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4400 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4401 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4402 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4403 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4404 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4405 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4406 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4407 RSurf_ActiveModelEntity(ent, false, false, false);
4408 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4409 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4415 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4417 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4419 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4420 Cvar_SetValueQuick(&r_test, 0);
4425 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4426 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4427 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4428 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4429 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4430 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4433 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4436 vec3_t centerorigin;
4440 // if it's too close, skip it
4441 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4443 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4446 if (usequery && r_numqueries + 2 <= r_maxqueries)
4448 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4449 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4450 // 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
4451 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4453 switch(vid.renderpath)
4455 case RENDERPATH_GL32:
4456 case RENDERPATH_GLES2:
4459 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4460 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4461 GL_DepthFunc(GL_ALWAYS);
4462 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4463 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4464 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4465 qglEndQuery(GL_SAMPLES_PASSED);
4466 GL_DepthFunc(GL_LEQUAL);
4467 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4468 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, 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);
4477 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4480 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4482 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4485 unsigned int occlude = 0;
4487 // now we have to check the query result
4488 if (rtlight->corona_queryindex_visiblepixels)
4490 switch(vid.renderpath)
4492 case RENDERPATH_GL32:
4493 case RENDERPATH_GLES2:
4495 // store the pixel counts into a uniform buffer for the shader to
4496 // use - we'll never know the results on the cpu without
4497 // synchronizing and we don't want that
4498 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4499 if (!r_shadow_occlusion_buf) {
4500 qglGenBuffers(1, &r_shadow_occlusion_buf);
4501 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4502 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4504 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4506 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4507 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4508 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4509 occlude = MATERIALFLAG_OCCLUDE;
4510 cscale *= rtlight->corona_visibility;
4520 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4523 VectorScale(rtlight->currentcolor, cscale, color);
4524 if (VectorLength(color) > (1.0f / 256.0f))
4527 qboolean negated = (color[0] + color[1] + color[2] < 0);
4530 VectorNegate(color, color);
4531 GL_BlendEquationSubtract(true);
4533 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4534 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);
4535 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
4537 GL_BlendEquationSubtract(false);
4541 void R_Shadow_DrawCoronas(void)
4544 qboolean usequery = false;
4549 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4551 if (r_fb.water.renderingscene)
4553 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4554 R_EntityMatrix(&identitymatrix);
4556 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4558 // check occlusion of coronas, using occlusion queries or raytraces
4560 switch (vid.renderpath)
4562 case RENDERPATH_GL32:
4563 case RENDERPATH_GLES2:
4564 usequery = r_coronas_occlusionquery.integer;
4568 GL_ColorMask(0,0,0,0);
4569 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4570 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4573 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4574 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4576 qglGenQueries(r_maxqueries - i, r_queries + i);
4579 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4580 GL_BlendFunc(GL_ONE, GL_ZERO);
4581 GL_CullFace(GL_NONE);
4582 GL_DepthMask(false);
4583 GL_DepthRange(0, 1);
4584 GL_PolygonOffset(0, 0);
4586 R_Mesh_ResetTextureState();
4587 R_SetupShader_Generic_NoTexture(false, false);
4592 for (lightindex = 0;lightindex < range;lightindex++)
4594 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4597 rtlight = &light->rtlight;
4598 rtlight->corona_visibility = 0;
4599 rtlight->corona_queryindex_visiblepixels = 0;
4600 rtlight->corona_queryindex_allpixels = 0;
4601 if (!(rtlight->flags & flag))
4603 if (rtlight->corona <= 0)
4605 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4607 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4609 for (i = 0;i < r_refdef.scene.numlights;i++)
4611 rtlight = r_refdef.scene.lights[i];
4612 rtlight->corona_visibility = 0;
4613 rtlight->corona_queryindex_visiblepixels = 0;
4614 rtlight->corona_queryindex_allpixels = 0;
4615 if (!(rtlight->flags & flag))
4617 if (rtlight->corona <= 0)
4619 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4622 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4624 // now draw the coronas using the query data for intensity info
4625 for (lightindex = 0;lightindex < range;lightindex++)
4627 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4630 rtlight = &light->rtlight;
4631 if (rtlight->corona_visibility <= 0)
4633 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4635 for (i = 0;i < r_refdef.scene.numlights;i++)
4637 rtlight = r_refdef.scene.lights[i];
4638 if (rtlight->corona_visibility <= 0)
4640 if (gl_flashblend.integer)
4641 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4643 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4649 static dlight_t *R_Shadow_NewWorldLight(void)
4651 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4654 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)
4658 // 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
4660 // validate parameters
4664 // copy to light properties
4665 VectorCopy(origin, light->origin);
4666 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4667 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4668 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4670 light->color[0] = max(color[0], 0);
4671 light->color[1] = max(color[1], 0);
4672 light->color[2] = max(color[2], 0);
4674 light->color[0] = color[0];
4675 light->color[1] = color[1];
4676 light->color[2] = color[2];
4677 light->radius = max(radius, 0);
4678 light->style = style;
4679 light->shadow = shadowenable;
4680 light->corona = corona;
4681 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4682 light->coronasizescale = coronasizescale;
4683 light->ambientscale = ambientscale;
4684 light->diffusescale = diffusescale;
4685 light->specularscale = specularscale;
4686 light->flags = flags;
4688 // update renderable light data
4689 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4690 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);
4693 static void R_Shadow_FreeWorldLight(dlight_t *light)
4695 if (r_shadow_selectedlight == light)
4696 r_shadow_selectedlight = NULL;
4697 R_RTLight_Uncompile(&light->rtlight);
4698 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4701 void R_Shadow_ClearWorldLights(void)
4705 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4706 for (lightindex = 0;lightindex < range;lightindex++)
4708 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4710 R_Shadow_FreeWorldLight(light);
4712 r_shadow_selectedlight = NULL;
4715 static void R_Shadow_SelectLight(dlight_t *light)
4717 if (r_shadow_selectedlight)
4718 r_shadow_selectedlight->selected = false;
4719 r_shadow_selectedlight = light;
4720 if (r_shadow_selectedlight)
4721 r_shadow_selectedlight->selected = true;
4724 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4726 // this is never batched (there can be only one)
4728 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4729 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4730 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4733 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4738 skinframe_t *skinframe;
4741 // this is never batched (due to the ent parameter changing every time)
4742 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4743 const dlight_t *light = (dlight_t *)ent;
4746 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4749 VectorScale(light->color, intensity, spritecolor);
4750 if (VectorLength(spritecolor) < 0.1732f)
4751 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4752 if (VectorLength(spritecolor) > 1.0f)
4753 VectorNormalize(spritecolor);
4755 // draw light sprite
4756 if (light->cubemapname[0] && !light->shadow)
4757 skinframe = r_editlights_sprcubemapnoshadowlight;
4758 else if (light->cubemapname[0])
4759 skinframe = r_editlights_sprcubemaplight;
4760 else if (!light->shadow)
4761 skinframe = r_editlights_sprnoshadowlight;
4763 skinframe = r_editlights_sprlight;
4765 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);
4766 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4768 // draw selection sprite if light is selected
4769 if (light->selected)
4771 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4772 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4773 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4777 void R_Shadow_DrawLightSprites(void)
4781 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4782 for (lightindex = 0;lightindex < range;lightindex++)
4784 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4786 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4788 if (!r_editlights_lockcursor)
4789 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4792 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4797 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4798 if (lightindex >= range)
4800 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4803 rtlight = &light->rtlight;
4804 //if (!(rtlight->flags & flag))
4806 VectorCopy(rtlight->shadoworigin, origin);
4807 *radius = rtlight->radius;
4808 VectorCopy(rtlight->color, color);
4812 static void R_Shadow_SelectLightInView(void)
4814 float bestrating, rating, temp[3];
4818 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4822 if (r_editlights_lockcursor)
4824 for (lightindex = 0;lightindex < range;lightindex++)
4826 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4829 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4830 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4833 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4834 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)
4836 bestrating = rating;
4841 R_Shadow_SelectLight(best);
4844 void R_Shadow_LoadWorldLights(void)
4846 int n, a, style, shadow, flags;
4847 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4848 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4849 if (cl.worldmodel == NULL)
4851 Con_Print("No map loaded.\n");
4854 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4855 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4865 for (;COM_Parse(t, true) && strcmp(
4866 if (COM_Parse(t, true))
4868 if (com_token[0] == '!')
4871 origin[0] = atof(com_token+1);
4874 origin[0] = atof(com_token);
4879 while (*s && *s != '\n' && *s != '\r')
4885 // check for modifier flags
4892 #if _MSC_VER >= 1400
4893 #define sscanf sscanf_s
4895 cubemapname[sizeof(cubemapname)-1] = 0;
4896 #if MAX_QPATH != 128
4897 #error update this code if MAX_QPATH changes
4899 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
4900 #if _MSC_VER >= 1400
4901 , sizeof(cubemapname)
4903 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4906 flags = LIGHTFLAG_REALTIMEMODE;
4914 coronasizescale = 0.25f;
4916 VectorClear(angles);
4919 if (a < 9 || !strcmp(cubemapname, "\"\""))
4921 // remove quotes on cubemapname
4922 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4925 namelen = strlen(cubemapname) - 2;
4926 memmove(cubemapname, cubemapname + 1, namelen);
4927 cubemapname[namelen] = '\0';
4931 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);
4934 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4942 Con_Printf("invalid rtlights file \"%s\"\n", name);
4943 Mem_Free(lightsstring);
4947 void R_Shadow_SaveWorldLights(void)
4951 size_t bufchars, bufmaxchars;
4953 char name[MAX_QPATH];
4954 char line[MAX_INPUTLINE];
4955 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4956 // I hate lines which are 3 times my screen size :( --blub
4959 if (cl.worldmodel == NULL)
4961 Con_Print("No map loaded.\n");
4964 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4965 bufchars = bufmaxchars = 0;
4967 for (lightindex = 0;lightindex < range;lightindex++)
4969 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4972 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4973 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);
4974 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4975 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]);
4977 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);
4978 if (bufchars + strlen(line) > bufmaxchars)
4980 bufmaxchars = bufchars + strlen(line) + 2048;
4982 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4986 memcpy(buf, oldbuf, bufchars);
4992 memcpy(buf + bufchars, line, strlen(line));
4993 bufchars += strlen(line);
4997 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5002 void R_Shadow_LoadLightsFile(void)
5005 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5006 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5007 if (cl.worldmodel == NULL)
5009 Con_Print("No map loaded.\n");
5012 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5013 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5021 while (*s && *s != '\n' && *s != '\r')
5027 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);
5031 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);
5034 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5035 radius = bound(15, radius, 4096);
5036 VectorScale(color, (2.0f / (8388608.0f)), color);
5037 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5045 Con_Printf("invalid lights file \"%s\"\n", name);
5046 Mem_Free(lightsstring);
5050 // tyrlite/hmap2 light types in the delay field
5051 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5053 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5065 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5066 char key[256], value[MAX_INPUTLINE];
5069 if (cl.worldmodel == NULL)
5071 Con_Print("No map loaded.\n");
5074 // try to load a .ent file first
5075 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5076 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5077 // and if that is not found, fall back to the bsp file entity string
5079 data = cl.worldmodel->brush.entities;
5082 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5084 type = LIGHTTYPE_MINUSX;
5085 origin[0] = origin[1] = origin[2] = 0;
5086 originhack[0] = originhack[1] = originhack[2] = 0;
5087 angles[0] = angles[1] = angles[2] = 0;
5088 color[0] = color[1] = color[2] = 1;
5089 light[0] = light[1] = light[2] = 1;light[3] = 300;
5090 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5100 if (!COM_ParseToken_Simple(&data, false, false, true))
5102 if (com_token[0] == '}')
5103 break; // end of entity
5104 if (com_token[0] == '_')
5105 strlcpy(key, com_token + 1, sizeof(key));
5107 strlcpy(key, com_token, sizeof(key));
5108 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5109 key[strlen(key)-1] = 0;
5110 if (!COM_ParseToken_Simple(&data, false, false, true))
5112 strlcpy(value, com_token, sizeof(value));
5114 // now that we have the key pair worked out...
5115 if (!strcmp("light", key))
5117 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5121 light[0] = vec[0] * (1.0f / 256.0f);
5122 light[1] = vec[0] * (1.0f / 256.0f);
5123 light[2] = vec[0] * (1.0f / 256.0f);
5129 light[0] = vec[0] * (1.0f / 255.0f);
5130 light[1] = vec[1] * (1.0f / 255.0f);
5131 light[2] = vec[2] * (1.0f / 255.0f);
5135 else if (!strcmp("delay", key))
5137 else if (!strcmp("origin", key))
5138 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5139 else if (!strcmp("angle", key))
5140 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5141 else if (!strcmp("angles", key))
5142 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5143 else if (!strcmp("color", key))
5144 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5145 else if (!strcmp("wait", key))
5146 fadescale = atof(value);
5147 else if (!strcmp("classname", key))
5149 if (!strncmp(value, "light", 5))
5152 if (!strcmp(value, "light_fluoro"))
5157 overridecolor[0] = 1;
5158 overridecolor[1] = 1;
5159 overridecolor[2] = 1;
5161 if (!strcmp(value, "light_fluorospark"))
5166 overridecolor[0] = 1;
5167 overridecolor[1] = 1;
5168 overridecolor[2] = 1;
5170 if (!strcmp(value, "light_globe"))
5175 overridecolor[0] = 1;
5176 overridecolor[1] = 0.8;
5177 overridecolor[2] = 0.4;
5179 if (!strcmp(value, "light_flame_large_yellow"))
5184 overridecolor[0] = 1;
5185 overridecolor[1] = 0.5;
5186 overridecolor[2] = 0.1;
5188 if (!strcmp(value, "light_flame_small_yellow"))
5193 overridecolor[0] = 1;
5194 overridecolor[1] = 0.5;
5195 overridecolor[2] = 0.1;
5197 if (!strcmp(value, "light_torch_small_white"))
5202 overridecolor[0] = 1;
5203 overridecolor[1] = 0.5;
5204 overridecolor[2] = 0.1;
5206 if (!strcmp(value, "light_torch_small_walltorch"))
5211 overridecolor[0] = 1;
5212 overridecolor[1] = 0.5;
5213 overridecolor[2] = 0.1;
5217 else if (!strcmp("style", key))
5218 style = atoi(value);
5219 else if (!strcmp("skin", key))
5220 skin = (int)atof(value);
5221 else if (!strcmp("pflags", key))
5222 pflags = (int)atof(value);
5223 //else if (!strcmp("effects", key))
5224 // effects = (int)atof(value);
5225 else if (cl.worldmodel->type == mod_brushq3)
5227 if (!strcmp("scale", key))
5228 lightscale = atof(value);
5229 if (!strcmp("fade", key))
5230 fadescale = atof(value);
5235 if (lightscale <= 0)
5239 if (color[0] == color[1] && color[0] == color[2])
5241 color[0] *= overridecolor[0];
5242 color[1] *= overridecolor[1];
5243 color[2] *= overridecolor[2];
5245 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5246 color[0] = color[0] * light[0];
5247 color[1] = color[1] * light[1];
5248 color[2] = color[2] * light[2];
5251 case LIGHTTYPE_MINUSX:
5253 case LIGHTTYPE_RECIPX:
5255 VectorScale(color, (1.0f / 16.0f), color);
5257 case LIGHTTYPE_RECIPXX:
5259 VectorScale(color, (1.0f / 16.0f), color);
5262 case LIGHTTYPE_NONE:
5266 case LIGHTTYPE_MINUSXX:
5269 VectorAdd(origin, originhack, origin);
5271 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);
5274 Mem_Free(entfiledata);
5278 static void R_Shadow_SetCursorLocationForView(void)
5281 vec3_t dest, endpos;
5283 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5284 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5285 if (trace.fraction < 1)
5287 dist = trace.fraction * r_editlights_cursordistance.value;
5288 push = r_editlights_cursorpushback.value;
5292 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5293 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5297 VectorClear( endpos );
5299 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5300 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5301 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5304 void R_Shadow_UpdateWorldLightSelection(void)
5306 if (r_editlights.integer)
5308 R_Shadow_SetCursorLocationForView();
5309 R_Shadow_SelectLightInView();
5312 R_Shadow_SelectLight(NULL);
5315 static void R_Shadow_EditLights_Clear_f(void)
5317 R_Shadow_ClearWorldLights();
5320 void R_Shadow_EditLights_Reload_f(void)
5324 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5325 R_Shadow_ClearWorldLights();
5326 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5328 R_Shadow_LoadWorldLights();
5329 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5330 R_Shadow_LoadLightsFile();
5332 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5334 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5335 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5339 static void R_Shadow_EditLights_Save_f(void)
5343 R_Shadow_SaveWorldLights();
5346 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5348 R_Shadow_ClearWorldLights();
5349 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5352 static void R_Shadow_EditLights_ImportLightsFile_f(void)
5354 R_Shadow_ClearWorldLights();
5355 R_Shadow_LoadLightsFile();
5358 static void R_Shadow_EditLights_Spawn_f(void)
5361 if (!r_editlights.integer)
5363 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5366 if (Cmd_Argc() != 1)
5368 Con_Print("r_editlights_spawn does not take parameters\n");
5371 color[0] = color[1] = color[2] = 1;
5372 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5375 static void R_Shadow_EditLights_Edit_f(void)
5377 vec3_t origin, angles, color;
5378 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5379 int style, shadows, flags, normalmode, realtimemode;
5380 char cubemapname[MAX_INPUTLINE];
5381 if (!r_editlights.integer)
5383 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5386 if (!r_shadow_selectedlight)
5388 Con_Print("No selected light.\n");
5391 VectorCopy(r_shadow_selectedlight->origin, origin);
5392 VectorCopy(r_shadow_selectedlight->angles, angles);
5393 VectorCopy(r_shadow_selectedlight->color, color);
5394 radius = r_shadow_selectedlight->radius;
5395 style = r_shadow_selectedlight->style;
5396 if (r_shadow_selectedlight->cubemapname)
5397 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5400 shadows = r_shadow_selectedlight->shadow;
5401 corona = r_shadow_selectedlight->corona;
5402 coronasizescale = r_shadow_selectedlight->coronasizescale;
5403 ambientscale = r_shadow_selectedlight->ambientscale;
5404 diffusescale = r_shadow_selectedlight->diffusescale;
5405 specularscale = r_shadow_selectedlight->specularscale;
5406 flags = r_shadow_selectedlight->flags;
5407 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5408 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5409 if (!strcmp(Cmd_Argv(1), "origin"))
5411 if (Cmd_Argc() != 5)
5413 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5416 origin[0] = atof(Cmd_Argv(2));
5417 origin[1] = atof(Cmd_Argv(3));
5418 origin[2] = atof(Cmd_Argv(4));
5420 else if (!strcmp(Cmd_Argv(1), "originscale"))
5422 if (Cmd_Argc() != 5)
5424 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5427 origin[0] *= atof(Cmd_Argv(2));
5428 origin[1] *= atof(Cmd_Argv(3));
5429 origin[2] *= atof(Cmd_Argv(4));
5431 else if (!strcmp(Cmd_Argv(1), "originx"))
5433 if (Cmd_Argc() != 3)
5435 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5438 origin[0] = atof(Cmd_Argv(2));
5440 else if (!strcmp(Cmd_Argv(1), "originy"))
5442 if (Cmd_Argc() != 3)
5444 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5447 origin[1] = atof(Cmd_Argv(2));
5449 else if (!strcmp(Cmd_Argv(1), "originz"))
5451 if (Cmd_Argc() != 3)
5453 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5456 origin[2] = atof(Cmd_Argv(2));
5458 else if (!strcmp(Cmd_Argv(1), "move"))
5460 if (Cmd_Argc() != 5)
5462 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5465 origin[0] += atof(Cmd_Argv(2));
5466 origin[1] += atof(Cmd_Argv(3));
5467 origin[2] += atof(Cmd_Argv(4));
5469 else if (!strcmp(Cmd_Argv(1), "movex"))
5471 if (Cmd_Argc() != 3)
5473 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5476 origin[0] += atof(Cmd_Argv(2));
5478 else if (!strcmp(Cmd_Argv(1), "movey"))
5480 if (Cmd_Argc() != 3)
5482 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5485 origin[1] += atof(Cmd_Argv(2));
5487 else if (!strcmp(Cmd_Argv(1), "movez"))
5489 if (Cmd_Argc() != 3)
5491 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5494 origin[2] += atof(Cmd_Argv(2));
5496 else if (!strcmp(Cmd_Argv(1), "angles"))
5498 if (Cmd_Argc() != 5)
5500 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5503 angles[0] = atof(Cmd_Argv(2));
5504 angles[1] = atof(Cmd_Argv(3));
5505 angles[2] = atof(Cmd_Argv(4));
5507 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5509 if (Cmd_Argc() != 3)
5511 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5514 angles[0] = atof(Cmd_Argv(2));
5516 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5518 if (Cmd_Argc() != 3)
5520 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5523 angles[1] = atof(Cmd_Argv(2));
5525 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5527 if (Cmd_Argc() != 3)
5529 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5532 angles[2] = atof(Cmd_Argv(2));
5534 else if (!strcmp(Cmd_Argv(1), "color"))
5536 if (Cmd_Argc() != 5)
5538 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5541 color[0] = atof(Cmd_Argv(2));
5542 color[1] = atof(Cmd_Argv(3));
5543 color[2] = atof(Cmd_Argv(4));
5545 else if (!strcmp(Cmd_Argv(1), "radius"))
5547 if (Cmd_Argc() != 3)
5549 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5552 radius = atof(Cmd_Argv(2));
5554 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5556 if (Cmd_Argc() == 3)
5558 double scale = atof(Cmd_Argv(2));
5565 if (Cmd_Argc() != 5)
5567 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5570 color[0] *= atof(Cmd_Argv(2));
5571 color[1] *= atof(Cmd_Argv(3));
5572 color[2] *= atof(Cmd_Argv(4));
5575 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5577 if (Cmd_Argc() != 3)
5579 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5582 radius *= atof(Cmd_Argv(2));
5584 else if (!strcmp(Cmd_Argv(1), "style"))
5586 if (Cmd_Argc() != 3)
5588 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5591 style = atoi(Cmd_Argv(2));
5593 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5597 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5600 if (Cmd_Argc() == 3)
5601 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5605 else if (!strcmp(Cmd_Argv(1), "shadows"))
5607 if (Cmd_Argc() != 3)
5609 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5612 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5614 else if (!strcmp(Cmd_Argv(1), "corona"))
5616 if (Cmd_Argc() != 3)
5618 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5621 corona = atof(Cmd_Argv(2));
5623 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5625 if (Cmd_Argc() != 3)
5627 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5630 coronasizescale = atof(Cmd_Argv(2));
5632 else if (!strcmp(Cmd_Argv(1), "ambient"))
5634 if (Cmd_Argc() != 3)
5636 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5639 ambientscale = atof(Cmd_Argv(2));
5641 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5643 if (Cmd_Argc() != 3)
5645 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5648 diffusescale = atof(Cmd_Argv(2));
5650 else if (!strcmp(Cmd_Argv(1), "specular"))
5652 if (Cmd_Argc() != 3)
5654 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5657 specularscale = atof(Cmd_Argv(2));
5659 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5661 if (Cmd_Argc() != 3)
5663 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5666 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5668 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5670 if (Cmd_Argc() != 3)
5672 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5675 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5679 Con_Print("usage: r_editlights_edit [property] [value]\n");
5680 Con_Print("Selected light's properties:\n");
5681 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5682 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5683 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5684 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5685 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5686 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5687 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5688 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5689 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5690 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5691 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5692 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5693 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5694 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5697 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5698 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5701 static void R_Shadow_EditLights_EditAll_f(void)
5704 dlight_t *light, *oldselected;
5707 if (!r_editlights.integer)
5709 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5713 oldselected = r_shadow_selectedlight;
5714 // EditLights doesn't seem to have a "remove" command or something so:
5715 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5716 for (lightindex = 0;lightindex < range;lightindex++)
5718 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5721 R_Shadow_SelectLight(light);
5722 R_Shadow_EditLights_Edit_f();
5724 // return to old selected (to not mess editing once selection is locked)
5725 R_Shadow_SelectLight(oldselected);
5728 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5730 int lightnumber, lightcount;
5731 size_t lightindex, range;
5736 if (!r_editlights.integer)
5739 // update cvars so QC can query them
5740 if (r_shadow_selectedlight)
5742 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5743 Cvar_SetQuick(&r_editlights_current_origin, temp);
5744 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5745 Cvar_SetQuick(&r_editlights_current_angles, temp);
5746 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5747 Cvar_SetQuick(&r_editlights_current_color, temp);
5748 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5749 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5750 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5751 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5752 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5753 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5754 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5755 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5756 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5757 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5758 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5761 // draw properties on screen
5762 if (!r_editlights_drawproperties.integer)
5764 x = vid_conwidth.value - 320;
5766 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5769 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5770 for (lightindex = 0;lightindex < range;lightindex++)
5772 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5775 if (light == r_shadow_selectedlight)
5776 lightnumber = (int)lightindex;
5779 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;
5780 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;
5782 if (r_shadow_selectedlight == NULL)
5784 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;
5785 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;
5786 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;
5787 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;
5788 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;
5789 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;
5790 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;
5791 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;
5792 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;
5793 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;
5794 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;
5795 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;
5796 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;
5797 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;
5798 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;
5800 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;
5801 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;
5802 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;
5803 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;
5804 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;
5805 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;
5806 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;
5807 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;
5808 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;
5809 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;
5812 static void R_Shadow_EditLights_ToggleShadow_f(void)
5814 if (!r_editlights.integer)
5816 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5819 if (!r_shadow_selectedlight)
5821 Con_Print("No selected light.\n");
5824 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);
5827 static void R_Shadow_EditLights_ToggleCorona_f(void)
5829 if (!r_editlights.integer)
5831 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5834 if (!r_shadow_selectedlight)
5836 Con_Print("No selected light.\n");
5839 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);
5842 static void R_Shadow_EditLights_Remove_f(void)
5844 if (!r_editlights.integer)
5846 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5849 if (!r_shadow_selectedlight)
5851 Con_Print("No selected light.\n");
5854 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5855 r_shadow_selectedlight = NULL;
5858 static void R_Shadow_EditLights_Help_f(void)
5861 "Documentation on r_editlights system:\n"
5863 "r_editlights : enable/disable editing mode\n"
5864 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5865 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5866 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5867 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5868 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5870 "r_editlights_help : this help\n"
5871 "r_editlights_clear : remove all lights\n"
5872 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5873 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5874 "r_editlights_save : save to .rtlights file\n"
5875 "r_editlights_spawn : create a light with default settings\n"
5876 "r_editlights_edit command : edit selected light - more documentation below\n"
5877 "r_editlights_remove : remove selected light\n"
5878 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5879 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5880 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5882 "origin x y z : set light location\n"
5883 "originx x: set x component of light location\n"
5884 "originy y: set y component of light location\n"
5885 "originz z: set z component of light location\n"
5886 "move x y z : adjust light location\n"
5887 "movex x: adjust x component of light location\n"
5888 "movey y: adjust y component of light location\n"
5889 "movez z: adjust z component of light location\n"
5890 "angles x y z : set light angles\n"
5891 "anglesx x: set x component of light angles\n"
5892 "anglesy y: set y component of light angles\n"
5893 "anglesz z: set z component of light angles\n"
5894 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5895 "radius radius : set radius (size) of light\n"
5896 "colorscale grey : multiply color of light (1 does nothing)\n"
5897 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5898 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5899 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5900 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5901 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5902 "cubemap basename : set filter cubemap of light\n"
5903 "shadows 1/0 : turn on/off shadows\n"
5904 "corona n : set corona intensity\n"
5905 "coronasize n : set corona size (0-1)\n"
5906 "ambient n : set ambient intensity (0-1)\n"
5907 "diffuse n : set diffuse intensity (0-1)\n"
5908 "specular n : set specular intensity (0-1)\n"
5909 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5910 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5911 "<nothing> : print light properties to console\n"
5915 static void R_Shadow_EditLights_CopyInfo_f(void)
5917 if (!r_editlights.integer)
5919 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5922 if (!r_shadow_selectedlight)
5924 Con_Print("No selected light.\n");
5927 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5928 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5929 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5930 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5931 if (r_shadow_selectedlight->cubemapname)
5932 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5934 r_shadow_bufferlight.cubemapname[0] = 0;
5935 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5936 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5937 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5938 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5939 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5940 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5941 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5944 static void R_Shadow_EditLights_PasteInfo_f(void)
5946 if (!r_editlights.integer)
5948 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5951 if (!r_shadow_selectedlight)
5953 Con_Print("No selected light.\n");
5956 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);
5959 static void R_Shadow_EditLights_Lock_f(void)
5961 if (!r_editlights.integer)
5963 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5966 if (r_editlights_lockcursor)
5968 r_editlights_lockcursor = false;
5971 if (!r_shadow_selectedlight)
5973 Con_Print("No selected light to lock on.\n");
5976 r_editlights_lockcursor = true;
5979 static void R_Shadow_EditLights_Init(void)
5981 Cvar_RegisterVariable(&r_editlights);
5982 Cvar_RegisterVariable(&r_editlights_cursordistance);
5983 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5984 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5985 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5986 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5987 Cvar_RegisterVariable(&r_editlights_drawproperties);
5988 Cvar_RegisterVariable(&r_editlights_current_origin);
5989 Cvar_RegisterVariable(&r_editlights_current_angles);
5990 Cvar_RegisterVariable(&r_editlights_current_color);
5991 Cvar_RegisterVariable(&r_editlights_current_radius);
5992 Cvar_RegisterVariable(&r_editlights_current_corona);
5993 Cvar_RegisterVariable(&r_editlights_current_coronasize);
5994 Cvar_RegisterVariable(&r_editlights_current_style);
5995 Cvar_RegisterVariable(&r_editlights_current_shadows);
5996 Cvar_RegisterVariable(&r_editlights_current_cubemap);
5997 Cvar_RegisterVariable(&r_editlights_current_ambient);
5998 Cvar_RegisterVariable(&r_editlights_current_diffuse);
5999 Cvar_RegisterVariable(&r_editlights_current_specular);
6000 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6001 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6002 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6003 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6004 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)");
6005 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6006 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6007 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6008 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)");
6009 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6010 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6011 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6012 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6013 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6014 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6015 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)");
6016 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6022 =============================================================================
6026 =============================================================================
6029 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6031 int i, numlights, flag, q;
6034 float relativepoint[3];
6039 float sa[3], sx[3], sy[3], sz[3], sd[3];
6042 // use first order spherical harmonics to combine directional lights
6043 for (q = 0; q < 3; q++)
6044 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6046 if (flags & LP_LIGHTMAP)
6048 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6050 float tempambient[3];
6051 for (q = 0; q < 3; q++)
6052 tempambient[q] = color[q] = relativepoint[q] = 0;
6053 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6054 // calculate a weighted average light direction as well
6055 intensity = VectorLength(color);
6056 for (q = 0; q < 3; q++)
6058 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6059 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6060 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6061 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6062 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6067 // unlit map - fullbright but scaled by lightmapintensity
6068 for (q = 0; q < 3; q++)
6069 sa[q] += lightmapintensity;
6073 if (flags & LP_RTWORLD)
6075 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6076 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6077 for (i = 0; i < numlights; i++)
6079 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6082 light = &dlight->rtlight;
6083 if (!(light->flags & flag))
6086 lightradius2 = light->radius * light->radius;
6087 VectorSubtract(light->shadoworigin, p, relativepoint);
6088 dist2 = VectorLength2(relativepoint);
6089 if (dist2 >= lightradius2)
6091 dist = sqrt(dist2) / light->radius;
6092 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6093 if (intensity <= 0.0f)
6095 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)
6097 for (q = 0; q < 3; q++)
6098 color[q] = light->currentcolor[q] * intensity;
6099 intensity = VectorLength(color);
6100 VectorNormalize(relativepoint);
6101 for (q = 0; q < 3; q++)
6103 sa[q] += 0.5f * color[q];
6104 sx[q] += relativepoint[0] * color[q];
6105 sy[q] += relativepoint[1] * color[q];
6106 sz[q] += relativepoint[2] * color[q];
6107 sd[q] += intensity * relativepoint[q];
6110 // FIXME: sample bouncegrid too!
6113 if (flags & LP_DYNLIGHT)
6116 for (i = 0;i < r_refdef.scene.numlights;i++)
6118 light = r_refdef.scene.lights[i];
6120 lightradius2 = light->radius * light->radius;
6121 VectorSubtract(light->shadoworigin, p, relativepoint);
6122 dist2 = VectorLength2(relativepoint);
6123 if (dist2 >= lightradius2)
6125 dist = sqrt(dist2) / light->radius;
6126 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6127 if (intensity <= 0.0f)
6129 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)
6131 for (q = 0; q < 3; q++)
6132 color[q] = light->currentcolor[q] * intensity;
6133 intensity = VectorLength(color);
6134 VectorNormalize(relativepoint);
6135 for (q = 0; q < 3; q++)
6137 sa[q] += 0.5f * color[q];
6138 sx[q] += relativepoint[0] * color[q];
6139 sy[q] += relativepoint[1] * color[q];
6140 sz[q] += relativepoint[2] * color[q];
6141 sd[q] += intensity * relativepoint[q];
6146 // calculate the weighted-average light direction (bentnormal)
6147 for (q = 0; q < 3; q++)
6148 lightdir[q] = sd[q];
6149 VectorNormalize(lightdir);
6150 for (q = 0; q < 3; q++)
6152 // extract the diffuse color along the chosen direction and scale it
6153 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6154 // subtract some of diffuse from ambient
6155 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;