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_STENCIL,
28 R_SHADOW_SHADOWMODE_SHADOWMAP2D
30 r_shadow_shadowmode_t;
32 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
33 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
34 int r_shadow_scenemaxlights;
35 int r_shadow_scenenumlights;
36 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
37 qboolean r_shadow_usingshadowmap2d;
38 qboolean r_shadow_usingshadowmaportho;
39 int r_shadow_shadowmapside;
40 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
41 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
42 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
43 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
45 int r_shadow_drawbuffer;
46 int r_shadow_readbuffer;
48 int r_shadow_cullface_front, r_shadow_cullface_back;
49 GLuint r_shadow_fbo2d;
50 r_shadow_shadowmode_t r_shadow_shadowmode;
51 int r_shadow_shadowmapfilterquality;
52 int r_shadow_shadowmapdepthbits;
53 int r_shadow_shadowmapmaxsize;
54 int r_shadow_shadowmaptexturesize;
55 qboolean r_shadow_shadowmapvsdct;
56 qboolean r_shadow_shadowmapsampler;
57 qboolean r_shadow_shadowmapshadowsampler;
58 int r_shadow_shadowmappcf;
59 int r_shadow_shadowmapborder;
60 matrix4x4_t r_shadow_shadowmapmatrix;
61 int r_shadow_lightscissor[4];
62 qboolean r_shadow_usingdeferredprepass;
63 qboolean r_shadow_shadowmapdepthtexture;
64 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
65 int r_shadow_shadowmapatlas_modelshadows_x;
66 int r_shadow_shadowmapatlas_modelshadows_y;
67 int r_shadow_shadowmapatlas_modelshadows_size;
68 int maxshadowtriangles;
71 int maxshadowvertices;
72 float *shadowvertex3f;
82 unsigned char *shadowsides;
90 int r_shadow_buffer_numleafpvsbytes;
91 unsigned char *r_shadow_buffer_visitingleafpvs;
92 unsigned char *r_shadow_buffer_leafpvs;
93 int *r_shadow_buffer_leaflist;
95 int r_shadow_buffer_numsurfacepvsbytes;
96 unsigned char *r_shadow_buffer_surfacepvs;
97 int *r_shadow_buffer_surfacelist;
98 unsigned char *r_shadow_buffer_surfacesides;
100 int r_shadow_buffer_numshadowtrispvsbytes;
101 unsigned char *r_shadow_buffer_shadowtrispvs;
102 int r_shadow_buffer_numlighttrispvsbytes;
103 unsigned char *r_shadow_buffer_lighttrispvs;
105 rtexturepool_t *r_shadow_texturepool;
106 rtexture_t *r_shadow_attenuationgradienttexture;
107 skinframe_t *r_shadow_lightcorona;
108 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
109 rtexture_t *r_shadow_shadowmap2ddepthtexture;
110 rtexture_t *r_shadow_shadowmapvsdcttexture;
112 GLuint r_shadow_prepassgeometryfbo;
113 GLuint r_shadow_prepasslightingdiffusespecularfbo;
114 GLuint r_shadow_prepasslightingdiffusefbo;
115 int r_shadow_prepass_width;
116 int r_shadow_prepass_height;
117 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
118 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
119 rtexture_t *r_shadow_prepasslightingdiffusetexture;
120 rtexture_t *r_shadow_prepasslightingspeculartexture;
122 int r_shadow_viewfbo;
123 rtexture_t *r_shadow_viewdepthtexture;
124 rtexture_t *r_shadow_viewcolortexture;
127 int r_shadow_viewwidth;
128 int r_shadow_viewheight;
130 // lights are reloaded when this changes
131 char r_shadow_mapname[MAX_QPATH];
133 // buffer for doing corona fading
134 unsigned int r_shadow_occlusion_buf = 0;
136 // used only for light filters (cubemaps)
137 rtexturepool_t *r_shadow_filters_texturepool;
139 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"};
140 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"};
141 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
142 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"};
143 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)"};
144 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
145 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)"};
146 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"};
147 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
148 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
149 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
150 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
151 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
152 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
153 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
154 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
155 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
156 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)"};
157 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
158 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
159 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
160 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
161 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)"};
162 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)"};
163 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"};
164 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
165 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
166 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"};
167 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)"};
168 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
169 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)"};
170 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
171 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)"};
172 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
173 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
174 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
175 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"};
176 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..."};
177 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"};
178 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"};
179 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
180 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
181 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
182 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
183 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
184 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
185 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
186 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
187 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"};
188 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"};
189 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
190 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
191 cvar_t r_shadow_culllights_trace_expand = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
192 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"};
193 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)"};
194 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)"};
195 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"};
196 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)"};
197 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"};
198 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"};
199 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" };
200 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)"};
201 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"};
202 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"};
203 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
204 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)"};
205 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)"};
206 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"};
207 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)"};
208 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
209 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"};
210 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
211 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
212 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
213 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"};
214 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)"};
215 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
216 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"};
217 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"};
218 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)" };
219 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"};
220 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
221 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" };
222 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)" };
223 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"};
224 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
225 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" };
226 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
227 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"};
228 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"};
229 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
230 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)" };
231 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
232 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
233 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"};
234 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility) - bad performance (synchronous rendering) - worse on multi-gpu!"};
235 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
236 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
237 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
238 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
239 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
240 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
241 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
242 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
243 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
244 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
245 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
246 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
247 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
248 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
249 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
250 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
251 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
252 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
253 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
254 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
255 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
256 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
258 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
260 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
261 #define ATTENTABLESIZE 256
262 // 1D gradient, 2D circle and 3D sphere attenuation textures
263 #define ATTEN1DSIZE 32
264 #define ATTEN2DSIZE 64
265 #define ATTEN3DSIZE 32
267 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
268 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
269 static float r_shadow_attentable[ATTENTABLESIZE+1];
271 rtlight_t *r_shadow_compilingrtlight;
272 static memexpandablearray_t r_shadow_worldlightsarray;
273 dlight_t *r_shadow_selectedlight;
274 dlight_t r_shadow_bufferlight;
275 vec3_t r_editlights_cursorlocation;
276 qboolean r_editlights_lockcursor;
278 extern int con_vislines;
280 void R_Shadow_UncompileWorldLights(void);
281 void R_Shadow_ClearWorldLights(void);
282 void R_Shadow_SaveWorldLights(void);
283 void R_Shadow_LoadWorldLights(void);
284 void R_Shadow_LoadLightsFile(void);
285 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
286 void R_Shadow_EditLights_Reload_f(void);
287 static void R_Shadow_MakeTextures(void);
289 #define EDLIGHTSPRSIZE 8
290 skinframe_t *r_editlights_sprcursor;
291 skinframe_t *r_editlights_sprlight;
292 skinframe_t *r_editlights_sprnoshadowlight;
293 skinframe_t *r_editlights_sprcubemaplight;
294 skinframe_t *r_editlights_sprcubemapnoshadowlight;
295 skinframe_t *r_editlights_sprselection;
297 static void R_Shadow_DrawModelShadowMaps(void);
298 static void R_Shadow_MakeShadowMap(int texturesize);
299 static void R_Shadow_MakeVSDCT(void);
300 static void R_Shadow_SetShadowMode(void)
302 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
303 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
304 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
305 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
306 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
307 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
308 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
309 r_shadow_shadowmapsampler = false;
310 r_shadow_shadowmappcf = 0;
311 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
312 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
313 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
314 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
316 switch(vid.renderpath)
318 case RENDERPATH_GL20:
319 if(r_shadow_shadowmapfilterquality < 0)
321 if (!r_fb.usedepthtextures)
322 r_shadow_shadowmappcf = 1;
323 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
325 r_shadow_shadowmapsampler = true;
326 r_shadow_shadowmappcf = 1;
328 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
329 r_shadow_shadowmappcf = 1;
330 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
331 r_shadow_shadowmappcf = 1;
333 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
337 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
338 switch (r_shadow_shadowmapfilterquality)
343 r_shadow_shadowmappcf = 1;
346 r_shadow_shadowmappcf = 1;
349 r_shadow_shadowmappcf = 2;
353 if (!r_fb.usedepthtextures)
354 r_shadow_shadowmapsampler = false;
355 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
357 case RENDERPATH_GLES2:
362 if(R_CompileShader_CheckStaticParms())
366 qboolean R_Shadow_ShadowMappingEnabled(void)
368 switch (r_shadow_shadowmode)
370 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
377 static void R_Shadow_FreeShadowMaps(void)
379 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
381 R_Shadow_SetShadowMode();
383 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
387 if (r_shadow_shadowmap2ddepthtexture)
388 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
389 r_shadow_shadowmap2ddepthtexture = NULL;
391 if (r_shadow_shadowmap2ddepthbuffer)
392 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
393 r_shadow_shadowmap2ddepthbuffer = NULL;
395 if (r_shadow_shadowmapvsdcttexture)
396 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
397 r_shadow_shadowmapvsdcttexture = NULL;
400 static void r_shadow_start(void)
402 // allocate vertex processing arrays
403 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
404 r_shadow_attenuationgradienttexture = NULL;
405 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
406 r_shadow_shadowmap2ddepthtexture = NULL;
407 r_shadow_shadowmap2ddepthbuffer = NULL;
408 r_shadow_shadowmapvsdcttexture = NULL;
409 r_shadow_shadowmapmaxsize = 0;
410 r_shadow_shadowmaptexturesize = 0;
411 r_shadow_shadowmapfilterquality = -1;
412 r_shadow_shadowmapdepthbits = 0;
413 r_shadow_shadowmapvsdct = false;
414 r_shadow_shadowmapsampler = false;
415 r_shadow_shadowmappcf = 0;
418 R_Shadow_FreeShadowMaps();
420 r_shadow_texturepool = NULL;
421 r_shadow_filters_texturepool = NULL;
422 R_Shadow_MakeTextures();
423 r_shadow_scenemaxlights = 0;
424 r_shadow_scenenumlights = 0;
425 r_shadow_scenelightlist = NULL;
426 maxshadowtriangles = 0;
427 shadowelements = NULL;
428 maxshadowvertices = 0;
429 shadowvertex3f = NULL;
437 shadowmarklist = NULL;
442 shadowsideslist = NULL;
443 r_shadow_buffer_numleafpvsbytes = 0;
444 r_shadow_buffer_visitingleafpvs = NULL;
445 r_shadow_buffer_leafpvs = NULL;
446 r_shadow_buffer_leaflist = NULL;
447 r_shadow_buffer_numsurfacepvsbytes = 0;
448 r_shadow_buffer_surfacepvs = NULL;
449 r_shadow_buffer_surfacelist = NULL;
450 r_shadow_buffer_surfacesides = NULL;
451 r_shadow_buffer_numshadowtrispvsbytes = 0;
452 r_shadow_buffer_shadowtrispvs = NULL;
453 r_shadow_buffer_numlighttrispvsbytes = 0;
454 r_shadow_buffer_lighttrispvs = NULL;
456 r_shadow_usingdeferredprepass = false;
457 r_shadow_prepass_width = r_shadow_prepass_height = 0;
459 // determine renderpath specific capabilities, we don't need to figure
460 // these out per frame...
461 switch(vid.renderpath)
463 case RENDERPATH_GL20:
464 r_shadow_bouncegrid_state.allowdirectionalshading = true;
465 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
467 case RENDERPATH_GLES2:
468 // for performance reasons, do not use directional shading on GLES devices
469 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
474 static void R_Shadow_FreeDeferred(void);
475 static void r_shadow_shutdown(void)
478 R_Shadow_UncompileWorldLights();
480 R_Shadow_FreeShadowMaps();
482 r_shadow_usingdeferredprepass = false;
483 if (r_shadow_prepass_width)
484 R_Shadow_FreeDeferred();
485 r_shadow_prepass_width = r_shadow_prepass_height = 0;
488 r_shadow_scenemaxlights = 0;
489 r_shadow_scenenumlights = 0;
490 if (r_shadow_scenelightlist)
491 Mem_Free(r_shadow_scenelightlist);
492 r_shadow_scenelightlist = NULL;
493 r_shadow_bouncegrid_state.highpixels = NULL;
494 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
495 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
496 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
497 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
498 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
499 r_shadow_bouncegrid_state.maxsplatpaths = 0;
500 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
501 r_shadow_attenuationgradienttexture = NULL;
502 R_FreeTexturePool(&r_shadow_texturepool);
503 R_FreeTexturePool(&r_shadow_filters_texturepool);
504 maxshadowtriangles = 0;
506 Mem_Free(shadowelements);
507 shadowelements = NULL;
509 Mem_Free(shadowvertex3f);
510 shadowvertex3f = NULL;
513 Mem_Free(vertexupdate);
516 Mem_Free(vertexremap);
522 Mem_Free(shadowmark);
525 Mem_Free(shadowmarklist);
526 shadowmarklist = NULL;
531 Mem_Free(shadowsides);
534 Mem_Free(shadowsideslist);
535 shadowsideslist = NULL;
536 r_shadow_buffer_numleafpvsbytes = 0;
537 if (r_shadow_buffer_visitingleafpvs)
538 Mem_Free(r_shadow_buffer_visitingleafpvs);
539 r_shadow_buffer_visitingleafpvs = NULL;
540 if (r_shadow_buffer_leafpvs)
541 Mem_Free(r_shadow_buffer_leafpvs);
542 r_shadow_buffer_leafpvs = NULL;
543 if (r_shadow_buffer_leaflist)
544 Mem_Free(r_shadow_buffer_leaflist);
545 r_shadow_buffer_leaflist = NULL;
546 r_shadow_buffer_numsurfacepvsbytes = 0;
547 if (r_shadow_buffer_surfacepvs)
548 Mem_Free(r_shadow_buffer_surfacepvs);
549 r_shadow_buffer_surfacepvs = NULL;
550 if (r_shadow_buffer_surfacelist)
551 Mem_Free(r_shadow_buffer_surfacelist);
552 r_shadow_buffer_surfacelist = NULL;
553 if (r_shadow_buffer_surfacesides)
554 Mem_Free(r_shadow_buffer_surfacesides);
555 r_shadow_buffer_surfacesides = NULL;
556 r_shadow_buffer_numshadowtrispvsbytes = 0;
557 if (r_shadow_buffer_shadowtrispvs)
558 Mem_Free(r_shadow_buffer_shadowtrispvs);
559 r_shadow_buffer_numlighttrispvsbytes = 0;
560 if (r_shadow_buffer_lighttrispvs)
561 Mem_Free(r_shadow_buffer_lighttrispvs);
564 static void r_shadow_newmap(void)
566 r_shadow_bouncegrid_state.highpixels = NULL;
567 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
568 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
569 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
570 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
571 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;
573 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
574 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
575 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
576 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
577 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
578 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
579 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
580 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
581 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
582 R_Shadow_EditLights_Reload_f();
585 void R_Shadow_Init(void)
587 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
588 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
589 Cvar_RegisterVariable(&r_shadow_usebihculling);
590 Cvar_RegisterVariable(&r_shadow_usenormalmap);
591 Cvar_RegisterVariable(&r_shadow_debuglight);
592 Cvar_RegisterVariable(&r_shadow_deferred);
593 Cvar_RegisterVariable(&r_shadow_gloss);
594 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
595 Cvar_RegisterVariable(&r_shadow_glossintensity);
596 Cvar_RegisterVariable(&r_shadow_glossexponent);
597 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
598 Cvar_RegisterVariable(&r_shadow_glossexact);
599 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
600 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
601 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
602 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
603 Cvar_RegisterVariable(&r_shadow_projectdistance);
604 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
605 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
606 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
607 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
608 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
609 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
610 Cvar_RegisterVariable(&r_shadow_realtime_world);
611 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
612 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
613 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
614 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
615 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
616 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
617 Cvar_RegisterVariable(&r_shadow_scissor);
618 Cvar_RegisterVariable(&r_shadow_shadowmapping);
619 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
620 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
621 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
622 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
623 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
624 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
625 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
626 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
627 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
628 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
629 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
630 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
631 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
632 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
633 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
634 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
635 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
636 Cvar_RegisterVariable(&r_shadow_culllights_trace);
637 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
638 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
639 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
640 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
641 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
642 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
643 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
644 Cvar_RegisterVariable(&r_shadow_bouncegrid);
645 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
646 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
647 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
648 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
649 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
650 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
651 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
652 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
653 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
654 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
655 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
656 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
657 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
658 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
659 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
660 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
661 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
662 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
663 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
664 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
665 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
666 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
667 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
668 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
669 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
670 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
671 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
672 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
673 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
674 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
675 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
676 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
677 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
678 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
679 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
680 Cvar_RegisterVariable(&r_coronas);
681 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
682 Cvar_RegisterVariable(&r_coronas_occlusionquery);
683 Cvar_RegisterVariable(&gl_flashblend);
684 R_Shadow_EditLights_Init();
685 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
686 r_shadow_scenemaxlights = 0;
687 r_shadow_scenenumlights = 0;
688 r_shadow_scenelightlist = NULL;
689 maxshadowtriangles = 0;
690 shadowelements = NULL;
691 maxshadowvertices = 0;
692 shadowvertex3f = NULL;
700 shadowmarklist = NULL;
705 shadowsideslist = NULL;
706 r_shadow_buffer_numleafpvsbytes = 0;
707 r_shadow_buffer_visitingleafpvs = NULL;
708 r_shadow_buffer_leafpvs = NULL;
709 r_shadow_buffer_leaflist = NULL;
710 r_shadow_buffer_numsurfacepvsbytes = 0;
711 r_shadow_buffer_surfacepvs = NULL;
712 r_shadow_buffer_surfacelist = NULL;
713 r_shadow_buffer_surfacesides = NULL;
714 r_shadow_buffer_shadowtrispvs = NULL;
715 r_shadow_buffer_lighttrispvs = NULL;
716 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
719 matrix4x4_t matrix_attenuationxyz =
722 {0.5, 0.0, 0.0, 0.5},
723 {0.0, 0.5, 0.0, 0.5},
724 {0.0, 0.0, 0.5, 0.5},
729 matrix4x4_t matrix_attenuationz =
732 {0.0, 0.0, 0.5, 0.5},
733 {0.0, 0.0, 0.0, 0.5},
734 {0.0, 0.0, 0.0, 0.5},
739 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
741 numvertices = ((numvertices + 255) & ~255) * vertscale;
742 numtriangles = ((numtriangles + 255) & ~255) * triscale;
743 // make sure shadowelements is big enough for this volume
744 if (maxshadowtriangles < numtriangles)
746 maxshadowtriangles = numtriangles;
748 Mem_Free(shadowelements);
749 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
751 // make sure shadowvertex3f is big enough for this volume
752 if (maxshadowvertices < numvertices)
754 maxshadowvertices = numvertices;
756 Mem_Free(shadowvertex3f);
757 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
761 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
763 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
764 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
765 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
766 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
767 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
769 if (r_shadow_buffer_visitingleafpvs)
770 Mem_Free(r_shadow_buffer_visitingleafpvs);
771 if (r_shadow_buffer_leafpvs)
772 Mem_Free(r_shadow_buffer_leafpvs);
773 if (r_shadow_buffer_leaflist)
774 Mem_Free(r_shadow_buffer_leaflist);
775 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
776 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
777 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
778 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
780 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
782 if (r_shadow_buffer_surfacepvs)
783 Mem_Free(r_shadow_buffer_surfacepvs);
784 if (r_shadow_buffer_surfacelist)
785 Mem_Free(r_shadow_buffer_surfacelist);
786 if (r_shadow_buffer_surfacesides)
787 Mem_Free(r_shadow_buffer_surfacesides);
788 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
789 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
790 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
791 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
793 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
795 if (r_shadow_buffer_shadowtrispvs)
796 Mem_Free(r_shadow_buffer_shadowtrispvs);
797 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
798 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
800 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
802 if (r_shadow_buffer_lighttrispvs)
803 Mem_Free(r_shadow_buffer_lighttrispvs);
804 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
805 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
809 void R_Shadow_PrepareShadowMark(int numtris)
811 // make sure shadowmark is big enough for this volume
812 if (maxshadowmark < numtris)
814 maxshadowmark = numtris;
816 Mem_Free(shadowmark);
818 Mem_Free(shadowmarklist);
819 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
820 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
824 // if shadowmarkcount wrapped we clear the array and adjust accordingly
825 if (shadowmarkcount == 0)
828 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
833 void R_Shadow_PrepareShadowSides(int numtris)
835 if (maxshadowsides < numtris)
837 maxshadowsides = numtris;
839 Mem_Free(shadowsides);
841 Mem_Free(shadowsideslist);
842 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
843 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
848 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
850 // p1, p2, p3 are in the cubemap's local coordinate system
851 // bias = border/(size - border)
854 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
855 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
856 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
857 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
859 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
860 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
861 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
862 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
864 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
865 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
866 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
868 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
869 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
870 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
871 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
873 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
874 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
875 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
876 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
878 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
879 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
880 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
882 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
883 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
884 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
885 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
887 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
888 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
889 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
890 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
892 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
893 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
894 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
899 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
901 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
902 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
905 VectorSubtract(maxs, mins, radius);
906 VectorScale(radius, 0.5f, radius);
907 VectorAdd(mins, radius, center);
908 Matrix4x4_Transform(worldtolight, center, lightcenter);
909 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
910 VectorSubtract(lightcenter, lightradius, pmin);
911 VectorAdd(lightcenter, lightradius, pmax);
913 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
914 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
915 if(ap1 > bias*an1 && ap2 > bias*an2)
917 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
918 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
919 if(an1 > bias*ap1 && an2 > bias*ap2)
921 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
922 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
924 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
925 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
926 if(ap1 > bias*an1 && ap2 > bias*an2)
928 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
929 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
930 if(an1 > bias*ap1 && an2 > bias*ap2)
932 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
933 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
935 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
936 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
937 if(ap1 > bias*an1 && ap2 > bias*an2)
939 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
940 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
941 if(an1 > bias*ap1 && an2 > bias*ap2)
943 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
944 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
949 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
951 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
953 // p is in the cubemap's local coordinate system
954 // bias = border/(size - border)
955 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
956 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
957 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
959 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
960 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
961 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
962 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
963 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
964 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
968 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
972 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
973 float scale = (size - 2*border)/size, len;
974 float bias = border / (float)(size - border), dp, dn, ap, an;
975 // check if cone enclosing side would cross frustum plane
976 scale = 2 / (scale*scale + 2);
977 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
978 for (i = 0;i < 5;i++)
980 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
982 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
983 len = scale*VectorLength2(n);
984 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
985 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
986 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
988 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
990 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
991 len = scale*VectorLength2(n);
992 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
993 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
994 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
996 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
997 // check if frustum corners/origin cross plane sides
999 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1000 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1001 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1002 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1003 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1004 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1005 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1006 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1007 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1008 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1009 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1010 for (i = 0;i < 4;i++)
1012 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1013 VectorSubtract(n, p, n);
1014 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1015 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1016 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1017 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1018 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1019 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1020 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1021 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1022 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1025 // finite version, assumes corners are a finite distance from origin dependent on far plane
1026 for (i = 0;i < 5;i++)
1028 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1029 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1030 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1031 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1032 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1033 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1034 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1035 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1036 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1037 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1040 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1043 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)
1051 int mask, surfacemask = 0;
1052 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1054 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1055 tend = firsttriangle + numtris;
1056 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1058 // surface box entirely inside light box, no box cull
1059 if (projectdirection)
1061 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1063 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1064 TriangleNormal(v[0], v[1], v[2], normal);
1065 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1067 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1068 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1069 surfacemask |= mask;
1072 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;
1073 shadowsides[numshadowsides] = mask;
1074 shadowsideslist[numshadowsides++] = t;
1081 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1083 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1084 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1086 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1087 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1088 surfacemask |= mask;
1091 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;
1092 shadowsides[numshadowsides] = mask;
1093 shadowsideslist[numshadowsides++] = t;
1101 // surface box not entirely inside light box, cull each triangle
1102 if (projectdirection)
1104 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1106 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1107 TriangleNormal(v[0], v[1], v[2], normal);
1108 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1109 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1111 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1112 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1113 surfacemask |= mask;
1116 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;
1117 shadowsides[numshadowsides] = mask;
1118 shadowsideslist[numshadowsides++] = t;
1125 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1127 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1128 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1129 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1131 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1132 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1133 surfacemask |= mask;
1136 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;
1137 shadowsides[numshadowsides] = mask;
1138 shadowsideslist[numshadowsides++] = t;
1147 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)
1149 int i, j, outtriangles = 0;
1150 int *outelement3i[6];
1151 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1153 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1154 // make sure shadowelements is big enough for this mesh
1155 if (maxshadowtriangles < outtriangles)
1156 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1158 // compute the offset and size of the separate index lists for each cubemap side
1160 for (i = 0;i < 6;i++)
1162 outelement3i[i] = shadowelements + outtriangles * 3;
1163 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1164 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1165 outtriangles += sidetotals[i];
1168 // gather up the (sparse) triangles into separate index lists for each cubemap side
1169 for (i = 0;i < numsidetris;i++)
1171 const int *element = elements + sidetris[i] * 3;
1172 for (j = 0;j < 6;j++)
1174 if (sides[i] & (1 << j))
1176 outelement3i[j][0] = element[0];
1177 outelement3i[j][1] = element[1];
1178 outelement3i[j][2] = element[2];
1179 outelement3i[j] += 3;
1184 Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1187 static void R_Shadow_MakeTextures_MakeCorona(void)
1191 unsigned char pixels[32][32][4];
1192 for (y = 0;y < 32;y++)
1194 dy = (y - 15.5f) * (1.0f / 16.0f);
1195 for (x = 0;x < 32;x++)
1197 dx = (x - 15.5f) * (1.0f / 16.0f);
1198 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1199 a = bound(0, a, 255);
1200 pixels[y][x][0] = a;
1201 pixels[y][x][1] = a;
1202 pixels[y][x][2] = a;
1203 pixels[y][x][3] = 255;
1206 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1209 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1211 float dist = sqrt(x*x+y*y+z*z);
1212 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1213 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1214 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1217 static void R_Shadow_MakeTextures(void)
1220 float intensity, dist;
1222 R_Shadow_FreeShadowMaps();
1223 R_FreeTexturePool(&r_shadow_texturepool);
1224 r_shadow_texturepool = R_AllocTexturePool();
1225 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1226 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1227 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1228 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1229 for (x = 0;x <= ATTENTABLESIZE;x++)
1231 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1232 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1233 r_shadow_attentable[x] = bound(0, intensity, 1);
1235 // 1D gradient texture
1236 for (x = 0;x < ATTEN1DSIZE;x++)
1237 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1238 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1241 R_Shadow_MakeTextures_MakeCorona();
1243 // Editor light sprites
1244 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1261 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1262 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1279 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1280 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1297 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1298 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1315 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1316 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1333 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1334 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1351 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1354 void R_Shadow_RenderMode_Begin(void)
1361 if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1362 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1363 R_Shadow_MakeTextures();
1366 R_Mesh_ResetTextureState();
1367 GL_BlendFunc(GL_ONE, GL_ZERO);
1368 GL_DepthRange(0, 1);
1369 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1371 GL_DepthMask(false);
1372 GL_Color(0, 0, 0, 1);
1373 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1375 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1376 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1380 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1381 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1382 r_shadow_drawbuffer = drawbuffer;
1383 r_shadow_readbuffer = readbuffer;
1385 r_shadow_cullface_front = r_refdef.view.cullface_front;
1386 r_shadow_cullface_back = r_refdef.view.cullface_back;
1389 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1391 rsurface.rtlight = rtlight;
1394 void R_Shadow_RenderMode_Reset(void)
1396 R_Mesh_ResetTextureState();
1397 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1398 R_SetViewport(&r_refdef.view.viewport);
1399 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1400 GL_DepthRange(0, 1);
1402 GL_DepthMask(false);
1403 GL_DepthFunc(GL_LEQUAL);
1404 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1405 r_refdef.view.cullface_front = r_shadow_cullface_front;
1406 r_refdef.view.cullface_back = r_shadow_cullface_back;
1407 GL_CullFace(r_refdef.view.cullface_back);
1408 GL_Color(1, 1, 1, 1);
1409 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1410 GL_BlendFunc(GL_ONE, GL_ZERO);
1411 R_SetupShader_Generic_NoTexture(false, false);
1412 r_shadow_usingshadowmap2d = false;
1415 void R_Shadow_ClearStencil(void)
1417 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1418 r_refdef.stats[r_stat_lights_clears]++;
1421 static void R_Shadow_MakeVSDCT(void)
1423 // maps to a 2x3 texture rectangle with normalized coordinates
1428 // stores abs(dir.xy), offset.xy/2.5
1429 unsigned char data[4*6] =
1431 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1432 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1433 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1434 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1435 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1436 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1438 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1441 static void R_Shadow_MakeShadowMap(int texturesize)
1443 switch (r_shadow_shadowmode)
1445 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1446 if (r_shadow_shadowmap2ddepthtexture) return;
1447 if (r_fb.usedepthtextures)
1449 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);
1450 r_shadow_shadowmap2ddepthbuffer = NULL;
1451 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1455 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1456 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1457 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1465 void R_Shadow_ClearShadowMapTexture(void)
1467 r_viewport_t viewport;
1468 float clearcolor[4];
1470 // if they don't exist, create our textures now
1471 if (!r_shadow_shadowmap2ddepthtexture)
1472 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1473 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1474 R_Shadow_MakeVSDCT();
1476 // we're setting up to render shadowmaps, so change rendermode
1477 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1479 R_Mesh_ResetTextureState();
1480 R_Shadow_RenderMode_Reset();
1481 if (r_shadow_shadowmap2ddepthbuffer)
1482 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1484 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1485 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1486 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1490 // we have to set a viewport to clear anything in some renderpaths (D3D)
1491 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1492 R_SetViewport(&viewport);
1493 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1494 if (r_shadow_shadowmap2ddepthbuffer)
1495 GL_ColorMask(1, 1, 1, 1);
1497 GL_ColorMask(0, 0, 0, 0);
1498 switch (vid.renderpath)
1500 case RENDERPATH_GL20:
1501 case RENDERPATH_GLES2:
1502 GL_CullFace(r_refdef.view.cullface_back);
1505 Vector4Set(clearcolor, 1, 1, 1, 1);
1506 if (r_shadow_shadowmap2ddepthbuffer)
1507 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1509 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1512 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1514 int size = rsurface.rtlight->shadowmapatlassidesize;
1515 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1516 float farclip = 1.0f;
1517 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1518 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1519 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1520 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1521 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1522 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1523 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1524 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1525 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1526 if (r_shadow_shadowmap2ddepthbuffer)
1528 // completely different meaning than in depthtexture approach
1529 r_shadow_lightshadowmap_parameters[1] = 0;
1530 r_shadow_lightshadowmap_parameters[3] = -bias;
1534 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1536 float nearclip, farclip, bias;
1537 r_viewport_t viewport;
1539 float clearcolor[4];
1541 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1543 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1545 R_Mesh_ResetTextureState();
1546 R_Shadow_RenderMode_Reset();
1547 if (r_shadow_shadowmap2ddepthbuffer)
1548 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1550 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1551 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1552 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1557 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1559 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1561 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1562 R_SetViewport(&viewport);
1563 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1564 flipped = (side & 1) ^ (side >> 2);
1565 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1566 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1568 Vector4Set(clearcolor, 1,1,1,1);
1569 if (r_shadow_shadowmap2ddepthbuffer)
1570 GL_ColorMask(1,1,1,1);
1572 GL_ColorMask(0,0,0,0);
1573 switch(vid.renderpath)
1575 case RENDERPATH_GL20:
1576 case RENDERPATH_GLES2:
1577 GL_CullFace(r_refdef.view.cullface_back);
1581 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1582 r_shadow_shadowmapside = side;
1585 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1587 R_Mesh_ResetTextureState();
1590 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1591 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1592 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1593 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1596 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1597 R_Shadow_RenderMode_Reset();
1598 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1600 GL_DepthFunc(GL_EQUAL);
1601 // do global setup needed for the chosen lighting mode
1602 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1603 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1604 r_shadow_usingshadowmap2d = shadowmapping;
1605 r_shadow_rendermode = r_shadow_lightingrendermode;
1608 static const unsigned short bboxelements[36] =
1618 static const float bboxpoints[8][3] =
1630 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1633 float vertex3f[8*3];
1634 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1635 // do global setup needed for the chosen lighting mode
1636 R_Shadow_RenderMode_Reset();
1637 r_shadow_rendermode = r_shadow_lightingrendermode;
1638 R_EntityMatrix(&identitymatrix);
1639 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1640 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1641 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1643 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1645 r_shadow_usingshadowmap2d = shadowmapping;
1647 // render the lighting
1648 R_SetupShader_DeferredLight(rsurface.rtlight);
1649 for (i = 0;i < 8;i++)
1650 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1651 GL_ColorMask(1,1,1,1);
1652 GL_DepthMask(false);
1653 GL_DepthRange(0, 1);
1654 GL_PolygonOffset(0, 0);
1656 GL_DepthFunc(GL_GREATER);
1657 GL_CullFace(r_refdef.view.cullface_back);
1658 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1659 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1662 #define MAXBOUNCEGRIDSPLATSIZE 7
1663 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
1665 // these are temporary data per-frame, sorted and performed in a more
1666 // cache-friendly order than the original photons
1667 typedef struct r_shadow_bouncegrid_splatpath_s
1673 vec_t splatintensity;
1674 vec_t splatsize_current;
1675 vec_t splatsize_perstep;
1676 int remainingsplats;
1678 r_shadow_bouncegrid_splatpath_t;
1680 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
1690 r_shadow_bouncegrid_splatpath_t *path;
1692 // cull paths that fail R_CullBox in dynamic mode
1693 if (!r_shadow_bouncegrid_state.settings.staticmode
1694 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
1696 vec3_t cullmins, cullmaxs;
1697 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
1698 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
1699 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
1700 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
1701 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
1702 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
1703 if (R_CullBox(cullmins, cullmaxs))
1707 // if the light path is going upward, reverse it - we always draw down.
1708 if (originalend[2] < originalstart[2])
1710 VectorCopy(originalend, start);
1711 VectorCopy(originalstart, end);
1715 VectorCopy(originalstart, start);
1716 VectorCopy(originalend, end);
1719 // transform to texture pixels
1720 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1721 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1722 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1723 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1724 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1725 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1727 // check if we need to grow the splatpaths array
1728 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
1730 // double the limit, this will persist from frame to frame so we don't
1731 // make the same mistake each time
1732 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
1733 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
1734 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
1735 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);
1738 // divide a series of splats along the length using the maximum axis
1739 VectorSubtract(end, start, diff);
1740 // pick the best axis to trace along
1742 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
1744 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
1746 len = fabs(diff[bestaxis]);
1748 numsplats = (int)(floor(len + 0.5f));
1750 numsplats = bound(0, numsplats, 1024);
1752 VectorSubtract(originalstart, originalend, originaldir);
1753 VectorNormalize(originaldir);
1755 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
1756 VectorCopy(start, path->point);
1757 VectorScale(diff, ilen, path->step);
1758 VectorCopy(color, path->splatcolor);
1759 VectorCopy(originaldir, path->splatdir);
1760 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
1761 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
1762 path->splatintensity = VectorLength(color);
1763 path->remainingsplats = numsplats;
1766 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1768 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1775 // see if there are really any lights to render...
1776 if (enable && r_shadow_bouncegrid_static.integer)
1779 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1780 for (lightindex = 0;lightindex < range;lightindex++)
1782 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1783 if (!light || !(light->flags & flag))
1785 rtlight = &light->rtlight;
1786 // when static, we skip styled lights because they tend to change...
1787 if (rtlight->style > 0)
1789 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1790 if (!VectorLength2(lightcolor))
1800 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1802 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1803 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1804 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1805 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1807 // prevent any garbage in alignment padded areas as we'll be using memcmp
1808 memset(settings, 0, sizeof(*settings));
1810 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1811 settings->staticmode = s;
1812 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1813 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1814 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
1815 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
1816 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
1817 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1818 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1819 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1820 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1821 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1822 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1823 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1824 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
1825 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1826 settings->energyperphoton = spacing * spacing / quality;
1827 settings->spacing[0] = spacing;
1828 settings->spacing[1] = spacing;
1829 settings->spacing[2] = spacing;
1830 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1831 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1832 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1833 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1834 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1836 // bound the values for sanity
1837 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1838 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1839 settings->maxbounce = bound(0, settings->maxbounce, 16);
1840 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1841 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1842 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1845 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1856 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1858 // get the spacing values
1859 spacing[0] = settings->spacing[0];
1860 spacing[1] = settings->spacing[1];
1861 spacing[2] = settings->spacing[2];
1862 ispacing[0] = 1.0f / spacing[0];
1863 ispacing[1] = 1.0f / spacing[1];
1864 ispacing[2] = 1.0f / spacing[2];
1866 // calculate texture size enclosing entire world bounds at the spacing
1867 if (r_refdef.scene.worldmodel)
1871 qboolean bounds_set = false;
1875 // calculate bounds enclosing world lights as they should be noticably tighter
1876 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1877 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1878 for (lightindex = 0;lightindex < range;lightindex++)
1880 const vec_t *rtlmins, *rtlmaxs;
1882 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1886 rtlight = &light->rtlight;
1887 rtlmins = rtlight->cullmins;
1888 rtlmaxs = rtlight->cullmaxs;
1892 VectorCopy(rtlmins, mins);
1893 VectorCopy(rtlmaxs, maxs);
1898 mins[0] = min(mins[0], rtlmins[0]);
1899 mins[1] = min(mins[1], rtlmins[1]);
1900 mins[2] = min(mins[2], rtlmins[2]);
1901 maxs[0] = max(maxs[0], rtlmaxs[0]);
1902 maxs[1] = max(maxs[1], rtlmaxs[1]);
1903 maxs[2] = max(maxs[2], rtlmaxs[2]);
1907 // limit to no larger than the world bounds
1908 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1909 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1910 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1911 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1912 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1913 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1915 VectorMA(mins, -2.0f, spacing, mins);
1916 VectorMA(maxs, 2.0f, spacing, maxs);
1920 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1921 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1923 VectorSubtract(maxs, mins, size);
1924 // now we can calculate the resolution we want
1925 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1926 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1927 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1928 // figure out the exact texture size (honoring power of 2 if required)
1929 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1930 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1931 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1932 if (vid.support.arb_texture_non_power_of_two)
1934 resolution[0] = c[0];
1935 resolution[1] = c[1];
1936 resolution[2] = c[2];
1940 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
1941 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
1942 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
1944 size[0] = spacing[0] * resolution[0];
1945 size[1] = spacing[1] * resolution[1];
1946 size[2] = spacing[2] * resolution[2];
1948 // if dynamic we may or may not want to use the world bounds
1949 // if the dynamic size is smaller than the world bounds, use it instead
1950 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]))
1952 // we know the resolution we want
1953 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1954 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1955 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1956 // now we can calculate the texture size (power of 2 if required)
1957 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1958 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1959 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1960 if (vid.support.arb_texture_non_power_of_two)
1962 resolution[0] = c[0];
1963 resolution[1] = c[1];
1964 resolution[2] = c[2];
1968 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
1969 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
1970 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
1972 size[0] = spacing[0] * resolution[0];
1973 size[1] = spacing[1] * resolution[1];
1974 size[2] = spacing[2] * resolution[2];
1975 // center the rendering on the view
1976 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1977 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1978 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1981 // recalculate the maxs in case the resolution was not satisfactory
1982 VectorAdd(mins, size, maxs);
1984 // check if this changed the texture size
1985 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);
1986 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1987 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1988 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1989 VectorCopy(size, r_shadow_bouncegrid_state.size);
1990 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1991 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1992 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1994 // reallocate pixels for this update if needed...
1995 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1996 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1997 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1998 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1999 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2001 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2002 r_shadow_bouncegrid_state.highpixels = NULL;
2003 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2004 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2005 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2006 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2007 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2008 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2009 r_shadow_bouncegrid_state.numpixels = numpixels;
2012 // update the bouncegrid matrix to put it in the world properly
2013 memset(m, 0, sizeof(m));
2014 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2015 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2016 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2017 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2018 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2019 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2021 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2024 // enumerate world rtlights and sum the overall amount of light in the world,
2025 // from that we can calculate a scaling factor to fairly distribute photons
2026 // to all the lights
2028 // this modifies rtlight->photoncolor and rtlight->photons
2029 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2031 float normalphotonscaling;
2032 float photonscaling;
2033 float photonintensity;
2034 float photoncount = 0.0f;
2035 float lightintensity;
2041 unsigned int lightindex;
2044 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2045 for (lightindex = 0;lightindex < range2;lightindex++)
2047 if (lightindex < range)
2049 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2052 rtlight = &light->rtlight;
2053 VectorClear(rtlight->bouncegrid_photoncolor);
2054 rtlight->bouncegrid_photons = 0;
2055 rtlight->bouncegrid_hits = 0;
2056 rtlight->bouncegrid_traces = 0;
2057 rtlight->bouncegrid_effectiveradius = 0;
2058 if (!(light->flags & flag))
2060 if (settings->staticmode)
2062 // when static, we skip styled lights because they tend to change...
2063 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2066 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2071 rtlight = r_refdef.scene.lights[lightindex - range];
2072 VectorClear(rtlight->bouncegrid_photoncolor);
2073 rtlight->bouncegrid_photons = 0;
2074 rtlight->bouncegrid_hits = 0;
2075 rtlight->bouncegrid_traces = 0;
2076 rtlight->bouncegrid_effectiveradius = 0;
2078 // draw only visible lights (major speedup)
2079 radius = rtlight->radius * settings->lightradiusscale;
2080 cullmins[0] = rtlight->shadoworigin[0] - radius;
2081 cullmins[1] = rtlight->shadoworigin[1] - radius;
2082 cullmins[2] = rtlight->shadoworigin[2] - radius;
2083 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2084 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2085 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2086 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2087 if (!settings->staticmode)
2089 // skip if the expanded light box does not touch any visible leafs
2090 if (r_refdef.scene.worldmodel
2091 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2092 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2094 // skip if the expanded light box is not visible to traceline
2095 // note that PrepareLight already did this check but for a smaller box, so we
2096 // end up casting more traces per frame per light when using bouncegrid, which
2097 // is probably fine (and they use the same timer)
2098 if (r_shadow_culllights_trace.integer)
2100 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))
2101 rtlight->trace_timer = realtime;
2102 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2105 // skip if expanded light box is offscreen
2106 if (R_CullBox(cullmins, cullmaxs))
2108 // skip if overall light intensity is zero
2109 if (w * VectorLength2(rtlight->color) == 0.0f)
2112 // a light that does not emit any light before style is applied, can be
2113 // skipped entirely (it may just be a corona)
2114 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2116 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2117 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2118 // skip lights that will emit no photons
2119 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2121 // shoot particles from this light
2122 // use a calculation for the number of particles that will not
2123 // vary with lightstyle, otherwise we get randomized particle
2124 // distribution, the seeded random is only consistent for a
2125 // consistent number of particles on this light...
2126 s = rtlight->radius;
2127 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2128 if (lightindex >= range)
2129 lightintensity *= settings->dlightparticlemultiplier;
2130 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2131 photoncount += rtlight->bouncegrid_photons;
2132 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2133 // if the lightstyle happens to be off right now, we can skip actually
2134 // firing the photons, but we did have to count them in the total.
2135 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2136 // rtlight->bouncegrid_photons = 0;
2138 // the user provided an energyperphoton value which we try to use
2139 // if that results in too many photons to shoot this frame, then we cap it
2140 // which causes photons to appear/disappear from frame to frame, so we don't
2141 // like doing that in the typical case
2142 photonscaling = 1.0f;
2143 photonintensity = 1.0f;
2144 if (photoncount > settings->maxphotons)
2146 photonscaling = settings->maxphotons / photoncount;
2147 photonintensity = 1.0f / photonscaling;
2150 // modify the lights to reflect our computed scaling
2151 for (lightindex = 0; lightindex < range2; lightindex++)
2153 if (lightindex < range)
2155 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2158 rtlight = &light->rtlight;
2161 rtlight = r_refdef.scene.lights[lightindex - range];
2162 rtlight->bouncegrid_photons *= photonscaling;
2163 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2167 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2169 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2170 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2171 // we only really care about sorting by Z
2172 if (a->point[2] < b->point[2])
2174 if (a->point[2] > b->point[2])
2179 static void R_Shadow_BounceGrid_ClearPixels(void)
2181 // clear the highpixels array we'll be accumulating into
2182 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2183 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2184 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2185 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2186 r_shadow_bouncegrid_state.highpixels_index = 0;
2187 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2188 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2191 static void R_Shadow_BounceGrid_PerformSplats(void)
2193 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2194 r_shadow_bouncegrid_splatpath_t *splatpath;
2195 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2196 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2201 vec_t lightpathsize_current;
2202 vec_t lightpathsize_perstep;
2203 float splatcolor[32];
2205 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2206 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2210 // hush warnings about uninitialized data - pixelbands doesn't change but...
2211 memset(splatcolor, 0, sizeof(splatcolor));
2213 // we use this a lot, so get a local copy
2214 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2216 // sort the splats before we execute them, to reduce cache misses
2217 if (r_shadow_bouncegrid_sortlightpaths.integer)
2218 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2220 splatpath = splatpaths;
2221 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2223 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2224 // accumulate average shotcolor
2225 VectorCopy(splatpath->splatdir, dir);
2226 splatcolor[ 0] = splatpath->splatcolor[0];
2227 splatcolor[ 1] = splatpath->splatcolor[1];
2228 splatcolor[ 2] = splatpath->splatcolor[2];
2229 splatcolor[ 3] = 0.0f;
2232 // store bentnormal in case the shader has a use for it,
2233 // bentnormal is an intensity-weighted average of the directions,
2234 // and will be normalized on conversion to texture pixels.
2235 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2236 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2237 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2238 splatcolor[ 7] = splatpath->splatintensity;
2239 // for each color component (R, G, B) calculate the amount that a
2240 // direction contributes
2241 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2242 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2243 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2244 splatcolor[11] = 0.0f;
2245 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2246 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2247 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2248 splatcolor[15] = 0.0f;
2249 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2250 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2251 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2252 splatcolor[19] = 0.0f;
2253 // and do the same for negative directions
2254 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2255 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2256 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2257 splatcolor[23] = 0.0f;
2258 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2259 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2260 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2261 splatcolor[27] = 0.0f;
2262 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2263 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2264 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2265 splatcolor[31] = 0.0f;
2267 // calculate the number of steps we need to traverse this distance
2268 VectorCopy(splatpath->point, steppos);
2269 VectorCopy(splatpath->step, stepdelta);
2270 numsteps = splatpath->remainingsplats;
2271 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
2272 lightpathsize_perstep = splatpath->splatsize_perstep;
2273 for (step = 0;step < numsteps;step++)
2275 // the middle row/column/layer of each splat are full intensity
2278 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
2279 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
2280 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
2281 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
2282 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
2283 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
2284 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
2285 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
2286 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
2288 // it is within bounds... do the real work now
2289 int xi, yi, zi, band, row;
2293 float colorscale = 1.0f / lightpathsize_current;
2294 r_refdef.stats[r_stat_bouncegrid_splats]++;
2295 // accumulate light onto the pixels
2296 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
2298 pixelpos[2] = zi + 0.5f;
2299 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
2301 pixelpos[1] = yi + 0.5f;
2302 row = (zi*resolution[1] + yi)*resolution[0];
2303 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
2305 pixelpos[0] = xi + 0.5f;
2306 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
2307 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
2313 p = highpixels + 4 * (row + xi);
2314 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
2316 // add to the pixel color
2317 p[0] += splatcolor[band * 4 + 0] * w;
2318 p[1] += splatcolor[band * 4 + 1] * w;
2319 p[2] += splatcolor[band * 4 + 2] * w;
2320 p[3] += splatcolor[band * 4 + 3] * w;
2327 VectorAdd(steppos, stepdelta, steppos);
2328 lightpathsize_current += lightpathsize_perstep;
2333 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2335 const float *inpixel;
2337 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2340 unsigned int x, y, z;
2341 unsigned int resolution[3];
2342 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2343 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2345 for (z = 1;z < resolution[2]-1;z++)
2347 for (y = 1;y < resolution[1]-1;y++)
2350 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2351 inpixel = inpixels + 4*index;
2352 outpixel = outpixels + 4*index;
2353 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2355 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2356 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2357 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2358 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2365 static void R_Shadow_BounceGrid_BlurPixels(void)
2368 unsigned int resolution[3];
2370 if (!r_shadow_bouncegrid_state.settings.blur)
2373 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2375 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2376 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2377 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2378 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2381 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2383 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2385 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2387 // toggle the state, highpixels now points to pixels[3] result
2388 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2389 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2392 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2394 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2395 unsigned char *pixelsbgra8 = NULL;
2396 unsigned char *pixelbgra8;
2397 unsigned short *pixelsrgba16f = NULL;
2398 unsigned short *pixelrgba16f;
2399 float *pixelsrgba32f = NULL;
2400 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2403 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2404 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2405 unsigned int pixelband;
2406 unsigned int x, y, z;
2407 unsigned int index, bandindex;
2408 unsigned int resolution[3];
2410 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2412 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2414 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2415 r_shadow_bouncegrid_state.texture = NULL;
2418 // if bentnormals exist, we need to normalize and bias them for the shader
2422 for (z = 0;z < resolution[2]-1;z++)
2424 for (y = 0;y < resolution[1]-1;y++)
2427 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2428 highpixel = highpixels + 4*index;
2429 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2431 // only convert pixels that were hit by photons
2432 if (highpixel[3] != 0.0f)
2433 VectorNormalize(highpixel);
2434 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2435 highpixel[pixelsperband * 4 + 3] = 1.0f;
2441 // start by clearing the pixels array - we won't be writing to all of it
2443 // then process only the pixels that have at least some color, skipping
2444 // the higher bands for speed on pixels that are black
2445 switch (floatcolors)
2448 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2449 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2450 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2451 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2454 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2456 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2458 for (z = 1;z < resolution[2]-1;z++)
2460 for (y = 1;y < resolution[1]-1;y++)
2464 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2465 highpixel = highpixels + 4*index;
2466 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2468 // only convert pixels that were hit by photons
2469 if (VectorLength2(highpixel))
2471 // normalize the bentnormal now
2474 VectorNormalize(highpixel + pixelsperband * 4);
2475 highpixel[pixelsperband * 4 + 3] = 1.0f;
2477 // process all of the pixelbands for this pixel
2478 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2480 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2481 bandpixel = highpixels + 4*bandindex;
2482 c[0] = (int)(bandpixel[0]*256.0f);
2483 c[1] = (int)(bandpixel[1]*256.0f);
2484 c[2] = (int)(bandpixel[2]*256.0f);
2485 c[3] = (int)(bandpixel[3]*256.0f);
2486 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2487 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2488 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2489 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2496 if (!r_shadow_bouncegrid_state.createtexture)
2497 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2499 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);
2502 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2503 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2504 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2505 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2506 for (z = 1;z < resolution[2]-1;z++)
2508 for (y = 1;y < resolution[1]-1;y++)
2512 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2513 highpixel = highpixels + 4*index;
2514 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2516 // only convert pixels that were hit by photons
2517 if (VectorLength2(highpixel))
2519 // process all of the pixelbands for this pixel
2520 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2522 // time to have fun with IEEE 754 bit hacking...
2525 unsigned int raw[4];
2527 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2528 bandpixel = highpixels + 4*bandindex;
2529 VectorCopy4(bandpixel, u.f);
2530 VectorCopy4(u.raw, c);
2531 // this math supports negative numbers, snaps denormals to zero
2532 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2533 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2534 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2535 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2536 // this math does not support negative
2537 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2538 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2539 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2540 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2547 if (!r_shadow_bouncegrid_state.createtexture)
2548 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2550 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);
2553 // our native format happens to match, so this is easy.
2554 pixelsrgba32f = highpixels;
2556 if (!r_shadow_bouncegrid_state.createtexture)
2557 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2559 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);
2563 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2566 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2568 vec3_t bouncerandom[10];
2571 int hitsupercontentsmask;
2572 int skipsupercontentsmask;
2573 int skipmaterialflagsmask;
2577 float bounceminimumintensity2;
2579 //trace_t cliptrace2;
2580 //trace_t cliptrace3;
2581 unsigned int lightindex;
2583 randomseed_t randomseed;
2585 vec3_t baseshotcolor;
2591 vec_t distancetraveled;
2595 // compute a seed for the unstable random modes
2596 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2597 seed = realtime * 1000.0;
2599 r_shadow_bouncegrid_state.numsplatpaths = 0;
2601 // figure out what we want to interact with
2602 if (settings.hitmodels)
2603 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2605 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2606 skipsupercontentsmask = 0;
2607 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
2608 maxbounce = settings.maxbounce;
2610 for (lightindex = 0;lightindex < range2;lightindex++)
2612 if (lightindex < range)
2614 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2617 rtlight = &light->rtlight;
2620 rtlight = r_refdef.scene.lights[lightindex - range];
2621 // note that this code used to keep track of residual photons and
2622 // distribute them evenly to achieve exactly a desired photon count,
2623 // but that caused unwanted flickering in dynamic mode
2624 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2625 // skip if we won't be shooting any photons
2626 if (!shootparticles)
2628 radius = rtlight->radius * settings.lightradiusscale;
2629 //s = settings.particleintensity / shootparticles;
2630 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2631 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2632 if (VectorLength2(baseshotcolor) <= 0.0f)
2634 r_refdef.stats[r_stat_bouncegrid_lights]++;
2635 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2636 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2637 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
2639 // for seeded random we start the RNG with the position of the light
2640 if (settings.rng_seed >= 0)
2648 u.f[0] = rtlight->shadoworigin[0];
2649 u.f[1] = rtlight->shadoworigin[1];
2650 u.f[2] = rtlight->shadoworigin[2];
2652 switch (settings.rng_type)
2656 // we have to shift the seed provided by the user because the result must be odd
2657 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
2660 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
2665 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2667 VectorCopy(baseshotcolor, shotcolor);
2668 VectorCopy(rtlight->shadoworigin, clipstart);
2669 switch (settings.rng_type)
2673 VectorLehmerRandom(&randomseed, clipend);
2674 if (settings.bounceanglediffuse)
2676 // we want random to be stable, so we still have to do all the random we would have done
2677 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2678 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
2682 VectorCheeseRandom(seed, clipend);
2683 if (settings.bounceanglediffuse)
2685 // we want random to be stable, so we still have to do all the random we would have done
2686 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2687 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
2692 // we want a uniform distribution spherically, not merely within the sphere
2693 if (settings.normalizevectors)
2694 VectorNormalize(clipend);
2696 VectorMA(clipstart, radius, clipend, clipend);
2697 distancetraveled = 0.0f;
2698 for (bouncecount = 0;;bouncecount++)
2700 r_refdef.stats[r_stat_bouncegrid_traces]++;
2701 rtlight->bouncegrid_traces++;
2702 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2703 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2704 if (settings.staticmode || settings.rng_seed < 0)
2706 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2707 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2708 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);
2712 // dynamic mode fires many rays and most will match the cache from the previous frame
2713 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
2715 if (bouncecount > 0 || settings.includedirectlighting)
2718 VectorCopy(cliptrace.endpos, hitpos);
2719 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
2721 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
2722 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
2723 if (rtlight->bouncegrid_effectiveradius < s)
2724 rtlight->bouncegrid_effectiveradius = s;
2725 if (cliptrace.fraction >= 1.0f)
2727 r_refdef.stats[r_stat_bouncegrid_hits]++;
2728 rtlight->bouncegrid_hits++;
2729 if (bouncecount >= maxbounce)
2731 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2732 // also clamp the resulting color to never add energy, even if the user requests extreme values
2733 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2734 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2736 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2737 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2738 surfcolor[0] = min(surfcolor[0], 1.0f);
2739 surfcolor[1] = min(surfcolor[1], 1.0f);
2740 surfcolor[2] = min(surfcolor[2], 1.0f);
2741 VectorMultiply(shotcolor, surfcolor, shotcolor);
2742 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
2744 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2745 if (settings.bounceanglediffuse)
2747 // random direction, primarily along plane normal
2748 s = VectorDistance(cliptrace.endpos, clipend);
2749 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
2750 VectorNormalize(clipend);
2751 VectorScale(clipend, s, clipend);
2755 // reflect the remaining portion of the line across plane normal
2756 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2757 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2759 // calculate the new line start and end
2760 VectorCopy(cliptrace.endpos, clipstart);
2761 VectorAdd(clipstart, clipend, clipend);
2767 void R_Shadow_UpdateBounceGridTexture(void)
2769 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2770 r_shadow_bouncegrid_settings_t settings;
2771 qboolean enable = false;
2772 qboolean settingschanged;
2773 unsigned int range; // number of world lights
2774 unsigned int range1; // number of dynamic lights (or zero if disabled)
2775 unsigned int range2; // range+range1
2777 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2779 R_Shadow_BounceGrid_GenerateSettings(&settings);
2781 // changing intensity does not require an update
2782 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2784 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2786 // when settings change, we free everything as it is just simpler that way.
2787 if (settingschanged || !enable)
2789 // not enabled, make sure we free anything we don't need anymore.
2790 if (r_shadow_bouncegrid_state.texture)
2792 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2793 r_shadow_bouncegrid_state.texture = NULL;
2795 r_shadow_bouncegrid_state.highpixels = NULL;
2796 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2797 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2798 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2799 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2800 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2801 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2802 r_shadow_bouncegrid_state.numpixels = 0;
2803 r_shadow_bouncegrid_state.directional = false;
2809 // if all the settings seem identical to the previous update, return
2810 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2813 // store the new settings
2814 r_shadow_bouncegrid_state.settings = settings;
2816 R_Shadow_BounceGrid_UpdateSpacing();
2818 // get the range of light numbers we'll be looping over:
2819 // range = static lights
2820 // range1 = dynamic lights (optional)
2821 // range2 = range + range1
2822 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2823 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2824 range2 = range + range1;
2826 // calculate weighting factors for distributing photons among the lights
2827 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
2829 // trace the photons from lights and accumulate illumination
2830 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
2832 // clear the texture
2833 R_Shadow_BounceGrid_ClearPixels();
2835 // accumulate the light splatting into texture
2836 R_Shadow_BounceGrid_PerformSplats();
2838 // apply a mild blur filter to the texture
2839 R_Shadow_BounceGrid_BlurPixels();
2841 // convert the pixels to lower precision and upload the texture
2842 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2844 // after we compute the static lighting we don't need to keep the highpixels array around
2845 if (settings.staticmode)
2847 r_shadow_bouncegrid_state.highpixels = NULL;
2848 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2849 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2850 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2851 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2852 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2853 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2857 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2859 R_Shadow_RenderMode_Reset();
2860 GL_BlendFunc(GL_ONE, GL_ONE);
2861 GL_DepthRange(0, 1);
2862 GL_DepthTest(r_showlighting.integer < 2);
2863 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2865 GL_DepthFunc(GL_EQUAL);
2866 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2869 void R_Shadow_RenderMode_End(void)
2871 R_Shadow_RenderMode_Reset();
2872 R_Shadow_RenderMode_ActiveLight(NULL);
2874 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2875 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2878 int bboxedges[12][2] =
2897 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2899 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2901 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2902 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2903 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2904 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2907 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2908 return true; // invisible
2909 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2910 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2911 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2912 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2913 r_refdef.stats[r_stat_lights_scissored]++;
2917 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2919 // used to display how many times a surface is lit for level design purposes
2920 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2921 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2925 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])
2927 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2928 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2932 extern cvar_t gl_lightmaps;
2933 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2936 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2937 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2938 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2939 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2940 if (!r_shadow_usenormalmap.integer)
2942 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2943 VectorClear(diffusecolor);
2944 VectorClear(specularcolor);
2946 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2947 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2948 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2949 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2951 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0) && vid.support.ext_blend_subtract;
2954 VectorNegate(ambientcolor, ambientcolor);
2955 VectorNegate(diffusecolor, diffusecolor);
2956 VectorNegate(specularcolor, specularcolor);
2957 GL_BlendEquationSubtract(true);
2959 RSurf_SetupDepthAndCulling();
2960 switch (r_shadow_rendermode)
2962 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2963 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2964 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2966 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2967 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2970 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2974 GL_BlendEquationSubtract(false);
2977 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)
2979 matrix4x4_t tempmatrix = *matrix;
2980 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2982 // if this light has been compiled before, free the associated data
2983 R_RTLight_Uncompile(rtlight);
2985 // clear it completely to avoid any lingering data
2986 memset(rtlight, 0, sizeof(*rtlight));
2988 // copy the properties
2989 rtlight->matrix_lighttoworld = tempmatrix;
2990 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2991 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2992 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2993 VectorCopy(color, rtlight->color);
2994 rtlight->cubemapname[0] = 0;
2995 if (cubemapname && cubemapname[0])
2996 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2997 rtlight->shadow = shadow;
2998 rtlight->corona = corona;
2999 rtlight->style = style;
3000 rtlight->isstatic = isstatic;
3001 rtlight->coronasizescale = coronasizescale;
3002 rtlight->ambientscale = ambientscale;
3003 rtlight->diffusescale = diffusescale;
3004 rtlight->specularscale = specularscale;
3005 rtlight->flags = flags;
3007 // compute derived data
3008 //rtlight->cullradius = rtlight->radius;
3009 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3010 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3011 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3012 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3013 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3014 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3015 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3018 // compiles rtlight geometry
3019 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3020 void R_RTLight_Compile(rtlight_t *rtlight)
3023 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3024 int lighttris, shadowtris;
3025 entity_render_t *ent = r_refdef.scene.worldentity;
3026 dp_model_t *model = r_refdef.scene.worldmodel;
3027 unsigned char *data;
3029 // compile the light
3030 rtlight->compiled = true;
3031 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3032 rtlight->static_numleafs = 0;
3033 rtlight->static_numleafpvsbytes = 0;
3034 rtlight->static_leaflist = NULL;
3035 rtlight->static_leafpvs = NULL;
3036 rtlight->static_numsurfaces = 0;
3037 rtlight->static_surfacelist = NULL;
3038 rtlight->static_shadowmap_receivers = 0x3F;
3039 rtlight->static_shadowmap_casters = 0x3F;
3040 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3041 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3042 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3043 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3044 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3045 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3047 if (model && model->GetLightInfo)
3049 // this variable must be set for the CompileShadowMap code
3050 r_shadow_compilingrtlight = rtlight;
3051 R_FrameData_SetMark();
3052 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);
3053 R_FrameData_ReturnToMark();
3054 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3055 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3056 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3057 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3058 rtlight->static_numsurfaces = numsurfaces;
3059 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3060 rtlight->static_numleafs = numleafs;
3061 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3062 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3063 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3064 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3065 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3066 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3067 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3068 if (rtlight->static_numsurfaces)
3069 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3070 if (rtlight->static_numleafs)
3071 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3072 if (rtlight->static_numleafpvsbytes)
3073 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3074 if (rtlight->static_numshadowtrispvsbytes)
3075 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3076 if (rtlight->static_numlighttrispvsbytes)
3077 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3078 R_FrameData_SetMark();
3079 if (model->CompileShadowMap && rtlight->shadow)
3080 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3081 R_FrameData_ReturnToMark();
3082 // now we're done compiling the rtlight
3083 r_shadow_compilingrtlight = NULL;
3087 // use smallest available cullradius - box radius or light radius
3088 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3089 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3092 if (rtlight->static_numlighttrispvsbytes)
3093 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3094 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3098 if (rtlight->static_numshadowtrispvsbytes)
3099 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3100 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3103 if (developer_extra.integer)
3104 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);
3107 void R_RTLight_Uncompile(rtlight_t *rtlight)
3109 if (rtlight->compiled)
3111 if (rtlight->static_meshchain_shadow_shadowmap)
3112 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3113 rtlight->static_meshchain_shadow_shadowmap = NULL;
3114 // these allocations are grouped
3115 if (rtlight->static_surfacelist)
3116 Mem_Free(rtlight->static_surfacelist);
3117 rtlight->static_numleafs = 0;
3118 rtlight->static_numleafpvsbytes = 0;
3119 rtlight->static_leaflist = NULL;
3120 rtlight->static_leafpvs = NULL;
3121 rtlight->static_numsurfaces = 0;
3122 rtlight->static_surfacelist = NULL;
3123 rtlight->static_numshadowtrispvsbytes = 0;
3124 rtlight->static_shadowtrispvs = NULL;
3125 rtlight->static_numlighttrispvsbytes = 0;
3126 rtlight->static_lighttrispvs = NULL;
3127 rtlight->compiled = false;
3131 void R_Shadow_UncompileWorldLights(void)
3135 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3136 for (lightindex = 0;lightindex < range;lightindex++)
3138 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3141 R_RTLight_Uncompile(&light->rtlight);
3145 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3149 // reset the count of frustum planes
3150 // see rtlight->cached_frustumplanes definition for how much this array
3152 rtlight->cached_numfrustumplanes = 0;
3154 if (r_trippy.integer)
3157 // haven't implemented a culling path for ortho rendering
3158 if (!r_refdef.view.useperspective)
3160 // check if the light is on screen and copy the 4 planes if it is
3161 for (i = 0;i < 4;i++)
3162 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3165 for (i = 0;i < 4;i++)
3166 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3171 // generate a deformed frustum that includes the light origin, this is
3172 // used to cull shadow casting surfaces that can not possibly cast a
3173 // shadow onto the visible light-receiving surfaces, which can be a
3176 // if the light origin is onscreen the result will be 4 planes exactly
3177 // if the light origin is offscreen on only one axis the result will
3178 // be exactly 5 planes (split-side case)
3179 // if the light origin is offscreen on two axes the result will be
3180 // exactly 4 planes (stretched corner case)
3181 for (i = 0;i < 4;i++)
3183 // quickly reject standard frustum planes that put the light
3184 // origin outside the frustum
3185 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3188 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3190 // if all the standard frustum planes were accepted, the light is onscreen
3191 // otherwise we need to generate some more planes below...
3192 if (rtlight->cached_numfrustumplanes < 4)
3194 // at least one of the stock frustum planes failed, so we need to
3195 // create one or two custom planes to enclose the light origin
3196 for (i = 0;i < 4;i++)
3198 // create a plane using the view origin and light origin, and a
3199 // single point from the frustum corner set
3200 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3201 VectorNormalize(plane.normal);
3202 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3203 // see if this plane is backwards and flip it if so
3204 for (j = 0;j < 4;j++)
3205 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3209 VectorNegate(plane.normal, plane.normal);
3211 // flipped plane, test again to see if it is now valid
3212 for (j = 0;j < 4;j++)
3213 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3215 // if the plane is still not valid, then it is dividing the
3216 // frustum and has to be rejected
3220 // we have created a valid plane, compute extra info
3221 PlaneClassify(&plane);
3223 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3225 // if we've found 5 frustum planes then we have constructed a
3226 // proper split-side case and do not need to keep searching for
3227 // planes to enclose the light origin
3228 if (rtlight->cached_numfrustumplanes == 5)
3236 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3238 plane = rtlight->cached_frustumplanes[i];
3239 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));
3244 // now add the light-space box planes if the light box is rotated, as any
3245 // caster outside the oriented light box is irrelevant (even if it passed
3246 // the worldspace light box, which is axial)
3247 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3249 for (i = 0;i < 6;i++)
3253 v[i >> 1] = (i & 1) ? -1 : 1;
3254 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3255 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3256 plane.dist = VectorNormalizeLength(plane.normal);
3257 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3258 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3264 // add the world-space reduced box planes
3265 for (i = 0;i < 6;i++)
3267 VectorClear(plane.normal);
3268 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3269 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3270 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3279 // reduce all plane distances to tightly fit the rtlight cull box, which
3281 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3282 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3283 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3284 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3285 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3286 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3287 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3288 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3289 oldnum = rtlight->cached_numfrustumplanes;
3290 rtlight->cached_numfrustumplanes = 0;
3291 for (j = 0;j < oldnum;j++)
3293 // find the nearest point on the box to this plane
3294 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3295 for (i = 1;i < 8;i++)
3297 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3298 if (bestdist > dist)
3301 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);
3302 // if the nearest point is near or behind the plane, we want this
3303 // plane, otherwise the plane is useless as it won't cull anything
3304 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3306 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3307 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3314 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3316 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3318 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3320 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3321 if (mesh->sidetotals[r_shadow_shadowmapside])
3324 GL_CullFace(GL_NONE);
3325 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3326 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3327 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);
3331 else if (r_refdef.scene.worldentity->model)
3332 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);
3334 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3337 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3339 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3340 vec_t relativeshadowradius;
3341 RSurf_ActiveModelEntity(ent, false, false, false);
3342 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3343 // we need to re-init the shader for each entity because the matrix changed
3344 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3345 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3346 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3347 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3348 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3349 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3350 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3351 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3352 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3355 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3357 // set up properties for rendering light onto this entity
3358 RSurf_ActiveModelEntity(ent, true, true, false);
3359 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3360 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3361 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3362 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3365 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3367 if (!r_refdef.scene.worldmodel->DrawLight)
3370 // set up properties for rendering light onto this entity
3371 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3372 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3373 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3374 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3375 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3377 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3379 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3382 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3384 dp_model_t *model = ent->model;
3385 if (!model->DrawLight)
3388 R_Shadow_SetupEntityLight(ent);
3390 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3392 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3395 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3399 int numleafs, numsurfaces;
3400 int *leaflist, *surfacelist;
3401 unsigned char *leafpvs;
3402 unsigned char *shadowtrispvs;
3403 unsigned char *lighttrispvs;
3404 //unsigned char *surfacesides;
3405 int numlightentities;
3406 int numlightentities_noselfshadow;
3407 int numshadowentities;
3408 int numshadowentities_noselfshadow;
3409 // FIXME: bounds check lightentities and shadowentities, etc.
3410 static entity_render_t *lightentities[MAX_EDICTS];
3411 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3412 static entity_render_t *shadowentities[MAX_EDICTS];
3413 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3415 qboolean castshadows;
3417 rtlight->draw = false;
3418 rtlight->cached_numlightentities = 0;
3419 rtlight->cached_numlightentities_noselfshadow = 0;
3420 rtlight->cached_numshadowentities = 0;
3421 rtlight->cached_numshadowentities_noselfshadow = 0;
3422 rtlight->cached_numsurfaces = 0;
3423 rtlight->cached_lightentities = NULL;
3424 rtlight->cached_lightentities_noselfshadow = NULL;
3425 rtlight->cached_shadowentities = NULL;
3426 rtlight->cached_shadowentities_noselfshadow = NULL;
3427 rtlight->cached_shadowtrispvs = NULL;
3428 rtlight->cached_lighttrispvs = NULL;
3429 rtlight->cached_surfacelist = NULL;
3430 rtlight->shadowmapsidesize = 0;
3432 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3433 // skip lights that are basically invisible (color 0 0 0)
3434 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3436 // loading is done before visibility checks because loading should happen
3437 // all at once at the start of a level, not when it stalls gameplay.
3438 // (especially important to benchmarks)
3440 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3442 if (rtlight->compiled)
3443 R_RTLight_Uncompile(rtlight);
3444 R_RTLight_Compile(rtlight);
3448 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3450 // look up the light style value at this time
3451 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3452 VectorScale(rtlight->color, f, rtlight->currentcolor);
3454 if (rtlight->selected)
3456 f = 2 + sin(realtime * M_PI * 4.0);
3457 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3461 // skip if lightstyle is currently off
3462 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3465 // skip processing on corona-only lights
3469 // skip if the light box is not touching any visible leafs
3470 if (r_shadow_culllights_pvs.integer
3471 && r_refdef.scene.worldmodel
3472 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3473 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3476 // skip if the light box is not visible to traceline
3477 if (r_shadow_culllights_trace.integer)
3479 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))
3480 rtlight->trace_timer = realtime;
3481 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3485 // skip if the light box is off screen
3486 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3489 // in the typical case this will be quickly replaced by GetLightInfo
3490 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3491 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3493 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3495 // 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
3496 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3499 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3501 // compiled light, world available and can receive realtime lighting
3502 // retrieve leaf information
3503 numleafs = rtlight->static_numleafs;
3504 leaflist = rtlight->static_leaflist;
3505 leafpvs = rtlight->static_leafpvs;
3506 numsurfaces = rtlight->static_numsurfaces;
3507 surfacelist = rtlight->static_surfacelist;
3508 //surfacesides = NULL;
3509 shadowtrispvs = rtlight->static_shadowtrispvs;
3510 lighttrispvs = rtlight->static_lighttrispvs;
3512 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3514 // dynamic light, world available and can receive realtime lighting
3515 // calculate lit surfaces and leafs
3516 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);
3517 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3518 leaflist = r_shadow_buffer_leaflist;
3519 leafpvs = r_shadow_buffer_leafpvs;
3520 surfacelist = r_shadow_buffer_surfacelist;
3521 //surfacesides = r_shadow_buffer_surfacesides;
3522 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3523 lighttrispvs = r_shadow_buffer_lighttrispvs;
3524 // if the reduced leaf bounds are offscreen, skip it
3525 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3536 //surfacesides = NULL;
3537 shadowtrispvs = NULL;
3538 lighttrispvs = NULL;
3540 // check if light is illuminating any visible leafs
3543 for (i = 0; i < numleafs; i++)
3544 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3550 // make a list of lit entities and shadow casting entities
3551 numlightentities = 0;
3552 numlightentities_noselfshadow = 0;
3553 numshadowentities = 0;
3554 numshadowentities_noselfshadow = 0;
3556 // add dynamic entities that are lit by the light
3557 for (i = 0; i < r_refdef.scene.numentities; i++)
3560 entity_render_t *ent = r_refdef.scene.entities[i];
3562 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3564 // skip the object entirely if it is not within the valid
3565 // shadow-casting region (which includes the lit region)
3566 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3568 if (!(model = ent->model))
3570 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3572 // this entity wants to receive light, is visible, and is
3573 // inside the light box
3574 // TODO: check if the surfaces in the model can receive light
3575 // so now check if it's in a leaf seen by the light
3576 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))
3578 if (ent->flags & RENDER_NOSELFSHADOW)
3579 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3581 lightentities[numlightentities++] = ent;
3582 // since it is lit, it probably also casts a shadow...
3583 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3584 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3585 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3587 // note: exterior models without the RENDER_NOSELFSHADOW
3588 // flag still create a RENDER_NOSELFSHADOW shadow but
3589 // are lit normally, this means that they are
3590 // self-shadowing but do not shadow other
3591 // RENDER_NOSELFSHADOW entities such as the gun
3592 // (very weird, but keeps the player shadow off the gun)
3593 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3594 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3596 shadowentities[numshadowentities++] = ent;
3599 else if (ent->flags & RENDER_SHADOW)
3601 // this entity is not receiving light, but may still need to
3603 // TODO: check if the surfaces in the model can cast shadow
3604 // now check if it is in a leaf seen by the light
3605 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))
3607 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3608 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3609 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3611 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3612 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3614 shadowentities[numshadowentities++] = ent;
3619 // return if there's nothing at all to light
3620 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3623 // count this light in the r_speeds
3624 r_refdef.stats[r_stat_lights]++;
3626 // flag it as worth drawing later
3627 rtlight->draw = true;
3629 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3630 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3632 numshadowentities = numshadowentities_noselfshadow = 0;
3633 rtlight->castshadows = castshadows;
3635 // cache all the animated entities that cast a shadow but are not visible
3636 for (i = 0; i < numshadowentities; i++)
3637 R_AnimCache_GetEntity(shadowentities[i], false, false);
3638 for (i = 0; i < numshadowentities_noselfshadow; i++)
3639 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3641 // 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)
3642 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3644 for (i = 0; i < numshadowentities_noselfshadow; i++)
3645 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3646 numshadowentities_noselfshadow = 0;
3649 // we can convert noselfshadow to regular if there are no casters of that type
3650 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3652 for (i = 0; i < numlightentities_noselfshadow; i++)
3653 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3654 numlightentities_noselfshadow = 0;
3657 // allocate some temporary memory for rendering this light later in the frame
3658 // reusable buffers need to be copied, static data can be used as-is
3659 rtlight->cached_numlightentities = numlightentities;
3660 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3661 rtlight->cached_numshadowentities = numshadowentities;
3662 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3663 rtlight->cached_numsurfaces = numsurfaces;
3664 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3665 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3666 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3667 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3668 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3670 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3671 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3672 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3673 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3674 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3678 // compiled light data
3679 rtlight->cached_shadowtrispvs = shadowtrispvs;
3680 rtlight->cached_lighttrispvs = lighttrispvs;
3681 rtlight->cached_surfacelist = surfacelist;
3684 if (R_Shadow_ShadowMappingEnabled())
3686 // figure out the shadowmapping parameters for this light
3687 vec3_t nearestpoint;
3690 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3691 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3692 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3693 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3694 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3695 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3696 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3697 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3698 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3702 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3706 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3707 int numlightentities;
3708 int numlightentities_noselfshadow;
3709 int numshadowentities;
3710 int numshadowentities_noselfshadow;
3711 entity_render_t **lightentities;
3712 entity_render_t **lightentities_noselfshadow;
3713 entity_render_t **shadowentities;
3714 entity_render_t **shadowentities_noselfshadow;
3716 static unsigned char entitysides[MAX_EDICTS];
3717 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3723 matrix4x4_t radiustolight;
3725 // check if we cached this light this frame (meaning it is worth drawing)
3726 if (!rtlight->draw || !rtlight->castshadows)
3729 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3730 if (rtlight->shadowmapatlassidesize == 0)
3732 rtlight->castshadows = false;
3736 // set up a scissor rectangle for this light
3737 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3740 // don't let sound skip if going slow
3741 if (r_refdef.scene.extraupdate)
3744 numlightentities = rtlight->cached_numlightentities;
3745 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3746 numshadowentities = rtlight->cached_numshadowentities;
3747 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3748 numsurfaces = rtlight->cached_numsurfaces;
3749 lightentities = rtlight->cached_lightentities;
3750 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3751 shadowentities = rtlight->cached_shadowentities;
3752 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3753 shadowtrispvs = rtlight->cached_shadowtrispvs;
3754 lighttrispvs = rtlight->cached_lighttrispvs;
3755 surfacelist = rtlight->cached_surfacelist;
3757 // make this the active rtlight for rendering purposes
3758 R_Shadow_RenderMode_ActiveLight(rtlight);
3760 radiustolight = rtlight->matrix_worldtolight;
3761 Matrix4x4_Abs(&radiustolight);
3763 size = rtlight->shadowmapatlassidesize;
3764 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3766 surfacesides = NULL;
3771 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3773 castermask = rtlight->static_shadowmap_casters;
3774 receivermask = rtlight->static_shadowmap_receivers;
3778 surfacesides = r_shadow_buffer_surfacesides;
3779 for (i = 0; i < numsurfaces; i++)
3781 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3782 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3783 castermask |= surfacesides[i];
3784 receivermask |= surfacesides[i];
3789 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3790 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3791 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3792 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3794 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3798 for (i = 0; i < numshadowentities; i++)
3799 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3800 for (i = 0; i < numshadowentities_noselfshadow; i++)
3801 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3804 // there is no need to render shadows for sides that have no receivers...
3805 castermask &= receivermask;
3807 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3809 // render shadow casters into shadowmaps for this light
3810 for (side = 0; side < 6; side++)
3812 int bit = 1 << side;
3813 if (castermask & bit)
3815 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3817 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3818 for (i = 0; i < numshadowentities; i++)
3819 if (entitysides[i] & bit)
3820 R_Shadow_DrawEntityShadow(shadowentities[i]);
3821 for (i = 0; i < numshadowentities_noselfshadow; i++)
3822 if (entitysides_noselfshadow[i] & bit)
3823 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3826 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3827 if (numshadowentities_noselfshadow)
3829 for (side = 0; side < 6; side++)
3831 int bit = 1 << side;
3832 if (castermask & bit)
3834 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3836 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3837 for (i = 0; i < numshadowentities; i++)
3838 if (entitysides[i] & bit)
3839 R_Shadow_DrawEntityShadow(shadowentities[i]);
3845 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3849 unsigned char *shadowtrispvs, *lighttrispvs;
3850 int numlightentities;
3851 int numlightentities_noselfshadow;
3852 int numshadowentities;
3853 int numshadowentities_noselfshadow;
3854 entity_render_t **lightentities;
3855 entity_render_t **lightentities_noselfshadow;
3856 entity_render_t **shadowentities;
3857 entity_render_t **shadowentities_noselfshadow;
3859 qboolean castshadows;
3861 // check if we cached this light this frame (meaning it is worth drawing)
3865 // set up a scissor rectangle for this light
3866 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3869 // don't let sound skip if going slow
3870 if (r_refdef.scene.extraupdate)
3873 numlightentities = rtlight->cached_numlightentities;
3874 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3875 numshadowentities = rtlight->cached_numshadowentities;
3876 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3877 numsurfaces = rtlight->cached_numsurfaces;
3878 lightentities = rtlight->cached_lightentities;
3879 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3880 shadowentities = rtlight->cached_shadowentities;
3881 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3882 shadowtrispvs = rtlight->cached_shadowtrispvs;
3883 lighttrispvs = rtlight->cached_lighttrispvs;
3884 surfacelist = rtlight->cached_surfacelist;
3885 castshadows = rtlight->castshadows;
3887 // make this the active rtlight for rendering purposes
3888 R_Shadow_RenderMode_ActiveLight(rtlight);
3890 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3892 // optionally draw the illuminated areas
3893 // for performance analysis by level designers
3894 R_Shadow_RenderMode_VisibleLighting(false);
3896 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3897 for (i = 0;i < numlightentities;i++)
3898 R_Shadow_DrawEntityLight(lightentities[i]);
3899 for (i = 0;i < numlightentities_noselfshadow;i++)
3900 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3903 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3907 float shadowmapoffsetnoselfshadow = 0;
3908 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3909 Matrix4x4_Abs(&radiustolight);
3911 size = rtlight->shadowmapatlassidesize;
3912 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3914 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3916 if (rtlight->cached_numshadowentities_noselfshadow)
3917 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3919 // render lighting using the depth texture as shadowmap
3920 // draw lighting in the unmasked areas
3921 if (numsurfaces + numlightentities)
3923 R_Shadow_RenderMode_Lighting(false, true, false);
3924 // draw lighting in the unmasked areas
3926 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3927 for (i = 0; i < numlightentities; i++)
3928 R_Shadow_DrawEntityLight(lightentities[i]);
3930 // offset to the noselfshadow part of the atlas and draw those too
3931 if (numlightentities_noselfshadow)
3933 R_Shadow_RenderMode_Lighting(false, true, true);
3934 for (i = 0; i < numlightentities_noselfshadow; i++)
3935 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3938 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3939 if (r_shadow_usingdeferredprepass)
3940 R_Shadow_RenderMode_DrawDeferredLight(true);
3944 // draw lighting in the unmasked areas
3945 R_Shadow_RenderMode_Lighting(false, false, false);
3947 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3948 for (i = 0;i < numlightentities;i++)
3949 R_Shadow_DrawEntityLight(lightentities[i]);
3950 for (i = 0;i < numlightentities_noselfshadow;i++)
3951 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3953 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3954 if (r_shadow_usingdeferredprepass)
3955 R_Shadow_RenderMode_DrawDeferredLight(false);
3959 static void R_Shadow_FreeDeferred(void)
3961 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3962 r_shadow_prepassgeometryfbo = 0;
3964 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3965 r_shadow_prepasslightingdiffusespecularfbo = 0;
3967 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3968 r_shadow_prepasslightingdiffusefbo = 0;
3970 if (r_shadow_prepassgeometrydepthbuffer)
3971 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3972 r_shadow_prepassgeometrydepthbuffer = NULL;
3974 if (r_shadow_prepassgeometrynormalmaptexture)
3975 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3976 r_shadow_prepassgeometrynormalmaptexture = NULL;
3978 if (r_shadow_prepasslightingdiffusetexture)
3979 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3980 r_shadow_prepasslightingdiffusetexture = NULL;
3982 if (r_shadow_prepasslightingspeculartexture)
3983 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3984 r_shadow_prepasslightingspeculartexture = NULL;
3987 void R_Shadow_DrawPrepass(void)
3991 entity_render_t *ent;
3992 float clearcolor[4];
3994 R_Mesh_ResetTextureState();
3996 GL_ColorMask(1,1,1,1);
3997 GL_BlendFunc(GL_ONE, GL_ZERO);
4000 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4001 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4002 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4003 if (r_timereport_active)
4004 R_TimeReport("prepasscleargeom");
4006 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4007 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4008 if (r_timereport_active)
4009 R_TimeReport("prepassworld");
4011 for (i = 0;i < r_refdef.scene.numentities;i++)
4013 if (!r_refdef.viewcache.entityvisible[i])
4015 ent = r_refdef.scene.entities[i];
4016 if (ent->model && ent->model->DrawPrepass != NULL)
4017 ent->model->DrawPrepass(ent);
4020 if (r_timereport_active)
4021 R_TimeReport("prepassmodels");
4023 GL_DepthMask(false);
4024 GL_ColorMask(1,1,1,1);
4027 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4028 Vector4Set(clearcolor, 0, 0, 0, 0);
4029 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4030 if (r_timereport_active)
4031 R_TimeReport("prepassclearlit");
4033 R_Shadow_RenderMode_Begin();
4035 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4036 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4038 R_Shadow_RenderMode_End();
4040 if (r_timereport_active)
4041 R_TimeReport("prepasslights");
4044 #define MAX_SCENELIGHTS 65536
4045 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4047 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4049 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4051 r_shadow_scenemaxlights *= 2;
4052 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4053 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4055 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4059 void R_Shadow_DrawLightSprites(void);
4060 void R_Shadow_PrepareLights(void)
4069 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4070 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4071 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4073 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4074 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4075 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4076 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4077 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4078 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4079 r_shadow_shadowmapborder != shadowmapborder ||
4080 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4081 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4082 R_Shadow_FreeShadowMaps();
4084 r_shadow_usingshadowmaportho = false;
4086 switch (vid.renderpath)
4088 case RENDERPATH_GL20:
4090 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4092 r_shadow_usingdeferredprepass = false;
4093 if (r_shadow_prepass_width)
4094 R_Shadow_FreeDeferred();
4095 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4099 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4101 R_Shadow_FreeDeferred();
4103 r_shadow_usingdeferredprepass = true;
4104 r_shadow_prepass_width = vid.width;
4105 r_shadow_prepass_height = vid.height;
4106 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4107 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);
4108 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);
4109 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);
4111 // set up the geometry pass fbo (depth + normalmap)
4112 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4113 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4114 // render depth into a renderbuffer and other important properties into the normalmap texture
4116 // set up the lighting pass fbo (diffuse + specular)
4117 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4118 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4119 // render diffuse into one texture and specular into another,
4120 // with depth and normalmap bound as textures,
4121 // with depth bound as attachment as well
4123 // set up the lighting pass fbo (diffuse)
4124 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4125 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4126 // render diffuse into one texture,
4127 // with depth and normalmap bound as textures,
4128 // with depth bound as attachment as well
4132 case RENDERPATH_GLES2:
4133 r_shadow_usingdeferredprepass = false;
4137 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);
4139 r_shadow_scenenumlights = 0;
4140 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4141 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4142 for (lightindex = 0; lightindex < range; lightindex++)
4144 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4145 if (light && (light->flags & flag))
4147 R_Shadow_PrepareLight(&light->rtlight);
4148 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4151 if (r_refdef.scene.rtdlight)
4153 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4155 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4156 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4159 else if (gl_flashblend.integer)
4161 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4163 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4164 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4165 VectorScale(rtlight->color, f, rtlight->currentcolor);
4169 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4170 if (r_shadow_debuglight.integer >= 0)
4172 r_shadow_scenenumlights = 0;
4173 lightindex = r_shadow_debuglight.integer;
4174 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4177 R_Shadow_PrepareLight(&light->rtlight);
4178 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4182 // if we're doing shadowmaps we need to prepare the atlas layout now
4183 if (R_Shadow_ShadowMappingEnabled())
4187 // allocate shadowmaps in the atlas now
4188 // 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...
4189 for (lod = 0; lod < 16; lod++)
4191 int packing_success = 0;
4192 int packing_failure = 0;
4193 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4194 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4195 if (r_shadow_shadowmapatlas_modelshadows_size)
4196 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);
4197 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4199 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4200 int size = rtlight->shadowmapsidesize >> lod;
4202 if (!rtlight->castshadows)
4204 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4207 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4208 if (rtlight->cached_numshadowentities_noselfshadow)
4210 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4212 rtlight->shadowmapatlassidesize = size;
4217 // note down that we failed to pack this one, it will have to disable shadows
4218 rtlight->shadowmapatlassidesize = 0;
4222 // generally everything fits and we stop here on the first iteration
4223 if (packing_failure == 0)
4228 if (r_editlights.integer)
4229 R_Shadow_DrawLightSprites();
4232 void R_Shadow_DrawShadowMaps(void)
4234 R_Shadow_RenderMode_Begin();
4235 R_Shadow_RenderMode_ActiveLight(NULL);
4237 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4238 R_Shadow_ClearShadowMapTexture();
4240 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4241 if (r_shadow_shadowmapatlas_modelshadows_size)
4243 R_Shadow_DrawModelShadowMaps();
4244 // don't let sound skip if going slow
4245 if (r_refdef.scene.extraupdate)
4249 if (R_Shadow_ShadowMappingEnabled())
4252 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4253 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4256 R_Shadow_RenderMode_End();
4259 void R_Shadow_DrawLights(void)
4263 R_Shadow_RenderMode_Begin();
4265 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4266 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4268 R_Shadow_RenderMode_End();
4271 #define MAX_MODELSHADOWS 1024
4272 static int r_shadow_nummodelshadows;
4273 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4275 void R_Shadow_PrepareModelShadows(void)
4278 float scale, size, radius, dot1, dot2;
4279 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4280 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4281 entity_render_t *ent;
4283 r_shadow_nummodelshadows = 0;
4284 r_shadow_shadowmapatlas_modelshadows_size = 0;
4286 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4289 size = r_shadow_shadowmaptexturesize / 4;
4290 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4291 radius = 0.5f * size / scale;
4293 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4294 VectorCopy(prvmshadowdir, shadowdir);
4295 VectorNormalize(shadowdir);
4296 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4297 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4298 if (fabs(dot1) <= fabs(dot2))
4299 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4301 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4302 VectorNormalize(shadowforward);
4303 CrossProduct(shadowdir, shadowforward, shadowright);
4304 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4305 VectorCopy(prvmshadowfocus, shadowfocus);
4306 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4307 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4308 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4309 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4310 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4312 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4314 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4315 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4316 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4317 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4318 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4319 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4321 for (i = 0; i < r_refdef.scene.numentities; i++)
4323 ent = r_refdef.scene.entities[i];
4324 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4326 // cast shadows from anything of the map (submodels are optional)
4327 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4329 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4331 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4332 R_AnimCache_GetEntity(ent, false, false);
4336 if (r_shadow_nummodelshadows)
4338 r_shadow_shadowmapatlas_modelshadows_x = 0;
4339 r_shadow_shadowmapatlas_modelshadows_y = 0;
4340 r_shadow_shadowmapatlas_modelshadows_size = size;
4344 static void R_Shadow_DrawModelShadowMaps(void)
4347 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4348 entity_render_t *ent;
4349 vec3_t relativelightorigin;
4350 vec3_t relativelightdirection, relativeforward, relativeright;
4351 vec3_t relativeshadowmins, relativeshadowmaxs;
4352 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4353 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4355 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4356 r_viewport_t viewport;
4358 size = r_shadow_shadowmapatlas_modelshadows_size;
4359 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4360 radius = 0.5f / scale;
4361 nearclip = -r_shadows_throwdistance.value;
4362 farclip = r_shadows_throwdistance.value;
4363 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);
4365 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4366 r_shadow_modelshadowmap_parameters[0] = size;
4367 r_shadow_modelshadowmap_parameters[1] = size;
4368 r_shadow_modelshadowmap_parameters[2] = 1.0;
4369 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4370 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4371 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4372 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4373 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4374 r_shadow_usingshadowmaportho = true;
4376 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4377 VectorCopy(prvmshadowdir, shadowdir);
4378 VectorNormalize(shadowdir);
4379 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4380 VectorCopy(prvmshadowfocus, shadowfocus);
4381 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4382 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4383 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4384 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4385 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4386 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4387 if (fabs(dot1) <= fabs(dot2))
4388 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4390 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4391 VectorNormalize(shadowforward);
4392 VectorM(scale, shadowforward, &m[0]);
4393 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4395 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4396 CrossProduct(shadowdir, shadowforward, shadowright);
4397 VectorM(scale, shadowright, &m[4]);
4398 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4399 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4400 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4401 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4402 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4403 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);
4404 R_SetViewport(&viewport);
4406 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4408 // render into a slightly restricted region so that the borders of the
4409 // shadowmap area fade away, rather than streaking across everything
4410 // outside the usable area
4411 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4413 for (i = 0;i < r_shadow_nummodelshadows;i++)
4415 ent = r_shadow_modelshadows[i];
4416 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4417 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4418 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4419 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4420 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4421 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4422 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4423 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4424 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4425 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4426 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4427 RSurf_ActiveModelEntity(ent, false, false, false);
4428 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4429 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4435 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4437 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4439 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4440 Cvar_SetValueQuick(&r_test, 0);
4445 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4446 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4447 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4448 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4449 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4450 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4453 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4456 vec3_t centerorigin;
4457 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4460 // if it's too close, skip it
4461 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4463 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4466 if (usequery && r_numqueries + 2 <= r_maxqueries)
4468 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4469 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4470 // 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
4471 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4473 switch(vid.renderpath)
4475 case RENDERPATH_GL20:
4476 case RENDERPATH_GLES2:
4477 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4479 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4480 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4481 GL_DepthFunc(GL_ALWAYS);
4482 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4483 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4484 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4485 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4486 GL_DepthFunc(GL_LEQUAL);
4487 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4488 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4489 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4490 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4491 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4497 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4500 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4502 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4505 unsigned int occlude = 0;
4506 GLint allpixels = 0, visiblepixels = 0;
4508 // now we have to check the query result
4509 if (rtlight->corona_queryindex_visiblepixels)
4511 switch(vid.renderpath)
4513 case RENDERPATH_GL20:
4514 case RENDERPATH_GLES2:
4515 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4516 // See if we can use the GPU-side method to prevent implicit sync
4517 if (vid.support.arb_query_buffer_object) {
4518 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4519 if (!r_shadow_occlusion_buf) {
4520 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
4521 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
4522 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
4524 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
4526 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
4527 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
4528 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4529 occlude = MATERIALFLAG_OCCLUDE;
4530 cscale *= rtlight->corona_visibility;
4535 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4536 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4537 if (visiblepixels < 1 || allpixels < 1)
4539 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4540 cscale *= rtlight->corona_visibility;
4550 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4553 VectorScale(rtlight->currentcolor, cscale, color);
4554 if (VectorLength(color) > (1.0f / 256.0f))
4557 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4560 VectorNegate(color, color);
4561 GL_BlendEquationSubtract(true);
4563 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4564 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);
4565 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
4567 GL_BlendEquationSubtract(false);
4571 void R_Shadow_DrawCoronas(void)
4574 qboolean usequery = false;
4579 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4581 if (r_fb.water.renderingscene)
4583 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4584 R_EntityMatrix(&identitymatrix);
4586 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4588 // check occlusion of coronas
4589 // use GL_ARB_occlusion_query if available
4590 // otherwise use raytraces
4592 switch (vid.renderpath)
4594 case RENDERPATH_GL20:
4595 case RENDERPATH_GLES2:
4596 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4597 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4600 GL_ColorMask(0,0,0,0);
4601 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4602 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4605 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4606 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4608 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4611 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4612 GL_BlendFunc(GL_ONE, GL_ZERO);
4613 GL_CullFace(GL_NONE);
4614 GL_DepthMask(false);
4615 GL_DepthRange(0, 1);
4616 GL_PolygonOffset(0, 0);
4618 R_Mesh_ResetTextureState();
4619 R_SetupShader_Generic_NoTexture(false, false);
4624 for (lightindex = 0;lightindex < range;lightindex++)
4626 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4629 rtlight = &light->rtlight;
4630 rtlight->corona_visibility = 0;
4631 rtlight->corona_queryindex_visiblepixels = 0;
4632 rtlight->corona_queryindex_allpixels = 0;
4633 if (!(rtlight->flags & flag))
4635 if (rtlight->corona <= 0)
4637 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4639 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4641 for (i = 0;i < r_refdef.scene.numlights;i++)
4643 rtlight = r_refdef.scene.lights[i];
4644 rtlight->corona_visibility = 0;
4645 rtlight->corona_queryindex_visiblepixels = 0;
4646 rtlight->corona_queryindex_allpixels = 0;
4647 if (!(rtlight->flags & flag))
4649 if (rtlight->corona <= 0)
4651 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4654 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4656 // now draw the coronas using the query data for intensity info
4657 for (lightindex = 0;lightindex < range;lightindex++)
4659 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4662 rtlight = &light->rtlight;
4663 if (rtlight->corona_visibility <= 0)
4665 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4667 for (i = 0;i < r_refdef.scene.numlights;i++)
4669 rtlight = r_refdef.scene.lights[i];
4670 if (rtlight->corona_visibility <= 0)
4672 if (gl_flashblend.integer)
4673 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4675 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4681 static dlight_t *R_Shadow_NewWorldLight(void)
4683 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4686 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)
4690 // 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
4692 // validate parameters
4696 // copy to light properties
4697 VectorCopy(origin, light->origin);
4698 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4699 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4700 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4702 light->color[0] = max(color[0], 0);
4703 light->color[1] = max(color[1], 0);
4704 light->color[2] = max(color[2], 0);
4706 light->color[0] = color[0];
4707 light->color[1] = color[1];
4708 light->color[2] = color[2];
4709 light->radius = max(radius, 0);
4710 light->style = style;
4711 light->shadow = shadowenable;
4712 light->corona = corona;
4713 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4714 light->coronasizescale = coronasizescale;
4715 light->ambientscale = ambientscale;
4716 light->diffusescale = diffusescale;
4717 light->specularscale = specularscale;
4718 light->flags = flags;
4720 // update renderable light data
4721 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4722 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);
4725 static void R_Shadow_FreeWorldLight(dlight_t *light)
4727 if (r_shadow_selectedlight == light)
4728 r_shadow_selectedlight = NULL;
4729 R_RTLight_Uncompile(&light->rtlight);
4730 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4733 void R_Shadow_ClearWorldLights(void)
4737 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4738 for (lightindex = 0;lightindex < range;lightindex++)
4740 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4742 R_Shadow_FreeWorldLight(light);
4744 r_shadow_selectedlight = NULL;
4747 static void R_Shadow_SelectLight(dlight_t *light)
4749 if (r_shadow_selectedlight)
4750 r_shadow_selectedlight->selected = false;
4751 r_shadow_selectedlight = light;
4752 if (r_shadow_selectedlight)
4753 r_shadow_selectedlight->selected = true;
4756 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4758 // this is never batched (there can be only one)
4760 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4761 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4762 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4765 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4770 skinframe_t *skinframe;
4773 // this is never batched (due to the ent parameter changing every time)
4774 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4775 const dlight_t *light = (dlight_t *)ent;
4778 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4781 VectorScale(light->color, intensity, spritecolor);
4782 if (VectorLength(spritecolor) < 0.1732f)
4783 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4784 if (VectorLength(spritecolor) > 1.0f)
4785 VectorNormalize(spritecolor);
4787 // draw light sprite
4788 if (light->cubemapname[0] && !light->shadow)
4789 skinframe = r_editlights_sprcubemapnoshadowlight;
4790 else if (light->cubemapname[0])
4791 skinframe = r_editlights_sprcubemaplight;
4792 else if (!light->shadow)
4793 skinframe = r_editlights_sprnoshadowlight;
4795 skinframe = r_editlights_sprlight;
4797 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);
4798 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4800 // draw selection sprite if light is selected
4801 if (light->selected)
4803 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4804 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4805 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4809 void R_Shadow_DrawLightSprites(void)
4813 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4814 for (lightindex = 0;lightindex < range;lightindex++)
4816 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4818 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4820 if (!r_editlights_lockcursor)
4821 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4824 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4829 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4830 if (lightindex >= range)
4832 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4835 rtlight = &light->rtlight;
4836 //if (!(rtlight->flags & flag))
4838 VectorCopy(rtlight->shadoworigin, origin);
4839 *radius = rtlight->radius;
4840 VectorCopy(rtlight->color, color);
4844 static void R_Shadow_SelectLightInView(void)
4846 float bestrating, rating, temp[3];
4850 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4854 if (r_editlights_lockcursor)
4856 for (lightindex = 0;lightindex < range;lightindex++)
4858 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4861 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4862 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4865 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4866 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)
4868 bestrating = rating;
4873 R_Shadow_SelectLight(best);
4876 void R_Shadow_LoadWorldLights(void)
4878 int n, a, style, shadow, flags;
4879 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4880 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4881 if (cl.worldmodel == NULL)
4883 Con_Print("No map loaded.\n");
4886 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4887 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4897 for (;COM_Parse(t, true) && strcmp(
4898 if (COM_Parse(t, true))
4900 if (com_token[0] == '!')
4903 origin[0] = atof(com_token+1);
4906 origin[0] = atof(com_token);
4911 while (*s && *s != '\n' && *s != '\r')
4917 // check for modifier flags
4924 #if _MSC_VER >= 1400
4925 #define sscanf sscanf_s
4927 cubemapname[sizeof(cubemapname)-1] = 0;
4928 #if MAX_QPATH != 128
4929 #error update this code if MAX_QPATH changes
4931 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
4932 #if _MSC_VER >= 1400
4933 , sizeof(cubemapname)
4935 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4938 flags = LIGHTFLAG_REALTIMEMODE;
4946 coronasizescale = 0.25f;
4948 VectorClear(angles);
4951 if (a < 9 || !strcmp(cubemapname, "\"\""))
4953 // remove quotes on cubemapname
4954 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4957 namelen = strlen(cubemapname) - 2;
4958 memmove(cubemapname, cubemapname + 1, namelen);
4959 cubemapname[namelen] = '\0';
4963 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);
4966 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4974 Con_Printf("invalid rtlights file \"%s\"\n", name);
4975 Mem_Free(lightsstring);
4979 void R_Shadow_SaveWorldLights(void)
4983 size_t bufchars, bufmaxchars;
4985 char name[MAX_QPATH];
4986 char line[MAX_INPUTLINE];
4987 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4988 // I hate lines which are 3 times my screen size :( --blub
4991 if (cl.worldmodel == NULL)
4993 Con_Print("No map loaded.\n");
4996 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4997 bufchars = bufmaxchars = 0;
4999 for (lightindex = 0;lightindex < range;lightindex++)
5001 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5004 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5005 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);
5006 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5007 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]);
5009 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);
5010 if (bufchars + strlen(line) > bufmaxchars)
5012 bufmaxchars = bufchars + strlen(line) + 2048;
5014 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5018 memcpy(buf, oldbuf, bufchars);
5024 memcpy(buf + bufchars, line, strlen(line));
5025 bufchars += strlen(line);
5029 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5034 void R_Shadow_LoadLightsFile(void)
5037 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5038 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5039 if (cl.worldmodel == NULL)
5041 Con_Print("No map loaded.\n");
5044 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5045 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5053 while (*s && *s != '\n' && *s != '\r')
5059 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);
5063 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);
5066 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5067 radius = bound(15, radius, 4096);
5068 VectorScale(color, (2.0f / (8388608.0f)), color);
5069 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5077 Con_Printf("invalid lights file \"%s\"\n", name);
5078 Mem_Free(lightsstring);
5082 // tyrlite/hmap2 light types in the delay field
5083 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5085 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5097 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5098 char key[256], value[MAX_INPUTLINE];
5101 if (cl.worldmodel == NULL)
5103 Con_Print("No map loaded.\n");
5106 // try to load a .ent file first
5107 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5108 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5109 // and if that is not found, fall back to the bsp file entity string
5111 data = cl.worldmodel->brush.entities;
5114 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5116 type = LIGHTTYPE_MINUSX;
5117 origin[0] = origin[1] = origin[2] = 0;
5118 originhack[0] = originhack[1] = originhack[2] = 0;
5119 angles[0] = angles[1] = angles[2] = 0;
5120 color[0] = color[1] = color[2] = 1;
5121 light[0] = light[1] = light[2] = 1;light[3] = 300;
5122 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5132 if (!COM_ParseToken_Simple(&data, false, false, true))
5134 if (com_token[0] == '}')
5135 break; // end of entity
5136 if (com_token[0] == '_')
5137 strlcpy(key, com_token + 1, sizeof(key));
5139 strlcpy(key, com_token, sizeof(key));
5140 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5141 key[strlen(key)-1] = 0;
5142 if (!COM_ParseToken_Simple(&data, false, false, true))
5144 strlcpy(value, com_token, sizeof(value));
5146 // now that we have the key pair worked out...
5147 if (!strcmp("light", key))
5149 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5153 light[0] = vec[0] * (1.0f / 256.0f);
5154 light[1] = vec[0] * (1.0f / 256.0f);
5155 light[2] = vec[0] * (1.0f / 256.0f);
5161 light[0] = vec[0] * (1.0f / 255.0f);
5162 light[1] = vec[1] * (1.0f / 255.0f);
5163 light[2] = vec[2] * (1.0f / 255.0f);
5167 else if (!strcmp("delay", key))
5169 else if (!strcmp("origin", key))
5170 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5171 else if (!strcmp("angle", key))
5172 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5173 else if (!strcmp("angles", key))
5174 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5175 else if (!strcmp("color", key))
5176 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5177 else if (!strcmp("wait", key))
5178 fadescale = atof(value);
5179 else if (!strcmp("classname", key))
5181 if (!strncmp(value, "light", 5))
5184 if (!strcmp(value, "light_fluoro"))
5189 overridecolor[0] = 1;
5190 overridecolor[1] = 1;
5191 overridecolor[2] = 1;
5193 if (!strcmp(value, "light_fluorospark"))
5198 overridecolor[0] = 1;
5199 overridecolor[1] = 1;
5200 overridecolor[2] = 1;
5202 if (!strcmp(value, "light_globe"))
5207 overridecolor[0] = 1;
5208 overridecolor[1] = 0.8;
5209 overridecolor[2] = 0.4;
5211 if (!strcmp(value, "light_flame_large_yellow"))
5216 overridecolor[0] = 1;
5217 overridecolor[1] = 0.5;
5218 overridecolor[2] = 0.1;
5220 if (!strcmp(value, "light_flame_small_yellow"))
5225 overridecolor[0] = 1;
5226 overridecolor[1] = 0.5;
5227 overridecolor[2] = 0.1;
5229 if (!strcmp(value, "light_torch_small_white"))
5234 overridecolor[0] = 1;
5235 overridecolor[1] = 0.5;
5236 overridecolor[2] = 0.1;
5238 if (!strcmp(value, "light_torch_small_walltorch"))
5243 overridecolor[0] = 1;
5244 overridecolor[1] = 0.5;
5245 overridecolor[2] = 0.1;
5249 else if (!strcmp("style", key))
5250 style = atoi(value);
5251 else if (!strcmp("skin", key))
5252 skin = (int)atof(value);
5253 else if (!strcmp("pflags", key))
5254 pflags = (int)atof(value);
5255 //else if (!strcmp("effects", key))
5256 // effects = (int)atof(value);
5257 else if (cl.worldmodel->type == mod_brushq3)
5259 if (!strcmp("scale", key))
5260 lightscale = atof(value);
5261 if (!strcmp("fade", key))
5262 fadescale = atof(value);
5267 if (lightscale <= 0)
5271 if (color[0] == color[1] && color[0] == color[2])
5273 color[0] *= overridecolor[0];
5274 color[1] *= overridecolor[1];
5275 color[2] *= overridecolor[2];
5277 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5278 color[0] = color[0] * light[0];
5279 color[1] = color[1] * light[1];
5280 color[2] = color[2] * light[2];
5283 case LIGHTTYPE_MINUSX:
5285 case LIGHTTYPE_RECIPX:
5287 VectorScale(color, (1.0f / 16.0f), color);
5289 case LIGHTTYPE_RECIPXX:
5291 VectorScale(color, (1.0f / 16.0f), color);
5294 case LIGHTTYPE_NONE:
5298 case LIGHTTYPE_MINUSXX:
5301 VectorAdd(origin, originhack, origin);
5303 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);
5306 Mem_Free(entfiledata);
5310 static void R_Shadow_SetCursorLocationForView(void)
5313 vec3_t dest, endpos;
5315 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5316 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5317 if (trace.fraction < 1)
5319 dist = trace.fraction * r_editlights_cursordistance.value;
5320 push = r_editlights_cursorpushback.value;
5324 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5325 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5329 VectorClear( endpos );
5331 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5332 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5333 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5336 void R_Shadow_UpdateWorldLightSelection(void)
5338 if (r_editlights.integer)
5340 R_Shadow_SetCursorLocationForView();
5341 R_Shadow_SelectLightInView();
5344 R_Shadow_SelectLight(NULL);
5347 static void R_Shadow_EditLights_Clear_f(void)
5349 R_Shadow_ClearWorldLights();
5352 void R_Shadow_EditLights_Reload_f(void)
5356 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5357 R_Shadow_ClearWorldLights();
5358 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5360 R_Shadow_LoadWorldLights();
5361 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5362 R_Shadow_LoadLightsFile();
5364 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5366 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5367 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5371 static void R_Shadow_EditLights_Save_f(void)
5375 R_Shadow_SaveWorldLights();
5378 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5380 R_Shadow_ClearWorldLights();
5381 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5384 static void R_Shadow_EditLights_ImportLightsFile_f(void)
5386 R_Shadow_ClearWorldLights();
5387 R_Shadow_LoadLightsFile();
5390 static void R_Shadow_EditLights_Spawn_f(void)
5393 if (!r_editlights.integer)
5395 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5398 if (Cmd_Argc() != 1)
5400 Con_Print("r_editlights_spawn does not take parameters\n");
5403 color[0] = color[1] = color[2] = 1;
5404 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5407 static void R_Shadow_EditLights_Edit_f(void)
5409 vec3_t origin, angles, color;
5410 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5411 int style, shadows, flags, normalmode, realtimemode;
5412 char cubemapname[MAX_INPUTLINE];
5413 if (!r_editlights.integer)
5415 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5418 if (!r_shadow_selectedlight)
5420 Con_Print("No selected light.\n");
5423 VectorCopy(r_shadow_selectedlight->origin, origin);
5424 VectorCopy(r_shadow_selectedlight->angles, angles);
5425 VectorCopy(r_shadow_selectedlight->color, color);
5426 radius = r_shadow_selectedlight->radius;
5427 style = r_shadow_selectedlight->style;
5428 if (r_shadow_selectedlight->cubemapname)
5429 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5432 shadows = r_shadow_selectedlight->shadow;
5433 corona = r_shadow_selectedlight->corona;
5434 coronasizescale = r_shadow_selectedlight->coronasizescale;
5435 ambientscale = r_shadow_selectedlight->ambientscale;
5436 diffusescale = r_shadow_selectedlight->diffusescale;
5437 specularscale = r_shadow_selectedlight->specularscale;
5438 flags = r_shadow_selectedlight->flags;
5439 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5440 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5441 if (!strcmp(Cmd_Argv(1), "origin"))
5443 if (Cmd_Argc() != 5)
5445 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5448 origin[0] = atof(Cmd_Argv(2));
5449 origin[1] = atof(Cmd_Argv(3));
5450 origin[2] = atof(Cmd_Argv(4));
5452 else if (!strcmp(Cmd_Argv(1), "originscale"))
5454 if (Cmd_Argc() != 5)
5456 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5459 origin[0] *= atof(Cmd_Argv(2));
5460 origin[1] *= atof(Cmd_Argv(3));
5461 origin[2] *= atof(Cmd_Argv(4));
5463 else if (!strcmp(Cmd_Argv(1), "originx"))
5465 if (Cmd_Argc() != 3)
5467 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5470 origin[0] = atof(Cmd_Argv(2));
5472 else if (!strcmp(Cmd_Argv(1), "originy"))
5474 if (Cmd_Argc() != 3)
5476 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5479 origin[1] = atof(Cmd_Argv(2));
5481 else if (!strcmp(Cmd_Argv(1), "originz"))
5483 if (Cmd_Argc() != 3)
5485 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5488 origin[2] = atof(Cmd_Argv(2));
5490 else if (!strcmp(Cmd_Argv(1), "move"))
5492 if (Cmd_Argc() != 5)
5494 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5497 origin[0] += atof(Cmd_Argv(2));
5498 origin[1] += atof(Cmd_Argv(3));
5499 origin[2] += atof(Cmd_Argv(4));
5501 else if (!strcmp(Cmd_Argv(1), "movex"))
5503 if (Cmd_Argc() != 3)
5505 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5508 origin[0] += atof(Cmd_Argv(2));
5510 else if (!strcmp(Cmd_Argv(1), "movey"))
5512 if (Cmd_Argc() != 3)
5514 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5517 origin[1] += atof(Cmd_Argv(2));
5519 else if (!strcmp(Cmd_Argv(1), "movez"))
5521 if (Cmd_Argc() != 3)
5523 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5526 origin[2] += atof(Cmd_Argv(2));
5528 else if (!strcmp(Cmd_Argv(1), "angles"))
5530 if (Cmd_Argc() != 5)
5532 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5535 angles[0] = atof(Cmd_Argv(2));
5536 angles[1] = atof(Cmd_Argv(3));
5537 angles[2] = atof(Cmd_Argv(4));
5539 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5541 if (Cmd_Argc() != 3)
5543 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5546 angles[0] = atof(Cmd_Argv(2));
5548 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5550 if (Cmd_Argc() != 3)
5552 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5555 angles[1] = atof(Cmd_Argv(2));
5557 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5559 if (Cmd_Argc() != 3)
5561 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5564 angles[2] = atof(Cmd_Argv(2));
5566 else if (!strcmp(Cmd_Argv(1), "color"))
5568 if (Cmd_Argc() != 5)
5570 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5573 color[0] = atof(Cmd_Argv(2));
5574 color[1] = atof(Cmd_Argv(3));
5575 color[2] = atof(Cmd_Argv(4));
5577 else if (!strcmp(Cmd_Argv(1), "radius"))
5579 if (Cmd_Argc() != 3)
5581 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5584 radius = atof(Cmd_Argv(2));
5586 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5588 if (Cmd_Argc() == 3)
5590 double scale = atof(Cmd_Argv(2));
5597 if (Cmd_Argc() != 5)
5599 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5602 color[0] *= atof(Cmd_Argv(2));
5603 color[1] *= atof(Cmd_Argv(3));
5604 color[2] *= atof(Cmd_Argv(4));
5607 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5609 if (Cmd_Argc() != 3)
5611 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5614 radius *= atof(Cmd_Argv(2));
5616 else if (!strcmp(Cmd_Argv(1), "style"))
5618 if (Cmd_Argc() != 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5623 style = atoi(Cmd_Argv(2));
5625 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5629 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5632 if (Cmd_Argc() == 3)
5633 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5637 else if (!strcmp(Cmd_Argv(1), "shadows"))
5639 if (Cmd_Argc() != 3)
5641 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5644 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5646 else if (!strcmp(Cmd_Argv(1), "corona"))
5648 if (Cmd_Argc() != 3)
5650 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5653 corona = atof(Cmd_Argv(2));
5655 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5657 if (Cmd_Argc() != 3)
5659 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5662 coronasizescale = atof(Cmd_Argv(2));
5664 else if (!strcmp(Cmd_Argv(1), "ambient"))
5666 if (Cmd_Argc() != 3)
5668 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5671 ambientscale = atof(Cmd_Argv(2));
5673 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5675 if (Cmd_Argc() != 3)
5677 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5680 diffusescale = atof(Cmd_Argv(2));
5682 else if (!strcmp(Cmd_Argv(1), "specular"))
5684 if (Cmd_Argc() != 3)
5686 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5689 specularscale = atof(Cmd_Argv(2));
5691 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5693 if (Cmd_Argc() != 3)
5695 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5698 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5700 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5702 if (Cmd_Argc() != 3)
5704 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5707 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5711 Con_Print("usage: r_editlights_edit [property] [value]\n");
5712 Con_Print("Selected light's properties:\n");
5713 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5714 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5715 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5716 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5717 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5718 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5719 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5720 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5721 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5722 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5723 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5724 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5725 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5726 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5729 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5730 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5733 static void R_Shadow_EditLights_EditAll_f(void)
5736 dlight_t *light, *oldselected;
5739 if (!r_editlights.integer)
5741 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5745 oldselected = r_shadow_selectedlight;
5746 // EditLights doesn't seem to have a "remove" command or something so:
5747 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5748 for (lightindex = 0;lightindex < range;lightindex++)
5750 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5753 R_Shadow_SelectLight(light);
5754 R_Shadow_EditLights_Edit_f();
5756 // return to old selected (to not mess editing once selection is locked)
5757 R_Shadow_SelectLight(oldselected);
5760 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5762 int lightnumber, lightcount;
5763 size_t lightindex, range;
5768 if (!r_editlights.integer)
5771 // update cvars so QC can query them
5772 if (r_shadow_selectedlight)
5774 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5775 Cvar_SetQuick(&r_editlights_current_origin, temp);
5776 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5777 Cvar_SetQuick(&r_editlights_current_angles, temp);
5778 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5779 Cvar_SetQuick(&r_editlights_current_color, temp);
5780 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5781 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5782 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5783 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5784 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5785 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5786 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5787 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5788 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5789 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5790 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5793 // draw properties on screen
5794 if (!r_editlights_drawproperties.integer)
5796 x = vid_conwidth.value - 320;
5798 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5801 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5802 for (lightindex = 0;lightindex < range;lightindex++)
5804 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5807 if (light == r_shadow_selectedlight)
5808 lightnumber = (int)lightindex;
5811 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;
5812 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;
5814 if (r_shadow_selectedlight == NULL)
5816 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;
5817 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;
5818 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;
5819 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;
5820 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;
5821 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;
5822 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;
5823 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;
5824 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;
5825 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;
5826 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;
5827 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;
5828 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;
5829 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;
5830 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;
5832 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;
5833 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;
5834 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;
5835 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;
5836 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;
5837 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;
5838 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;
5839 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;
5840 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;
5841 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;
5844 static void R_Shadow_EditLights_ToggleShadow_f(void)
5846 if (!r_editlights.integer)
5848 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5851 if (!r_shadow_selectedlight)
5853 Con_Print("No selected light.\n");
5856 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);
5859 static void R_Shadow_EditLights_ToggleCorona_f(void)
5861 if (!r_editlights.integer)
5863 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5866 if (!r_shadow_selectedlight)
5868 Con_Print("No selected light.\n");
5871 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);
5874 static void R_Shadow_EditLights_Remove_f(void)
5876 if (!r_editlights.integer)
5878 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5881 if (!r_shadow_selectedlight)
5883 Con_Print("No selected light.\n");
5886 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5887 r_shadow_selectedlight = NULL;
5890 static void R_Shadow_EditLights_Help_f(void)
5893 "Documentation on r_editlights system:\n"
5895 "r_editlights : enable/disable editing mode\n"
5896 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5897 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5898 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5899 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5900 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5902 "r_editlights_help : this help\n"
5903 "r_editlights_clear : remove all lights\n"
5904 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5905 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5906 "r_editlights_save : save to .rtlights file\n"
5907 "r_editlights_spawn : create a light with default settings\n"
5908 "r_editlights_edit command : edit selected light - more documentation below\n"
5909 "r_editlights_remove : remove selected light\n"
5910 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5911 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5912 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5914 "origin x y z : set light location\n"
5915 "originx x: set x component of light location\n"
5916 "originy y: set y component of light location\n"
5917 "originz z: set z component of light location\n"
5918 "move x y z : adjust light location\n"
5919 "movex x: adjust x component of light location\n"
5920 "movey y: adjust y component of light location\n"
5921 "movez z: adjust z component of light location\n"
5922 "angles x y z : set light angles\n"
5923 "anglesx x: set x component of light angles\n"
5924 "anglesy y: set y component of light angles\n"
5925 "anglesz z: set z component of light angles\n"
5926 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5927 "radius radius : set radius (size) of light\n"
5928 "colorscale grey : multiply color of light (1 does nothing)\n"
5929 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5930 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5931 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5932 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5933 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5934 "cubemap basename : set filter cubemap of light\n"
5935 "shadows 1/0 : turn on/off shadows\n"
5936 "corona n : set corona intensity\n"
5937 "coronasize n : set corona size (0-1)\n"
5938 "ambient n : set ambient intensity (0-1)\n"
5939 "diffuse n : set diffuse intensity (0-1)\n"
5940 "specular n : set specular intensity (0-1)\n"
5941 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5942 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5943 "<nothing> : print light properties to console\n"
5947 static void R_Shadow_EditLights_CopyInfo_f(void)
5949 if (!r_editlights.integer)
5951 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5954 if (!r_shadow_selectedlight)
5956 Con_Print("No selected light.\n");
5959 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5960 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5961 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5962 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5963 if (r_shadow_selectedlight->cubemapname)
5964 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5966 r_shadow_bufferlight.cubemapname[0] = 0;
5967 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5968 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5969 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5970 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5971 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5972 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5973 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5976 static void R_Shadow_EditLights_PasteInfo_f(void)
5978 if (!r_editlights.integer)
5980 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5983 if (!r_shadow_selectedlight)
5985 Con_Print("No selected light.\n");
5988 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);
5991 static void R_Shadow_EditLights_Lock_f(void)
5993 if (!r_editlights.integer)
5995 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5998 if (r_editlights_lockcursor)
6000 r_editlights_lockcursor = false;
6003 if (!r_shadow_selectedlight)
6005 Con_Print("No selected light to lock on.\n");
6008 r_editlights_lockcursor = true;
6011 static void R_Shadow_EditLights_Init(void)
6013 Cvar_RegisterVariable(&r_editlights);
6014 Cvar_RegisterVariable(&r_editlights_cursordistance);
6015 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6016 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6017 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6018 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6019 Cvar_RegisterVariable(&r_editlights_drawproperties);
6020 Cvar_RegisterVariable(&r_editlights_current_origin);
6021 Cvar_RegisterVariable(&r_editlights_current_angles);
6022 Cvar_RegisterVariable(&r_editlights_current_color);
6023 Cvar_RegisterVariable(&r_editlights_current_radius);
6024 Cvar_RegisterVariable(&r_editlights_current_corona);
6025 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6026 Cvar_RegisterVariable(&r_editlights_current_style);
6027 Cvar_RegisterVariable(&r_editlights_current_shadows);
6028 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6029 Cvar_RegisterVariable(&r_editlights_current_ambient);
6030 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6031 Cvar_RegisterVariable(&r_editlights_current_specular);
6032 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6033 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6034 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6035 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6036 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)");
6037 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6038 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6039 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6040 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)");
6041 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6042 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6043 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6044 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6045 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6046 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6047 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)");
6048 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6054 =============================================================================
6058 =============================================================================
6061 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6063 int i, numlights, flag, q;
6066 float relativepoint[3];
6071 float sa[3], sx[3], sy[3], sz[3], sd[3];
6074 // use first order spherical harmonics to combine directional lights
6075 for (q = 0; q < 3; q++)
6076 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6078 if (flags & LP_LIGHTMAP)
6080 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6082 float tempambient[3];
6083 for (q = 0; q < 3; q++)
6084 tempambient[q] = color[q] = relativepoint[q] = 0;
6085 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6086 // calculate a weighted average light direction as well
6087 intensity = VectorLength(color);
6088 for (q = 0; q < 3; q++)
6090 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6091 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6092 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6093 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6094 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6099 // unlit map - fullbright but scaled by lightmapintensity
6100 for (q = 0; q < 3; q++)
6101 sa[q] += lightmapintensity;
6105 if (flags & LP_RTWORLD)
6107 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6108 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6109 for (i = 0; i < numlights; i++)
6111 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6114 light = &dlight->rtlight;
6115 if (!(light->flags & flag))
6118 lightradius2 = light->radius * light->radius;
6119 VectorSubtract(light->shadoworigin, p, relativepoint);
6120 dist2 = VectorLength2(relativepoint);
6121 if (dist2 >= lightradius2)
6123 dist = sqrt(dist2) / light->radius;
6124 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6125 if (intensity <= 0.0f)
6127 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)
6129 for (q = 0; q < 3; q++)
6130 color[q] = light->currentcolor[q] * intensity;
6131 intensity = VectorLength(color);
6132 VectorNormalize(relativepoint);
6133 for (q = 0; q < 3; q++)
6135 sa[q] += 0.5f * color[q];
6136 sx[q] += relativepoint[0] * color[q];
6137 sy[q] += relativepoint[1] * color[q];
6138 sz[q] += relativepoint[2] * color[q];
6139 sd[q] += intensity * relativepoint[q];
6142 // FIXME: sample bouncegrid too!
6145 if (flags & LP_DYNLIGHT)
6148 for (i = 0;i < r_refdef.scene.numlights;i++)
6150 light = r_refdef.scene.lights[i];
6152 lightradius2 = light->radius * light->radius;
6153 VectorSubtract(light->shadoworigin, p, relativepoint);
6154 dist2 = VectorLength2(relativepoint);
6155 if (dist2 >= lightradius2)
6157 dist = sqrt(dist2) / light->radius;
6158 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6159 if (intensity <= 0.0f)
6161 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)
6163 for (q = 0; q < 3; q++)
6164 color[q] = light->currentcolor[q] * intensity;
6165 intensity = VectorLength(color);
6166 VectorNormalize(relativepoint);
6167 for (q = 0; q < 3; q++)
6169 sa[q] += 0.5f * color[q];
6170 sx[q] += relativepoint[0] * color[q];
6171 sy[q] += relativepoint[1] * color[q];
6172 sz[q] += relativepoint[2] * color[q];
6173 sd[q] += intensity * relativepoint[q];
6178 // calculate the weighted-average light direction (bentnormal)
6179 for (q = 0; q < 3; q++)
6180 lightdir[q] = sd[q];
6181 VectorNormalize(lightdir);
6182 for (q = 0; q < 3; q++)
6184 // extract the diffuse color along the chosen direction and scale it
6185 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6186 // subtract some of diffuse from ambient
6187 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;