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 rtexture_t *r_shadow_attenuation2dtexture;
108 rtexture_t *r_shadow_attenuation3dtexture;
109 skinframe_t *r_shadow_lightcorona;
110 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
111 rtexture_t *r_shadow_shadowmap2ddepthtexture;
112 rtexture_t *r_shadow_shadowmapvsdcttexture;
114 GLuint r_shadow_prepassgeometryfbo;
115 GLuint r_shadow_prepasslightingdiffusespecularfbo;
116 GLuint r_shadow_prepasslightingdiffusefbo;
117 int r_shadow_prepass_width;
118 int r_shadow_prepass_height;
119 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
120 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
121 rtexture_t *r_shadow_prepasslightingdiffusetexture;
122 rtexture_t *r_shadow_prepasslightingspeculartexture;
124 int r_shadow_viewfbo;
125 rtexture_t *r_shadow_viewdepthtexture;
126 rtexture_t *r_shadow_viewcolortexture;
129 int r_shadow_viewwidth;
130 int r_shadow_viewheight;
132 // lights are reloaded when this changes
133 char r_shadow_mapname[MAX_QPATH];
135 // buffer for doing corona fading
136 unsigned int r_shadow_occlusion_buf = 0;
138 // used only for light filters (cubemaps)
139 rtexturepool_t *r_shadow_filters_texturepool;
141 cvar_t r_shadow_bumpscale_basetexture = {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"};
142 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"};
143 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
144 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"};
145 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)"};
146 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
147 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)"};
148 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"};
149 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
150 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
151 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
152 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
153 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
154 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
155 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
156 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
157 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
158 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)"};
159 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
160 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
161 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
162 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
163 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)"};
164 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)"};
165 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"};
166 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
167 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
168 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"};
169 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)"};
170 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
171 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)"};
172 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
173 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)"};
174 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
175 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
176 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
177 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"};
178 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..."};
179 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"};
180 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"};
181 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
182 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
183 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
184 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
185 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
186 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
187 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
188 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
189 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
190 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"};
191 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"};
192 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
193 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
194 cvar_t r_shadow_culllights_trace_expand = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
195 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"};
196 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)"};
197 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)"};
198 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"};
199 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)"};
200 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"};
201 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"};
202 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" };
203 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)"};
204 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"};
205 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"};
206 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
207 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)"};
208 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)"};
209 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"};
210 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)"};
211 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
212 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"};
213 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
214 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
215 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
216 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"};
217 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)"};
218 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
219 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"};
220 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"};
221 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)" };
222 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"};
223 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
224 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" };
225 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)" };
226 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"};
227 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
228 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" };
229 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
230 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"};
231 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"};
232 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
233 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)" };
234 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
235 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
236 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"};
237 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!"};
238 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
239 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
240 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
241 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
242 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
243 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
244 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
245 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
246 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
247 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
248 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
249 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
250 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
251 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
252 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
253 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
254 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
255 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
256 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
257 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
258 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
259 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
261 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
263 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
264 #define ATTENTABLESIZE 256
265 // 1D gradient, 2D circle and 3D sphere attenuation textures
266 #define ATTEN1DSIZE 32
267 #define ATTEN2DSIZE 64
268 #define ATTEN3DSIZE 32
270 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
271 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
272 static float r_shadow_attentable[ATTENTABLESIZE+1];
274 rtlight_t *r_shadow_compilingrtlight;
275 static memexpandablearray_t r_shadow_worldlightsarray;
276 dlight_t *r_shadow_selectedlight;
277 dlight_t r_shadow_bufferlight;
278 vec3_t r_editlights_cursorlocation;
279 qboolean r_editlights_lockcursor;
281 extern int con_vislines;
283 void R_Shadow_UncompileWorldLights(void);
284 void R_Shadow_ClearWorldLights(void);
285 void R_Shadow_SaveWorldLights(void);
286 void R_Shadow_LoadWorldLights(void);
287 void R_Shadow_LoadLightsFile(void);
288 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
289 void R_Shadow_EditLights_Reload_f(void);
290 void R_Shadow_ValidateCvars(void);
291 static void R_Shadow_MakeTextures(void);
293 #define EDLIGHTSPRSIZE 8
294 skinframe_t *r_editlights_sprcursor;
295 skinframe_t *r_editlights_sprlight;
296 skinframe_t *r_editlights_sprnoshadowlight;
297 skinframe_t *r_editlights_sprcubemaplight;
298 skinframe_t *r_editlights_sprcubemapnoshadowlight;
299 skinframe_t *r_editlights_sprselection;
301 static void R_Shadow_DrawModelShadowMaps(void);
302 static void R_Shadow_MakeShadowMap(int texturesize);
303 static void R_Shadow_MakeVSDCT(void);
304 static void R_Shadow_SetShadowMode(void)
306 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
307 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
308 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
309 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
310 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
311 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
312 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
313 r_shadow_shadowmapsampler = false;
314 r_shadow_shadowmappcf = 0;
315 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
316 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
317 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
318 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
320 switch(vid.renderpath)
322 case RENDERPATH_GL20:
323 if(r_shadow_shadowmapfilterquality < 0)
325 if (!r_fb.usedepthtextures)
326 r_shadow_shadowmappcf = 1;
327 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
329 r_shadow_shadowmapsampler = true;
330 r_shadow_shadowmappcf = 1;
332 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
333 r_shadow_shadowmappcf = 1;
334 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
335 r_shadow_shadowmappcf = 1;
337 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
341 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
342 switch (r_shadow_shadowmapfilterquality)
347 r_shadow_shadowmappcf = 1;
350 r_shadow_shadowmappcf = 1;
353 r_shadow_shadowmappcf = 2;
357 if (!r_fb.usedepthtextures)
358 r_shadow_shadowmapsampler = false;
359 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
361 case RENDERPATH_GLES2:
366 if(R_CompileShader_CheckStaticParms())
370 qboolean R_Shadow_ShadowMappingEnabled(void)
372 switch (r_shadow_shadowmode)
374 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
381 static void R_Shadow_FreeShadowMaps(void)
383 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
385 R_Shadow_SetShadowMode();
387 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
391 if (r_shadow_shadowmap2ddepthtexture)
392 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
393 r_shadow_shadowmap2ddepthtexture = NULL;
395 if (r_shadow_shadowmap2ddepthbuffer)
396 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
397 r_shadow_shadowmap2ddepthbuffer = NULL;
399 if (r_shadow_shadowmapvsdcttexture)
400 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
401 r_shadow_shadowmapvsdcttexture = NULL;
404 static void r_shadow_start(void)
406 // allocate vertex processing arrays
407 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
408 r_shadow_attenuationgradienttexture = NULL;
409 r_shadow_attenuation2dtexture = NULL;
410 r_shadow_attenuation3dtexture = NULL;
411 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
412 r_shadow_shadowmap2ddepthtexture = NULL;
413 r_shadow_shadowmap2ddepthbuffer = NULL;
414 r_shadow_shadowmapvsdcttexture = NULL;
415 r_shadow_shadowmapmaxsize = 0;
416 r_shadow_shadowmaptexturesize = 0;
417 r_shadow_shadowmapfilterquality = -1;
418 r_shadow_shadowmapdepthbits = 0;
419 r_shadow_shadowmapvsdct = false;
420 r_shadow_shadowmapsampler = false;
421 r_shadow_shadowmappcf = 0;
424 R_Shadow_FreeShadowMaps();
426 r_shadow_texturepool = NULL;
427 r_shadow_filters_texturepool = NULL;
428 R_Shadow_ValidateCvars();
429 R_Shadow_MakeTextures();
430 r_shadow_scenemaxlights = 0;
431 r_shadow_scenenumlights = 0;
432 r_shadow_scenelightlist = NULL;
433 maxshadowtriangles = 0;
434 shadowelements = NULL;
435 maxshadowvertices = 0;
436 shadowvertex3f = NULL;
444 shadowmarklist = NULL;
449 shadowsideslist = NULL;
450 r_shadow_buffer_numleafpvsbytes = 0;
451 r_shadow_buffer_visitingleafpvs = NULL;
452 r_shadow_buffer_leafpvs = NULL;
453 r_shadow_buffer_leaflist = NULL;
454 r_shadow_buffer_numsurfacepvsbytes = 0;
455 r_shadow_buffer_surfacepvs = NULL;
456 r_shadow_buffer_surfacelist = NULL;
457 r_shadow_buffer_surfacesides = NULL;
458 r_shadow_buffer_numshadowtrispvsbytes = 0;
459 r_shadow_buffer_shadowtrispvs = NULL;
460 r_shadow_buffer_numlighttrispvsbytes = 0;
461 r_shadow_buffer_lighttrispvs = NULL;
463 r_shadow_usingdeferredprepass = false;
464 r_shadow_prepass_width = r_shadow_prepass_height = 0;
466 // determine renderpath specific capabilities, we don't need to figure
467 // these out per frame...
468 switch(vid.renderpath)
470 case RENDERPATH_GL20:
471 r_shadow_bouncegrid_state.allowdirectionalshading = true;
472 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
474 case RENDERPATH_GLES2:
475 // for performance reasons, do not use directional shading on GLES devices
476 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
481 static void R_Shadow_FreeDeferred(void);
482 static void r_shadow_shutdown(void)
485 R_Shadow_UncompileWorldLights();
487 R_Shadow_FreeShadowMaps();
489 r_shadow_usingdeferredprepass = false;
490 if (r_shadow_prepass_width)
491 R_Shadow_FreeDeferred();
492 r_shadow_prepass_width = r_shadow_prepass_height = 0;
495 r_shadow_scenemaxlights = 0;
496 r_shadow_scenenumlights = 0;
497 if (r_shadow_scenelightlist)
498 Mem_Free(r_shadow_scenelightlist);
499 r_shadow_scenelightlist = NULL;
500 r_shadow_bouncegrid_state.highpixels = NULL;
501 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
502 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
503 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
504 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
505 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
506 r_shadow_bouncegrid_state.maxsplatpaths = 0;
507 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
508 r_shadow_attenuationgradienttexture = NULL;
509 r_shadow_attenuation2dtexture = NULL;
510 r_shadow_attenuation3dtexture = NULL;
511 R_FreeTexturePool(&r_shadow_texturepool);
512 R_FreeTexturePool(&r_shadow_filters_texturepool);
513 maxshadowtriangles = 0;
515 Mem_Free(shadowelements);
516 shadowelements = NULL;
518 Mem_Free(shadowvertex3f);
519 shadowvertex3f = NULL;
522 Mem_Free(vertexupdate);
525 Mem_Free(vertexremap);
531 Mem_Free(shadowmark);
534 Mem_Free(shadowmarklist);
535 shadowmarklist = NULL;
540 Mem_Free(shadowsides);
543 Mem_Free(shadowsideslist);
544 shadowsideslist = NULL;
545 r_shadow_buffer_numleafpvsbytes = 0;
546 if (r_shadow_buffer_visitingleafpvs)
547 Mem_Free(r_shadow_buffer_visitingleafpvs);
548 r_shadow_buffer_visitingleafpvs = NULL;
549 if (r_shadow_buffer_leafpvs)
550 Mem_Free(r_shadow_buffer_leafpvs);
551 r_shadow_buffer_leafpvs = NULL;
552 if (r_shadow_buffer_leaflist)
553 Mem_Free(r_shadow_buffer_leaflist);
554 r_shadow_buffer_leaflist = NULL;
555 r_shadow_buffer_numsurfacepvsbytes = 0;
556 if (r_shadow_buffer_surfacepvs)
557 Mem_Free(r_shadow_buffer_surfacepvs);
558 r_shadow_buffer_surfacepvs = NULL;
559 if (r_shadow_buffer_surfacelist)
560 Mem_Free(r_shadow_buffer_surfacelist);
561 r_shadow_buffer_surfacelist = NULL;
562 if (r_shadow_buffer_surfacesides)
563 Mem_Free(r_shadow_buffer_surfacesides);
564 r_shadow_buffer_surfacesides = NULL;
565 r_shadow_buffer_numshadowtrispvsbytes = 0;
566 if (r_shadow_buffer_shadowtrispvs)
567 Mem_Free(r_shadow_buffer_shadowtrispvs);
568 r_shadow_buffer_numlighttrispvsbytes = 0;
569 if (r_shadow_buffer_lighttrispvs)
570 Mem_Free(r_shadow_buffer_lighttrispvs);
573 static void r_shadow_newmap(void)
575 r_shadow_bouncegrid_state.highpixels = NULL;
576 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
577 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
578 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
579 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
580 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
581 r_shadow_bouncegrid_state.maxsplatpaths = 0;
582 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
583 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
584 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
585 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
586 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
587 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
588 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
589 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
590 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
591 R_Shadow_EditLights_Reload_f();
594 void R_Shadow_Init(void)
596 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
597 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
598 Cvar_RegisterVariable(&r_shadow_usebihculling);
599 Cvar_RegisterVariable(&r_shadow_usenormalmap);
600 Cvar_RegisterVariable(&r_shadow_debuglight);
601 Cvar_RegisterVariable(&r_shadow_deferred);
602 Cvar_RegisterVariable(&r_shadow_gloss);
603 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
604 Cvar_RegisterVariable(&r_shadow_glossintensity);
605 Cvar_RegisterVariable(&r_shadow_glossexponent);
606 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
607 Cvar_RegisterVariable(&r_shadow_glossexact);
608 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
609 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
610 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
611 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
612 Cvar_RegisterVariable(&r_shadow_projectdistance);
613 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
614 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
615 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
616 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
617 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
618 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
619 Cvar_RegisterVariable(&r_shadow_realtime_world);
620 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
621 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
622 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
623 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
624 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
625 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
626 Cvar_RegisterVariable(&r_shadow_scissor);
627 Cvar_RegisterVariable(&r_shadow_shadowmapping);
628 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
629 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
630 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
631 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
632 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
633 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
634 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
635 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
636 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
637 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
638 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
639 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
640 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
641 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
642 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
643 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
644 Cvar_RegisterVariable(&r_shadow_texture3d);
645 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
646 Cvar_RegisterVariable(&r_shadow_culllights_trace);
647 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
648 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
649 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
650 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
651 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
652 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
653 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
654 Cvar_RegisterVariable(&r_shadow_bouncegrid);
655 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
656 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
657 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
658 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
659 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
660 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
661 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
662 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
663 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
664 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
665 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
666 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
667 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
668 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
669 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
670 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
671 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
672 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
673 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
674 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
675 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
676 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
677 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
678 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
679 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
680 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
681 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
682 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
683 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
684 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
685 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
686 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
687 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
688 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
689 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
690 Cvar_RegisterVariable(&r_coronas);
691 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
692 Cvar_RegisterVariable(&r_coronas_occlusionquery);
693 Cvar_RegisterVariable(&gl_flashblend);
694 R_Shadow_EditLights_Init();
695 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
696 r_shadow_scenemaxlights = 0;
697 r_shadow_scenenumlights = 0;
698 r_shadow_scenelightlist = NULL;
699 maxshadowtriangles = 0;
700 shadowelements = NULL;
701 maxshadowvertices = 0;
702 shadowvertex3f = NULL;
710 shadowmarklist = NULL;
715 shadowsideslist = NULL;
716 r_shadow_buffer_numleafpvsbytes = 0;
717 r_shadow_buffer_visitingleafpvs = NULL;
718 r_shadow_buffer_leafpvs = NULL;
719 r_shadow_buffer_leaflist = NULL;
720 r_shadow_buffer_numsurfacepvsbytes = 0;
721 r_shadow_buffer_surfacepvs = NULL;
722 r_shadow_buffer_surfacelist = NULL;
723 r_shadow_buffer_surfacesides = NULL;
724 r_shadow_buffer_shadowtrispvs = NULL;
725 r_shadow_buffer_lighttrispvs = NULL;
726 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
729 matrix4x4_t matrix_attenuationxyz =
732 {0.5, 0.0, 0.0, 0.5},
733 {0.0, 0.5, 0.0, 0.5},
734 {0.0, 0.0, 0.5, 0.5},
739 matrix4x4_t matrix_attenuationz =
742 {0.0, 0.0, 0.5, 0.5},
743 {0.0, 0.0, 0.0, 0.5},
744 {0.0, 0.0, 0.0, 0.5},
749 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
751 numvertices = ((numvertices + 255) & ~255) * vertscale;
752 numtriangles = ((numtriangles + 255) & ~255) * triscale;
753 // make sure shadowelements is big enough for this volume
754 if (maxshadowtriangles < numtriangles)
756 maxshadowtriangles = numtriangles;
758 Mem_Free(shadowelements);
759 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
761 // make sure shadowvertex3f is big enough for this volume
762 if (maxshadowvertices < numvertices)
764 maxshadowvertices = numvertices;
766 Mem_Free(shadowvertex3f);
767 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
771 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
773 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
774 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
775 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
776 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
777 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
779 if (r_shadow_buffer_visitingleafpvs)
780 Mem_Free(r_shadow_buffer_visitingleafpvs);
781 if (r_shadow_buffer_leafpvs)
782 Mem_Free(r_shadow_buffer_leafpvs);
783 if (r_shadow_buffer_leaflist)
784 Mem_Free(r_shadow_buffer_leaflist);
785 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
786 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
787 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
788 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
790 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
792 if (r_shadow_buffer_surfacepvs)
793 Mem_Free(r_shadow_buffer_surfacepvs);
794 if (r_shadow_buffer_surfacelist)
795 Mem_Free(r_shadow_buffer_surfacelist);
796 if (r_shadow_buffer_surfacesides)
797 Mem_Free(r_shadow_buffer_surfacesides);
798 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
799 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
800 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
801 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
803 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
805 if (r_shadow_buffer_shadowtrispvs)
806 Mem_Free(r_shadow_buffer_shadowtrispvs);
807 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
808 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
810 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
812 if (r_shadow_buffer_lighttrispvs)
813 Mem_Free(r_shadow_buffer_lighttrispvs);
814 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
815 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
819 void R_Shadow_PrepareShadowMark(int numtris)
821 // make sure shadowmark is big enough for this volume
822 if (maxshadowmark < numtris)
824 maxshadowmark = numtris;
826 Mem_Free(shadowmark);
828 Mem_Free(shadowmarklist);
829 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
830 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
834 // if shadowmarkcount wrapped we clear the array and adjust accordingly
835 if (shadowmarkcount == 0)
838 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
843 void R_Shadow_PrepareShadowSides(int numtris)
845 if (maxshadowsides < numtris)
847 maxshadowsides = numtris;
849 Mem_Free(shadowsides);
851 Mem_Free(shadowsideslist);
852 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
853 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
858 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
860 // p1, p2, p3 are in the cubemap's local coordinate system
861 // bias = border/(size - border)
864 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
865 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
866 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
867 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
869 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
870 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
871 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
872 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
874 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
875 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
876 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
878 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
879 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
880 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
881 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
883 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
884 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
885 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
886 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
888 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
889 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
890 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
892 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
893 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
894 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
895 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
897 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
898 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
899 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
900 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
902 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
903 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
904 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
909 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
911 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
912 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
915 VectorSubtract(maxs, mins, radius);
916 VectorScale(radius, 0.5f, radius);
917 VectorAdd(mins, radius, center);
918 Matrix4x4_Transform(worldtolight, center, lightcenter);
919 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
920 VectorSubtract(lightcenter, lightradius, pmin);
921 VectorAdd(lightcenter, lightradius, pmax);
923 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
924 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
925 if(ap1 > bias*an1 && ap2 > bias*an2)
927 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
928 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
929 if(an1 > bias*ap1 && an2 > bias*ap2)
931 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
932 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
934 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
935 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
936 if(ap1 > bias*an1 && ap2 > bias*an2)
938 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
939 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
940 if(an1 > bias*ap1 && an2 > bias*ap2)
942 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
943 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
945 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
946 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
947 if(ap1 > bias*an1 && ap2 > bias*an2)
949 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
950 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
951 if(an1 > bias*ap1 && an2 > bias*ap2)
953 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
954 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
959 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
961 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
963 // p is in the cubemap's local coordinate system
964 // bias = border/(size - border)
965 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
966 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
967 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
969 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
970 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
971 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
972 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
973 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
974 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
978 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
982 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
983 float scale = (size - 2*border)/size, len;
984 float bias = border / (float)(size - border), dp, dn, ap, an;
985 // check if cone enclosing side would cross frustum plane
986 scale = 2 / (scale*scale + 2);
987 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
988 for (i = 0;i < 5;i++)
990 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
992 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
993 len = scale*VectorLength2(n);
994 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
995 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
996 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
998 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1000 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1001 len = scale*VectorLength2(n);
1002 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1003 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1004 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1006 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1007 // check if frustum corners/origin cross plane sides
1009 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1010 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1011 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1012 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1013 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1014 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1015 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1016 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1017 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1018 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1019 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1020 for (i = 0;i < 4;i++)
1022 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1023 VectorSubtract(n, p, n);
1024 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1025 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1026 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1027 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1028 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1029 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1030 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1031 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1032 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1035 // finite version, assumes corners are a finite distance from origin dependent on far plane
1036 for (i = 0;i < 5;i++)
1038 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1039 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1040 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1041 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1042 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1043 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1044 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1045 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1046 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1047 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1050 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1053 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)
1061 int mask, surfacemask = 0;
1062 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1064 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1065 tend = firsttriangle + numtris;
1066 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1068 // surface box entirely inside light box, no box cull
1069 if (projectdirection)
1071 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1073 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1074 TriangleNormal(v[0], v[1], v[2], normal);
1075 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1077 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1078 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1079 surfacemask |= mask;
1082 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;
1083 shadowsides[numshadowsides] = mask;
1084 shadowsideslist[numshadowsides++] = t;
1091 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1093 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1094 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1096 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1097 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1098 surfacemask |= mask;
1101 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;
1102 shadowsides[numshadowsides] = mask;
1103 shadowsideslist[numshadowsides++] = t;
1111 // surface box not entirely inside light box, cull each triangle
1112 if (projectdirection)
1114 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1116 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1117 TriangleNormal(v[0], v[1], v[2], normal);
1118 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1119 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1121 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1122 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1123 surfacemask |= mask;
1126 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;
1127 shadowsides[numshadowsides] = mask;
1128 shadowsideslist[numshadowsides++] = t;
1135 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1137 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1138 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1139 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1141 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1142 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1143 surfacemask |= mask;
1146 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;
1147 shadowsides[numshadowsides] = mask;
1148 shadowsideslist[numshadowsides++] = t;
1157 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)
1159 int i, j, outtriangles = 0;
1160 int *outelement3i[6];
1161 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1163 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1164 // make sure shadowelements is big enough for this mesh
1165 if (maxshadowtriangles < outtriangles)
1166 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1168 // compute the offset and size of the separate index lists for each cubemap side
1170 for (i = 0;i < 6;i++)
1172 outelement3i[i] = shadowelements + outtriangles * 3;
1173 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1174 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1175 outtriangles += sidetotals[i];
1178 // gather up the (sparse) triangles into separate index lists for each cubemap side
1179 for (i = 0;i < numsidetris;i++)
1181 const int *element = elements + sidetris[i] * 3;
1182 for (j = 0;j < 6;j++)
1184 if (sides[i] & (1 << j))
1186 outelement3i[j][0] = element[0];
1187 outelement3i[j][1] = element[1];
1188 outelement3i[j][2] = element[2];
1189 outelement3i[j] += 3;
1194 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1197 static void R_Shadow_MakeTextures_MakeCorona(void)
1201 unsigned char pixels[32][32][4];
1202 for (y = 0;y < 32;y++)
1204 dy = (y - 15.5f) * (1.0f / 16.0f);
1205 for (x = 0;x < 32;x++)
1207 dx = (x - 15.5f) * (1.0f / 16.0f);
1208 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1209 a = bound(0, a, 255);
1210 pixels[y][x][0] = a;
1211 pixels[y][x][1] = a;
1212 pixels[y][x][2] = a;
1213 pixels[y][x][3] = 255;
1216 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1219 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1221 float dist = sqrt(x*x+y*y+z*z);
1222 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1223 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1224 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1227 static void R_Shadow_MakeTextures(void)
1230 float intensity, dist;
1232 R_Shadow_FreeShadowMaps();
1233 R_FreeTexturePool(&r_shadow_texturepool);
1234 r_shadow_texturepool = R_AllocTexturePool();
1235 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1236 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1237 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1238 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1239 for (x = 0;x <= ATTENTABLESIZE;x++)
1241 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1242 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1243 r_shadow_attentable[x] = bound(0, intensity, 1);
1245 // 1D gradient texture
1246 for (x = 0;x < ATTEN1DSIZE;x++)
1247 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1248 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1249 // 2D circle texture
1250 for (y = 0;y < ATTEN2DSIZE;y++)
1251 for (x = 0;x < ATTEN2DSIZE;x++)
1252 data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
1253 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1254 // 3D sphere texture
1255 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1257 for (z = 0;z < ATTEN3DSIZE;z++)
1258 for (y = 0;y < ATTEN3DSIZE;y++)
1259 for (x = 0;x < ATTEN3DSIZE;x++)
1260 data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
1261 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1264 r_shadow_attenuation3dtexture = NULL;
1267 R_Shadow_MakeTextures_MakeCorona();
1269 // Editor light sprites
1270 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1287 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1288 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1305 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1306 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1323 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1324 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1341 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1342 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1359 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1360 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1377 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1380 void R_Shadow_ValidateCvars(void)
1382 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1383 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1386 void R_Shadow_RenderMode_Begin(void)
1392 R_Shadow_ValidateCvars();
1394 if (!r_shadow_attenuation2dtexture
1395 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1396 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1397 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1398 R_Shadow_MakeTextures();
1401 R_Mesh_ResetTextureState();
1402 GL_BlendFunc(GL_ONE, GL_ZERO);
1403 GL_DepthRange(0, 1);
1404 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1406 GL_DepthMask(false);
1407 GL_Color(0, 0, 0, 1);
1408 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1410 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1411 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1415 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1416 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1417 r_shadow_drawbuffer = drawbuffer;
1418 r_shadow_readbuffer = readbuffer;
1420 r_shadow_cullface_front = r_refdef.view.cullface_front;
1421 r_shadow_cullface_back = r_refdef.view.cullface_back;
1424 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1426 rsurface.rtlight = rtlight;
1429 void R_Shadow_RenderMode_Reset(void)
1431 R_Mesh_ResetTextureState();
1432 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1433 R_SetViewport(&r_refdef.view.viewport);
1434 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1435 GL_DepthRange(0, 1);
1437 GL_DepthMask(false);
1438 GL_DepthFunc(GL_LEQUAL);
1439 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1440 r_refdef.view.cullface_front = r_shadow_cullface_front;
1441 r_refdef.view.cullface_back = r_shadow_cullface_back;
1442 GL_CullFace(r_refdef.view.cullface_back);
1443 GL_Color(1, 1, 1, 1);
1444 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1445 GL_BlendFunc(GL_ONE, GL_ZERO);
1446 R_SetupShader_Generic_NoTexture(false, false);
1447 r_shadow_usingshadowmap2d = false;
1450 void R_Shadow_ClearStencil(void)
1452 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1453 r_refdef.stats[r_stat_lights_clears]++;
1456 static void R_Shadow_MakeVSDCT(void)
1458 // maps to a 2x3 texture rectangle with normalized coordinates
1463 // stores abs(dir.xy), offset.xy/2.5
1464 unsigned char data[4*6] =
1466 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1467 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1468 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1469 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1470 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1471 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1473 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1476 static void R_Shadow_MakeShadowMap(int texturesize)
1478 switch (r_shadow_shadowmode)
1480 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1481 if (r_shadow_shadowmap2ddepthtexture) return;
1482 if (r_fb.usedepthtextures)
1484 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);
1485 r_shadow_shadowmap2ddepthbuffer = NULL;
1486 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1490 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1491 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1492 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1500 void R_Shadow_ClearShadowMapTexture(void)
1502 r_viewport_t viewport;
1503 float clearcolor[4];
1505 // if they don't exist, create our textures now
1506 if (!r_shadow_shadowmap2ddepthtexture)
1507 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1508 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1509 R_Shadow_MakeVSDCT();
1511 // we're setting up to render shadowmaps, so change rendermode
1512 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1514 R_Mesh_ResetTextureState();
1515 R_Shadow_RenderMode_Reset();
1516 if (r_shadow_shadowmap2ddepthbuffer)
1517 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1519 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1520 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1521 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1525 // we have to set a viewport to clear anything in some renderpaths (D3D)
1526 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1527 R_SetViewport(&viewport);
1528 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1529 if (r_shadow_shadowmap2ddepthbuffer)
1530 GL_ColorMask(1, 1, 1, 1);
1532 GL_ColorMask(0, 0, 0, 0);
1533 switch (vid.renderpath)
1535 case RENDERPATH_GL20:
1536 case RENDERPATH_GLES2:
1537 GL_CullFace(r_refdef.view.cullface_back);
1540 Vector4Set(clearcolor, 1, 1, 1, 1);
1541 if (r_shadow_shadowmap2ddepthbuffer)
1542 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1544 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1547 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1549 int size = rsurface.rtlight->shadowmapatlassidesize;
1550 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1551 float farclip = 1.0f;
1552 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1553 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1554 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1555 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1556 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1557 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1558 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1559 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1560 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1561 if (r_shadow_shadowmap2ddepthbuffer)
1563 // completely different meaning than in depthtexture approach
1564 r_shadow_lightshadowmap_parameters[1] = 0;
1565 r_shadow_lightshadowmap_parameters[3] = -bias;
1569 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1571 float nearclip, farclip, bias;
1572 r_viewport_t viewport;
1574 float clearcolor[4];
1576 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1578 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1580 R_Mesh_ResetTextureState();
1581 R_Shadow_RenderMode_Reset();
1582 if (r_shadow_shadowmap2ddepthbuffer)
1583 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1585 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1586 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1587 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1592 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1594 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1596 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1597 R_SetViewport(&viewport);
1598 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1599 flipped = (side & 1) ^ (side >> 2);
1600 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1601 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1603 Vector4Set(clearcolor, 1,1,1,1);
1604 if (r_shadow_shadowmap2ddepthbuffer)
1605 GL_ColorMask(1,1,1,1);
1607 GL_ColorMask(0,0,0,0);
1608 switch(vid.renderpath)
1610 case RENDERPATH_GL20:
1611 case RENDERPATH_GLES2:
1612 GL_CullFace(r_refdef.view.cullface_back);
1616 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1617 r_shadow_shadowmapside = side;
1620 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1622 R_Mesh_ResetTextureState();
1625 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1626 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1627 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1628 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1631 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1632 R_Shadow_RenderMode_Reset();
1633 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1635 GL_DepthFunc(GL_EQUAL);
1636 // do global setup needed for the chosen lighting mode
1637 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1638 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1639 r_shadow_usingshadowmap2d = shadowmapping;
1640 r_shadow_rendermode = r_shadow_lightingrendermode;
1643 static const unsigned short bboxelements[36] =
1653 static const float bboxpoints[8][3] =
1665 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1668 float vertex3f[8*3];
1669 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1670 // do global setup needed for the chosen lighting mode
1671 R_Shadow_RenderMode_Reset();
1672 r_shadow_rendermode = r_shadow_lightingrendermode;
1673 R_EntityMatrix(&identitymatrix);
1674 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1675 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1676 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1678 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1680 r_shadow_usingshadowmap2d = shadowmapping;
1682 // render the lighting
1683 R_SetupShader_DeferredLight(rsurface.rtlight);
1684 for (i = 0;i < 8;i++)
1685 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1686 GL_ColorMask(1,1,1,1);
1687 GL_DepthMask(false);
1688 GL_DepthRange(0, 1);
1689 GL_PolygonOffset(0, 0);
1691 GL_DepthFunc(GL_GREATER);
1692 GL_CullFace(r_refdef.view.cullface_back);
1693 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1694 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1697 #define MAXBOUNCEGRIDSPLATSIZE 7
1698 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
1700 // these are temporary data per-frame, sorted and performed in a more
1701 // cache-friendly order than the original photons
1702 typedef struct r_shadow_bouncegrid_splatpath_s
1708 vec_t splatintensity;
1709 vec_t splatsize_current;
1710 vec_t splatsize_perstep;
1711 int remainingsplats;
1713 r_shadow_bouncegrid_splatpath_t;
1715 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
1725 r_shadow_bouncegrid_splatpath_t *path;
1727 // cull paths that fail R_CullBox in dynamic mode
1728 if (!r_shadow_bouncegrid_state.settings.staticmode
1729 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
1731 vec3_t cullmins, cullmaxs;
1732 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
1733 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
1734 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
1735 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
1736 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
1737 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
1738 if (R_CullBox(cullmins, cullmaxs))
1742 // if the light path is going upward, reverse it - we always draw down.
1743 if (originalend[2] < originalstart[2])
1745 VectorCopy(originalend, start);
1746 VectorCopy(originalstart, end);
1750 VectorCopy(originalstart, start);
1751 VectorCopy(originalend, end);
1754 // transform to texture pixels
1755 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1756 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1757 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1758 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
1759 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
1760 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
1762 // check if we need to grow the splatpaths array
1763 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
1765 // double the limit, this will persist from frame to frame so we don't
1766 // make the same mistake each time
1767 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
1768 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
1769 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
1770 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);
1773 // divide a series of splats along the length using the maximum axis
1774 VectorSubtract(end, start, diff);
1775 // pick the best axis to trace along
1777 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
1779 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
1781 len = fabs(diff[bestaxis]);
1783 numsplats = (int)(floor(len + 0.5f));
1785 numsplats = bound(0, numsplats, 1024);
1787 VectorSubtract(originalstart, originalend, originaldir);
1788 VectorNormalize(originaldir);
1790 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
1791 VectorCopy(start, path->point);
1792 VectorScale(diff, ilen, path->step);
1793 VectorCopy(color, path->splatcolor);
1794 VectorCopy(originaldir, path->splatdir);
1795 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
1796 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
1797 path->splatintensity = VectorLength(color);
1798 path->remainingsplats = numsplats;
1801 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1803 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1810 // see if there are really any lights to render...
1811 if (enable && r_shadow_bouncegrid_static.integer)
1814 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1815 for (lightindex = 0;lightindex < range;lightindex++)
1817 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1818 if (!light || !(light->flags & flag))
1820 rtlight = &light->rtlight;
1821 // when static, we skip styled lights because they tend to change...
1822 if (rtlight->style > 0)
1824 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1825 if (!VectorLength2(lightcolor))
1835 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1837 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1838 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1839 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1840 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1842 // prevent any garbage in alignment padded areas as we'll be using memcmp
1843 memset(settings, 0, sizeof(*settings));
1845 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1846 settings->staticmode = s;
1847 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1848 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1849 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
1850 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
1851 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
1852 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1853 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1854 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1855 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1856 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1857 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1858 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1859 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
1860 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1861 settings->energyperphoton = spacing * spacing / quality;
1862 settings->spacing[0] = spacing;
1863 settings->spacing[1] = spacing;
1864 settings->spacing[2] = spacing;
1865 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1866 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1867 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1868 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1869 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1871 // bound the values for sanity
1872 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1873 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1874 settings->maxbounce = bound(0, settings->maxbounce, 16);
1875 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1876 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1877 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1880 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1891 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1893 // get the spacing values
1894 spacing[0] = settings->spacing[0];
1895 spacing[1] = settings->spacing[1];
1896 spacing[2] = settings->spacing[2];
1897 ispacing[0] = 1.0f / spacing[0];
1898 ispacing[1] = 1.0f / spacing[1];
1899 ispacing[2] = 1.0f / spacing[2];
1901 // calculate texture size enclosing entire world bounds at the spacing
1902 if (r_refdef.scene.worldmodel)
1906 qboolean bounds_set = false;
1910 // calculate bounds enclosing world lights as they should be noticably tighter
1911 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1912 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1913 for (lightindex = 0;lightindex < range;lightindex++)
1915 const vec_t *rtlmins, *rtlmaxs;
1917 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1921 rtlight = &light->rtlight;
1922 rtlmins = rtlight->cullmins;
1923 rtlmaxs = rtlight->cullmaxs;
1927 VectorCopy(rtlmins, mins);
1928 VectorCopy(rtlmaxs, maxs);
1933 mins[0] = min(mins[0], rtlmins[0]);
1934 mins[1] = min(mins[1], rtlmins[1]);
1935 mins[2] = min(mins[2], rtlmins[2]);
1936 maxs[0] = max(maxs[0], rtlmaxs[0]);
1937 maxs[1] = max(maxs[1], rtlmaxs[1]);
1938 maxs[2] = max(maxs[2], rtlmaxs[2]);
1942 // limit to no larger than the world bounds
1943 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1944 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1945 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1946 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1947 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1948 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1950 VectorMA(mins, -2.0f, spacing, mins);
1951 VectorMA(maxs, 2.0f, spacing, maxs);
1955 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1956 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1958 VectorSubtract(maxs, mins, size);
1959 // now we can calculate the resolution we want
1960 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1961 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1962 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1963 // figure out the exact texture size (honoring power of 2 if required)
1964 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1965 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1966 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1967 if (vid.support.arb_texture_non_power_of_two)
1969 resolution[0] = c[0];
1970 resolution[1] = c[1];
1971 resolution[2] = c[2];
1975 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
1976 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
1977 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
1979 size[0] = spacing[0] * resolution[0];
1980 size[1] = spacing[1] * resolution[1];
1981 size[2] = spacing[2] * resolution[2];
1983 // if dynamic we may or may not want to use the world bounds
1984 // if the dynamic size is smaller than the world bounds, use it instead
1985 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]))
1987 // we know the resolution we want
1988 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1989 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1990 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1991 // now we can calculate the texture size (power of 2 if required)
1992 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1993 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1994 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1995 if (vid.support.arb_texture_non_power_of_two)
1997 resolution[0] = c[0];
1998 resolution[1] = c[1];
1999 resolution[2] = c[2];
2003 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2004 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2005 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2007 size[0] = spacing[0] * resolution[0];
2008 size[1] = spacing[1] * resolution[1];
2009 size[2] = spacing[2] * resolution[2];
2010 // center the rendering on the view
2011 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2012 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2013 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2016 // recalculate the maxs in case the resolution was not satisfactory
2017 VectorAdd(mins, size, maxs);
2019 // check if this changed the texture size
2020 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);
2021 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2022 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2023 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2024 VectorCopy(size, r_shadow_bouncegrid_state.size);
2025 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2026 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2027 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2029 // reallocate pixels for this update if needed...
2030 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2031 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2032 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2033 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2034 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2036 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2037 r_shadow_bouncegrid_state.highpixels = NULL;
2038 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2039 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2040 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2041 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2042 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2043 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2044 r_shadow_bouncegrid_state.numpixels = numpixels;
2047 // update the bouncegrid matrix to put it in the world properly
2048 memset(m, 0, sizeof(m));
2049 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2050 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2051 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2052 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2053 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2054 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2056 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2059 // enumerate world rtlights and sum the overall amount of light in the world,
2060 // from that we can calculate a scaling factor to fairly distribute photons
2061 // to all the lights
2063 // this modifies rtlight->photoncolor and rtlight->photons
2064 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2066 float normalphotonscaling;
2067 float photonscaling;
2068 float photonintensity;
2069 float photoncount = 0.0f;
2070 float lightintensity;
2076 unsigned int lightindex;
2079 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2080 for (lightindex = 0;lightindex < range2;lightindex++)
2082 if (lightindex < range)
2084 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2087 rtlight = &light->rtlight;
2088 VectorClear(rtlight->bouncegrid_photoncolor);
2089 rtlight->bouncegrid_photons = 0;
2090 rtlight->bouncegrid_hits = 0;
2091 rtlight->bouncegrid_traces = 0;
2092 rtlight->bouncegrid_effectiveradius = 0;
2093 if (!(light->flags & flag))
2095 if (settings->staticmode)
2097 // when static, we skip styled lights because they tend to change...
2098 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2101 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2106 rtlight = r_refdef.scene.lights[lightindex - range];
2107 VectorClear(rtlight->bouncegrid_photoncolor);
2108 rtlight->bouncegrid_photons = 0;
2109 rtlight->bouncegrid_hits = 0;
2110 rtlight->bouncegrid_traces = 0;
2111 rtlight->bouncegrid_effectiveradius = 0;
2113 // draw only visible lights (major speedup)
2114 radius = rtlight->radius * settings->lightradiusscale;
2115 cullmins[0] = rtlight->shadoworigin[0] - radius;
2116 cullmins[1] = rtlight->shadoworigin[1] - radius;
2117 cullmins[2] = rtlight->shadoworigin[2] - radius;
2118 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2119 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2120 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2121 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2122 if (!settings->staticmode)
2124 // skip if the expanded light box does not touch any visible leafs
2125 if (r_refdef.scene.worldmodel
2126 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2127 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2129 // skip if the expanded light box is not visible to traceline
2130 // note that PrepareLight already did this check but for a smaller box, so we
2131 // end up casting more traces per frame per light when using bouncegrid, which
2132 // is probably fine (and they use the same timer)
2133 if (r_shadow_culllights_trace.integer)
2135 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))
2136 rtlight->trace_timer = realtime;
2137 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2140 // skip if expanded light box is offscreen
2141 if (R_CullBox(cullmins, cullmaxs))
2143 // skip if overall light intensity is zero
2144 if (w * VectorLength2(rtlight->color) == 0.0f)
2147 // a light that does not emit any light before style is applied, can be
2148 // skipped entirely (it may just be a corona)
2149 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2151 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2152 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2153 // skip lights that will emit no photons
2154 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2156 // shoot particles from this light
2157 // use a calculation for the number of particles that will not
2158 // vary with lightstyle, otherwise we get randomized particle
2159 // distribution, the seeded random is only consistent for a
2160 // consistent number of particles on this light...
2161 s = rtlight->radius;
2162 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2163 if (lightindex >= range)
2164 lightintensity *= settings->dlightparticlemultiplier;
2165 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2166 photoncount += rtlight->bouncegrid_photons;
2167 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2168 // if the lightstyle happens to be off right now, we can skip actually
2169 // firing the photons, but we did have to count them in the total.
2170 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2171 // rtlight->bouncegrid_photons = 0;
2173 // the user provided an energyperphoton value which we try to use
2174 // if that results in too many photons to shoot this frame, then we cap it
2175 // which causes photons to appear/disappear from frame to frame, so we don't
2176 // like doing that in the typical case
2177 photonscaling = 1.0f;
2178 photonintensity = 1.0f;
2179 if (photoncount > settings->maxphotons)
2181 photonscaling = settings->maxphotons / photoncount;
2182 photonintensity = 1.0f / photonscaling;
2185 // modify the lights to reflect our computed scaling
2186 for (lightindex = 0; lightindex < range2; lightindex++)
2188 if (lightindex < range)
2190 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2193 rtlight = &light->rtlight;
2196 rtlight = r_refdef.scene.lights[lightindex - range];
2197 rtlight->bouncegrid_photons *= photonscaling;
2198 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2202 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2204 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2205 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2206 // we only really care about sorting by Z
2207 if (a->point[2] < b->point[2])
2209 if (a->point[2] > b->point[2])
2214 static void R_Shadow_BounceGrid_ClearPixels(void)
2216 // clear the highpixels array we'll be accumulating into
2217 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2218 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2219 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2220 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2221 r_shadow_bouncegrid_state.highpixels_index = 0;
2222 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2223 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2226 static void R_Shadow_BounceGrid_PerformSplats(void)
2228 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2229 r_shadow_bouncegrid_splatpath_t *splatpath;
2230 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2231 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2236 vec_t lightpathsize_current;
2237 vec_t lightpathsize_perstep;
2238 float splatcolor[32];
2240 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2241 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2245 // hush warnings about uninitialized data - pixelbands doesn't change but...
2246 memset(splatcolor, 0, sizeof(splatcolor));
2248 // we use this a lot, so get a local copy
2249 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2251 // sort the splats before we execute them, to reduce cache misses
2252 if (r_shadow_bouncegrid_sortlightpaths.integer)
2253 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2255 splatpath = splatpaths;
2256 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2258 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2259 // accumulate average shotcolor
2260 VectorCopy(splatpath->splatdir, dir);
2261 splatcolor[ 0] = splatpath->splatcolor[0];
2262 splatcolor[ 1] = splatpath->splatcolor[1];
2263 splatcolor[ 2] = splatpath->splatcolor[2];
2264 splatcolor[ 3] = 0.0f;
2267 // store bentnormal in case the shader has a use for it,
2268 // bentnormal is an intensity-weighted average of the directions,
2269 // and will be normalized on conversion to texture pixels.
2270 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2271 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2272 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2273 splatcolor[ 7] = splatpath->splatintensity;
2274 // for each color component (R, G, B) calculate the amount that a
2275 // direction contributes
2276 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2277 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2278 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2279 splatcolor[11] = 0.0f;
2280 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2281 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2282 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2283 splatcolor[15] = 0.0f;
2284 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2285 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2286 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2287 splatcolor[19] = 0.0f;
2288 // and do the same for negative directions
2289 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2290 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2291 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2292 splatcolor[23] = 0.0f;
2293 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2294 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2295 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2296 splatcolor[27] = 0.0f;
2297 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2298 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2299 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2300 splatcolor[31] = 0.0f;
2302 // calculate the number of steps we need to traverse this distance
2303 VectorCopy(splatpath->point, steppos);
2304 VectorCopy(splatpath->step, stepdelta);
2305 numsteps = splatpath->remainingsplats;
2306 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
2307 lightpathsize_perstep = splatpath->splatsize_perstep;
2308 for (step = 0;step < numsteps;step++)
2310 // the middle row/column/layer of each splat are full intensity
2313 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
2314 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
2315 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
2316 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
2317 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
2318 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
2319 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
2320 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
2321 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
2323 // it is within bounds... do the real work now
2324 int xi, yi, zi, band, row;
2328 float colorscale = 1.0f / lightpathsize_current;
2329 r_refdef.stats[r_stat_bouncegrid_splats]++;
2330 // accumulate light onto the pixels
2331 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
2333 pixelpos[2] = zi + 0.5f;
2334 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
2336 pixelpos[1] = yi + 0.5f;
2337 row = (zi*resolution[1] + yi)*resolution[0];
2338 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
2340 pixelpos[0] = xi + 0.5f;
2341 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
2342 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
2348 p = highpixels + 4 * (row + xi);
2349 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
2351 // add to the pixel color
2352 p[0] += splatcolor[band * 4 + 0] * w;
2353 p[1] += splatcolor[band * 4 + 1] * w;
2354 p[2] += splatcolor[band * 4 + 2] * w;
2355 p[3] += splatcolor[band * 4 + 3] * w;
2362 VectorAdd(steppos, stepdelta, steppos);
2363 lightpathsize_current += lightpathsize_perstep;
2368 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2370 const float *inpixel;
2372 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2375 unsigned int x, y, z;
2376 unsigned int resolution[3];
2377 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2378 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2380 for (z = 1;z < resolution[2]-1;z++)
2382 for (y = 1;y < resolution[1]-1;y++)
2385 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2386 inpixel = inpixels + 4*index;
2387 outpixel = outpixels + 4*index;
2388 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2390 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2391 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2392 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2393 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2400 static void R_Shadow_BounceGrid_BlurPixels(void)
2403 unsigned int resolution[3];
2405 if (!r_shadow_bouncegrid_state.settings.blur)
2408 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2410 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2411 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2412 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2413 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2416 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2418 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2420 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2422 // toggle the state, highpixels now points to pixels[3] result
2423 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2424 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2427 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2429 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2430 unsigned char *pixelsbgra8 = NULL;
2431 unsigned char *pixelbgra8;
2432 unsigned short *pixelsrgba16f = NULL;
2433 unsigned short *pixelrgba16f;
2434 float *pixelsrgba32f = NULL;
2435 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2438 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2439 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2440 unsigned int pixelband;
2441 unsigned int x, y, z;
2442 unsigned int index, bandindex;
2443 unsigned int resolution[3];
2445 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2447 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2449 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2450 r_shadow_bouncegrid_state.texture = NULL;
2453 // if bentnormals exist, we need to normalize and bias them for the shader
2457 for (z = 0;z < resolution[2]-1;z++)
2459 for (y = 0;y < resolution[1]-1;y++)
2462 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2463 highpixel = highpixels + 4*index;
2464 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2466 // only convert pixels that were hit by photons
2467 if (highpixel[3] != 0.0f)
2468 VectorNormalize(highpixel);
2469 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2470 highpixel[pixelsperband * 4 + 3] = 1.0f;
2476 // start by clearing the pixels array - we won't be writing to all of it
2478 // then process only the pixels that have at least some color, skipping
2479 // the higher bands for speed on pixels that are black
2480 switch (floatcolors)
2483 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2484 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2485 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2486 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2489 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2491 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2493 for (z = 1;z < resolution[2]-1;z++)
2495 for (y = 1;y < resolution[1]-1;y++)
2499 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2500 highpixel = highpixels + 4*index;
2501 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2503 // only convert pixels that were hit by photons
2504 if (VectorLength2(highpixel))
2506 // normalize the bentnormal now
2509 VectorNormalize(highpixel + pixelsperband * 4);
2510 highpixel[pixelsperband * 4 + 3] = 1.0f;
2512 // process all of the pixelbands for this pixel
2513 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2515 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2516 bandpixel = highpixels + 4*bandindex;
2517 c[0] = (int)(bandpixel[0]*256.0f);
2518 c[1] = (int)(bandpixel[1]*256.0f);
2519 c[2] = (int)(bandpixel[2]*256.0f);
2520 c[3] = (int)(bandpixel[3]*256.0f);
2521 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2522 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2523 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2524 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2531 if (!r_shadow_bouncegrid_state.createtexture)
2532 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2534 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, pixelsbgra8, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2537 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2538 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2539 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2540 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2541 for (z = 1;z < resolution[2]-1;z++)
2543 for (y = 1;y < resolution[1]-1;y++)
2547 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2548 highpixel = highpixels + 4*index;
2549 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2551 // only convert pixels that were hit by photons
2552 if (VectorLength2(highpixel))
2554 // process all of the pixelbands for this pixel
2555 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2557 // time to have fun with IEEE 754 bit hacking...
2560 unsigned int raw[4];
2562 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2563 bandpixel = highpixels + 4*bandindex;
2564 VectorCopy4(bandpixel, u.f);
2565 VectorCopy4(u.raw, c);
2566 // this math supports negative numbers, snaps denormals to zero
2567 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2568 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2569 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2570 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2571 // this math does not support negative
2572 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2573 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2574 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2575 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2582 if (!r_shadow_bouncegrid_state.createtexture)
2583 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2585 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);
2588 // our native format happens to match, so this is easy.
2589 pixelsrgba32f = highpixels;
2591 if (!r_shadow_bouncegrid_state.createtexture)
2592 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2594 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);
2598 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2601 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2603 vec3_t bouncerandom[10];
2606 int hitsupercontentsmask;
2607 int skipsupercontentsmask;
2608 int skipmaterialflagsmask;
2612 float bounceminimumintensity2;
2614 //trace_t cliptrace2;
2615 //trace_t cliptrace3;
2616 unsigned int lightindex;
2618 randomseed_t randomseed;
2620 vec3_t baseshotcolor;
2626 vec_t distancetraveled;
2630 // compute a seed for the unstable random modes
2631 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2632 seed = realtime * 1000.0;
2634 r_shadow_bouncegrid_state.numsplatpaths = 0;
2636 // figure out what we want to interact with
2637 if (settings.hitmodels)
2638 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2640 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2641 skipsupercontentsmask = 0;
2642 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
2643 maxbounce = settings.maxbounce;
2645 for (lightindex = 0;lightindex < range2;lightindex++)
2647 if (lightindex < range)
2649 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2652 rtlight = &light->rtlight;
2655 rtlight = r_refdef.scene.lights[lightindex - range];
2656 // note that this code used to keep track of residual photons and
2657 // distribute them evenly to achieve exactly a desired photon count,
2658 // but that caused unwanted flickering in dynamic mode
2659 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2660 // skip if we won't be shooting any photons
2661 if (!shootparticles)
2663 radius = rtlight->radius * settings.lightradiusscale;
2664 //s = settings.particleintensity / shootparticles;
2665 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2666 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2667 if (VectorLength2(baseshotcolor) <= 0.0f)
2669 r_refdef.stats[r_stat_bouncegrid_lights]++;
2670 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2671 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2672 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
2674 // for seeded random we start the RNG with the position of the light
2675 if (settings.rng_seed >= 0)
2683 u.f[0] = rtlight->shadoworigin[0];
2684 u.f[1] = rtlight->shadoworigin[1];
2685 u.f[2] = rtlight->shadoworigin[2];
2687 switch (settings.rng_type)
2691 // we have to shift the seed provided by the user because the result must be odd
2692 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
2695 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
2700 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2702 VectorCopy(baseshotcolor, shotcolor);
2703 VectorCopy(rtlight->shadoworigin, clipstart);
2704 switch (settings.rng_type)
2708 VectorLehmerRandom(&randomseed, clipend);
2709 if (settings.bounceanglediffuse)
2711 // we want random to be stable, so we still have to do all the random we would have done
2712 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2713 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
2717 VectorCheeseRandom(seed, clipend);
2718 if (settings.bounceanglediffuse)
2720 // we want random to be stable, so we still have to do all the random we would have done
2721 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2722 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
2727 // we want a uniform distribution spherically, not merely within the sphere
2728 if (settings.normalizevectors)
2729 VectorNormalize(clipend);
2731 VectorMA(clipstart, radius, clipend, clipend);
2732 distancetraveled = 0.0f;
2733 for (bouncecount = 0;;bouncecount++)
2735 r_refdef.stats[r_stat_bouncegrid_traces]++;
2736 rtlight->bouncegrid_traces++;
2737 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2738 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2739 if (settings.staticmode || settings.rng_seed < 0)
2741 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2742 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2743 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);
2747 // dynamic mode fires many rays and most will match the cache from the previous frame
2748 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
2750 if (bouncecount > 0 || settings.includedirectlighting)
2753 VectorCopy(cliptrace.endpos, hitpos);
2754 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
2756 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
2757 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
2758 if (rtlight->bouncegrid_effectiveradius < s)
2759 rtlight->bouncegrid_effectiveradius = s;
2760 if (cliptrace.fraction >= 1.0f)
2762 r_refdef.stats[r_stat_bouncegrid_hits]++;
2763 rtlight->bouncegrid_hits++;
2764 if (bouncecount >= maxbounce)
2766 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2767 // also clamp the resulting color to never add energy, even if the user requests extreme values
2768 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2769 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2771 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2772 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2773 surfcolor[0] = min(surfcolor[0], 1.0f);
2774 surfcolor[1] = min(surfcolor[1], 1.0f);
2775 surfcolor[2] = min(surfcolor[2], 1.0f);
2776 VectorMultiply(shotcolor, surfcolor, shotcolor);
2777 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
2779 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2780 if (settings.bounceanglediffuse)
2782 // random direction, primarily along plane normal
2783 s = VectorDistance(cliptrace.endpos, clipend);
2784 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
2785 VectorNormalize(clipend);
2786 VectorScale(clipend, s, clipend);
2790 // reflect the remaining portion of the line across plane normal
2791 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2792 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2794 // calculate the new line start and end
2795 VectorCopy(cliptrace.endpos, clipstart);
2796 VectorAdd(clipstart, clipend, clipend);
2802 void R_Shadow_UpdateBounceGridTexture(void)
2804 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2805 r_shadow_bouncegrid_settings_t settings;
2806 qboolean enable = false;
2807 qboolean settingschanged;
2808 unsigned int range; // number of world lights
2809 unsigned int range1; // number of dynamic lights (or zero if disabled)
2810 unsigned int range2; // range+range1
2812 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2814 R_Shadow_BounceGrid_GenerateSettings(&settings);
2816 // changing intensity does not require an update
2817 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2819 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2821 // when settings change, we free everything as it is just simpler that way.
2822 if (settingschanged || !enable)
2824 // not enabled, make sure we free anything we don't need anymore.
2825 if (r_shadow_bouncegrid_state.texture)
2827 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2828 r_shadow_bouncegrid_state.texture = NULL;
2830 r_shadow_bouncegrid_state.highpixels = NULL;
2831 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2832 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2833 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2834 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2835 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2836 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2837 r_shadow_bouncegrid_state.numpixels = 0;
2838 r_shadow_bouncegrid_state.directional = false;
2844 // if all the settings seem identical to the previous update, return
2845 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2848 // store the new settings
2849 r_shadow_bouncegrid_state.settings = settings;
2851 R_Shadow_BounceGrid_UpdateSpacing();
2853 // get the range of light numbers we'll be looping over:
2854 // range = static lights
2855 // range1 = dynamic lights (optional)
2856 // range2 = range + range1
2857 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2858 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2859 range2 = range + range1;
2861 // calculate weighting factors for distributing photons among the lights
2862 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
2864 // trace the photons from lights and accumulate illumination
2865 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
2867 // clear the texture
2868 R_Shadow_BounceGrid_ClearPixels();
2870 // accumulate the light splatting into texture
2871 R_Shadow_BounceGrid_PerformSplats();
2873 // apply a mild blur filter to the texture
2874 R_Shadow_BounceGrid_BlurPixels();
2876 // convert the pixels to lower precision and upload the texture
2877 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2879 // after we compute the static lighting we don't need to keep the highpixels array around
2880 if (settings.staticmode)
2882 r_shadow_bouncegrid_state.highpixels = NULL;
2883 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2884 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2885 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2886 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2887 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2888 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2892 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2894 R_Shadow_RenderMode_Reset();
2895 GL_BlendFunc(GL_ONE, GL_ONE);
2896 GL_DepthRange(0, 1);
2897 GL_DepthTest(r_showlighting.integer < 2);
2898 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2900 GL_DepthFunc(GL_EQUAL);
2901 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2904 void R_Shadow_RenderMode_End(void)
2906 R_Shadow_RenderMode_Reset();
2907 R_Shadow_RenderMode_ActiveLight(NULL);
2909 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2910 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2913 int bboxedges[12][2] =
2932 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2934 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2936 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2937 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2938 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2939 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2942 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2943 return true; // invisible
2944 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2945 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2946 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2947 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2948 r_refdef.stats[r_stat_lights_scissored]++;
2952 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2954 // used to display how many times a surface is lit for level design purposes
2955 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2956 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2960 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])
2962 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2963 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2967 extern cvar_t gl_lightmaps;
2968 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2971 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2972 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2973 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2974 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2975 if (!r_shadow_usenormalmap.integer)
2977 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2978 VectorClear(diffusecolor);
2979 VectorClear(specularcolor);
2981 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2982 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2983 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2984 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2986 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0) && vid.support.ext_blend_subtract;
2989 VectorNegate(ambientcolor, ambientcolor);
2990 VectorNegate(diffusecolor, diffusecolor);
2991 VectorNegate(specularcolor, specularcolor);
2992 GL_BlendEquationSubtract(true);
2994 RSurf_SetupDepthAndCulling();
2995 switch (r_shadow_rendermode)
2997 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2998 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2999 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3001 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3002 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
3005 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3009 GL_BlendEquationSubtract(false);
3012 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)
3014 matrix4x4_t tempmatrix = *matrix;
3015 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3017 // if this light has been compiled before, free the associated data
3018 R_RTLight_Uncompile(rtlight);
3020 // clear it completely to avoid any lingering data
3021 memset(rtlight, 0, sizeof(*rtlight));
3023 // copy the properties
3024 rtlight->matrix_lighttoworld = tempmatrix;
3025 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3026 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3027 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3028 VectorCopy(color, rtlight->color);
3029 rtlight->cubemapname[0] = 0;
3030 if (cubemapname && cubemapname[0])
3031 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3032 rtlight->shadow = shadow;
3033 rtlight->corona = corona;
3034 rtlight->style = style;
3035 rtlight->isstatic = isstatic;
3036 rtlight->coronasizescale = coronasizescale;
3037 rtlight->ambientscale = ambientscale;
3038 rtlight->diffusescale = diffusescale;
3039 rtlight->specularscale = specularscale;
3040 rtlight->flags = flags;
3042 // compute derived data
3043 //rtlight->cullradius = rtlight->radius;
3044 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3045 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3046 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3047 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3048 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3049 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3050 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3053 // compiles rtlight geometry
3054 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3055 void R_RTLight_Compile(rtlight_t *rtlight)
3058 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3059 int lighttris, shadowtris;
3060 entity_render_t *ent = r_refdef.scene.worldentity;
3061 dp_model_t *model = r_refdef.scene.worldmodel;
3062 unsigned char *data;
3064 // compile the light
3065 rtlight->compiled = true;
3066 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3067 rtlight->static_numleafs = 0;
3068 rtlight->static_numleafpvsbytes = 0;
3069 rtlight->static_leaflist = NULL;
3070 rtlight->static_leafpvs = NULL;
3071 rtlight->static_numsurfaces = 0;
3072 rtlight->static_surfacelist = NULL;
3073 rtlight->static_shadowmap_receivers = 0x3F;
3074 rtlight->static_shadowmap_casters = 0x3F;
3075 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3076 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3077 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3078 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3079 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3080 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3082 if (model && model->GetLightInfo)
3084 // this variable must be set for the CompileShadowMap code
3085 r_shadow_compilingrtlight = rtlight;
3086 R_FrameData_SetMark();
3087 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);
3088 R_FrameData_ReturnToMark();
3089 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3090 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3091 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3092 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3093 rtlight->static_numsurfaces = numsurfaces;
3094 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3095 rtlight->static_numleafs = numleafs;
3096 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3097 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3098 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3099 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3100 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3101 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3102 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3103 if (rtlight->static_numsurfaces)
3104 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3105 if (rtlight->static_numleafs)
3106 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3107 if (rtlight->static_numleafpvsbytes)
3108 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3109 if (rtlight->static_numshadowtrispvsbytes)
3110 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3111 if (rtlight->static_numlighttrispvsbytes)
3112 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3113 R_FrameData_SetMark();
3114 if (model->CompileShadowMap && rtlight->shadow)
3115 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3116 R_FrameData_ReturnToMark();
3117 // now we're done compiling the rtlight
3118 r_shadow_compilingrtlight = NULL;
3122 // use smallest available cullradius - box radius or light radius
3123 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3124 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3127 if (rtlight->static_numlighttrispvsbytes)
3128 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3129 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3133 if (rtlight->static_numshadowtrispvsbytes)
3134 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3135 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3138 if (developer_extra.integer)
3139 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);
3142 void R_RTLight_Uncompile(rtlight_t *rtlight)
3144 if (rtlight->compiled)
3146 if (rtlight->static_meshchain_shadow_shadowmap)
3147 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3148 rtlight->static_meshchain_shadow_shadowmap = NULL;
3149 // these allocations are grouped
3150 if (rtlight->static_surfacelist)
3151 Mem_Free(rtlight->static_surfacelist);
3152 rtlight->static_numleafs = 0;
3153 rtlight->static_numleafpvsbytes = 0;
3154 rtlight->static_leaflist = NULL;
3155 rtlight->static_leafpvs = NULL;
3156 rtlight->static_numsurfaces = 0;
3157 rtlight->static_surfacelist = NULL;
3158 rtlight->static_numshadowtrispvsbytes = 0;
3159 rtlight->static_shadowtrispvs = NULL;
3160 rtlight->static_numlighttrispvsbytes = 0;
3161 rtlight->static_lighttrispvs = NULL;
3162 rtlight->compiled = false;
3166 void R_Shadow_UncompileWorldLights(void)
3170 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3171 for (lightindex = 0;lightindex < range;lightindex++)
3173 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3176 R_RTLight_Uncompile(&light->rtlight);
3180 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3184 // reset the count of frustum planes
3185 // see rtlight->cached_frustumplanes definition for how much this array
3187 rtlight->cached_numfrustumplanes = 0;
3189 if (r_trippy.integer)
3192 // haven't implemented a culling path for ortho rendering
3193 if (!r_refdef.view.useperspective)
3195 // check if the light is on screen and copy the 4 planes if it is
3196 for (i = 0;i < 4;i++)
3197 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3200 for (i = 0;i < 4;i++)
3201 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3206 // generate a deformed frustum that includes the light origin, this is
3207 // used to cull shadow casting surfaces that can not possibly cast a
3208 // shadow onto the visible light-receiving surfaces, which can be a
3211 // if the light origin is onscreen the result will be 4 planes exactly
3212 // if the light origin is offscreen on only one axis the result will
3213 // be exactly 5 planes (split-side case)
3214 // if the light origin is offscreen on two axes the result will be
3215 // exactly 4 planes (stretched corner case)
3216 for (i = 0;i < 4;i++)
3218 // quickly reject standard frustum planes that put the light
3219 // origin outside the frustum
3220 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3223 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3225 // if all the standard frustum planes were accepted, the light is onscreen
3226 // otherwise we need to generate some more planes below...
3227 if (rtlight->cached_numfrustumplanes < 4)
3229 // at least one of the stock frustum planes failed, so we need to
3230 // create one or two custom planes to enclose the light origin
3231 for (i = 0;i < 4;i++)
3233 // create a plane using the view origin and light origin, and a
3234 // single point from the frustum corner set
3235 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3236 VectorNormalize(plane.normal);
3237 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3238 // see if this plane is backwards and flip it if so
3239 for (j = 0;j < 4;j++)
3240 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3244 VectorNegate(plane.normal, plane.normal);
3246 // flipped plane, test again to see if it is now valid
3247 for (j = 0;j < 4;j++)
3248 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3250 // if the plane is still not valid, then it is dividing the
3251 // frustum and has to be rejected
3255 // we have created a valid plane, compute extra info
3256 PlaneClassify(&plane);
3258 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3260 // if we've found 5 frustum planes then we have constructed a
3261 // proper split-side case and do not need to keep searching for
3262 // planes to enclose the light origin
3263 if (rtlight->cached_numfrustumplanes == 5)
3271 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3273 plane = rtlight->cached_frustumplanes[i];
3274 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));
3279 // now add the light-space box planes if the light box is rotated, as any
3280 // caster outside the oriented light box is irrelevant (even if it passed
3281 // the worldspace light box, which is axial)
3282 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3284 for (i = 0;i < 6;i++)
3288 v[i >> 1] = (i & 1) ? -1 : 1;
3289 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3290 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3291 plane.dist = VectorNormalizeLength(plane.normal);
3292 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3293 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3299 // add the world-space reduced box planes
3300 for (i = 0;i < 6;i++)
3302 VectorClear(plane.normal);
3303 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3304 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3305 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3314 // reduce all plane distances to tightly fit the rtlight cull box, which
3316 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3317 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3318 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3319 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3320 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3321 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3322 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3323 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3324 oldnum = rtlight->cached_numfrustumplanes;
3325 rtlight->cached_numfrustumplanes = 0;
3326 for (j = 0;j < oldnum;j++)
3328 // find the nearest point on the box to this plane
3329 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3330 for (i = 1;i < 8;i++)
3332 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3333 if (bestdist > dist)
3336 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);
3337 // if the nearest point is near or behind the plane, we want this
3338 // plane, otherwise the plane is useless as it won't cull anything
3339 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3341 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3342 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3349 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3353 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3355 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3358 GL_CullFace(GL_NONE);
3359 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3360 for (;mesh;mesh = mesh->next)
3362 if (!mesh->sidetotals[r_shadow_shadowmapside])
3364 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3365 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3366 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);
3370 else if (r_refdef.scene.worldentity->model)
3371 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);
3373 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3376 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3378 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3379 vec_t relativeshadowradius;
3380 RSurf_ActiveModelEntity(ent, false, false, false);
3381 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3382 // we need to re-init the shader for each entity because the matrix changed
3383 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3384 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3385 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3386 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3387 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3388 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3389 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3390 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3391 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3394 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3396 // set up properties for rendering light onto this entity
3397 RSurf_ActiveModelEntity(ent, true, true, false);
3398 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3399 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3400 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3401 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3404 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3406 if (!r_refdef.scene.worldmodel->DrawLight)
3409 // set up properties for rendering light onto this entity
3410 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3411 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3412 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3413 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3414 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3416 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3418 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3421 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3423 dp_model_t *model = ent->model;
3424 if (!model->DrawLight)
3427 R_Shadow_SetupEntityLight(ent);
3429 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3431 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3434 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3438 int numleafs, numsurfaces;
3439 int *leaflist, *surfacelist;
3440 unsigned char *leafpvs;
3441 unsigned char *shadowtrispvs;
3442 unsigned char *lighttrispvs;
3443 //unsigned char *surfacesides;
3444 int numlightentities;
3445 int numlightentities_noselfshadow;
3446 int numshadowentities;
3447 int numshadowentities_noselfshadow;
3448 // FIXME: bounds check lightentities and shadowentities, etc.
3449 static entity_render_t *lightentities[MAX_EDICTS];
3450 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3451 static entity_render_t *shadowentities[MAX_EDICTS];
3452 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3454 qboolean castshadows;
3456 rtlight->draw = false;
3457 rtlight->cached_numlightentities = 0;
3458 rtlight->cached_numlightentities_noselfshadow = 0;
3459 rtlight->cached_numshadowentities = 0;
3460 rtlight->cached_numshadowentities_noselfshadow = 0;
3461 rtlight->cached_numsurfaces = 0;
3462 rtlight->cached_lightentities = NULL;
3463 rtlight->cached_lightentities_noselfshadow = NULL;
3464 rtlight->cached_shadowentities = NULL;
3465 rtlight->cached_shadowentities_noselfshadow = NULL;
3466 rtlight->cached_shadowtrispvs = NULL;
3467 rtlight->cached_lighttrispvs = NULL;
3468 rtlight->cached_surfacelist = NULL;
3469 rtlight->shadowmapsidesize = 0;
3471 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3472 // skip lights that are basically invisible (color 0 0 0)
3473 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3475 // loading is done before visibility checks because loading should happen
3476 // all at once at the start of a level, not when it stalls gameplay.
3477 // (especially important to benchmarks)
3479 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3481 if (rtlight->compiled)
3482 R_RTLight_Uncompile(rtlight);
3483 R_RTLight_Compile(rtlight);
3487 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3489 // look up the light style value at this time
3490 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3491 VectorScale(rtlight->color, f, rtlight->currentcolor);
3493 if (rtlight->selected)
3495 f = 2 + sin(realtime * M_PI * 4.0);
3496 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3500 // skip if lightstyle is currently off
3501 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3504 // skip processing on corona-only lights
3508 // skip if the light box is not touching any visible leafs
3509 if (r_shadow_culllights_pvs.integer
3510 && r_refdef.scene.worldmodel
3511 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3512 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3515 // skip if the light box is not visible to traceline
3516 if (r_shadow_culllights_trace.integer)
3518 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))
3519 rtlight->trace_timer = realtime;
3520 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3524 // skip if the light box is off screen
3525 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3528 // in the typical case this will be quickly replaced by GetLightInfo
3529 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3530 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3532 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3534 // 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
3535 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3538 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3540 // compiled light, world available and can receive realtime lighting
3541 // retrieve leaf information
3542 numleafs = rtlight->static_numleafs;
3543 leaflist = rtlight->static_leaflist;
3544 leafpvs = rtlight->static_leafpvs;
3545 numsurfaces = rtlight->static_numsurfaces;
3546 surfacelist = rtlight->static_surfacelist;
3547 //surfacesides = NULL;
3548 shadowtrispvs = rtlight->static_shadowtrispvs;
3549 lighttrispvs = rtlight->static_lighttrispvs;
3551 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3553 // dynamic light, world available and can receive realtime lighting
3554 // calculate lit surfaces and leafs
3555 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);
3556 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3557 leaflist = r_shadow_buffer_leaflist;
3558 leafpvs = r_shadow_buffer_leafpvs;
3559 surfacelist = r_shadow_buffer_surfacelist;
3560 //surfacesides = r_shadow_buffer_surfacesides;
3561 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3562 lighttrispvs = r_shadow_buffer_lighttrispvs;
3563 // if the reduced leaf bounds are offscreen, skip it
3564 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3575 //surfacesides = NULL;
3576 shadowtrispvs = NULL;
3577 lighttrispvs = NULL;
3579 // check if light is illuminating any visible leafs
3582 for (i = 0; i < numleafs; i++)
3583 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3589 // make a list of lit entities and shadow casting entities
3590 numlightentities = 0;
3591 numlightentities_noselfshadow = 0;
3592 numshadowentities = 0;
3593 numshadowentities_noselfshadow = 0;
3595 // add dynamic entities that are lit by the light
3596 for (i = 0; i < r_refdef.scene.numentities; i++)
3599 entity_render_t *ent = r_refdef.scene.entities[i];
3601 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3603 // skip the object entirely if it is not within the valid
3604 // shadow-casting region (which includes the lit region)
3605 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3607 if (!(model = ent->model))
3609 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3611 // this entity wants to receive light, is visible, and is
3612 // inside the light box
3613 // TODO: check if the surfaces in the model can receive light
3614 // so now check if it's in a leaf seen by the light
3615 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))
3617 if (ent->flags & RENDER_NOSELFSHADOW)
3618 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3620 lightentities[numlightentities++] = ent;
3621 // since it is lit, it probably also casts a shadow...
3622 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3623 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3624 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3626 // note: exterior models without the RENDER_NOSELFSHADOW
3627 // flag still create a RENDER_NOSELFSHADOW shadow but
3628 // are lit normally, this means that they are
3629 // self-shadowing but do not shadow other
3630 // RENDER_NOSELFSHADOW entities such as the gun
3631 // (very weird, but keeps the player shadow off the gun)
3632 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3633 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3635 shadowentities[numshadowentities++] = ent;
3638 else if (ent->flags & RENDER_SHADOW)
3640 // this entity is not receiving light, but may still need to
3642 // TODO: check if the surfaces in the model can cast shadow
3643 // now check if it is in a leaf seen by the light
3644 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))
3646 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3647 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3648 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3650 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3651 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3653 shadowentities[numshadowentities++] = ent;
3658 // return if there's nothing at all to light
3659 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3662 // count this light in the r_speeds
3663 r_refdef.stats[r_stat_lights]++;
3665 // flag it as worth drawing later
3666 rtlight->draw = true;
3668 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3669 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3671 numshadowentities = numshadowentities_noselfshadow = 0;
3672 rtlight->castshadows = castshadows;
3674 // cache all the animated entities that cast a shadow but are not visible
3675 for (i = 0; i < numshadowentities; i++)
3676 R_AnimCache_GetEntity(shadowentities[i], false, false);
3677 for (i = 0; i < numshadowentities_noselfshadow; i++)
3678 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3680 // 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)
3681 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3683 for (i = 0; i < numshadowentities_noselfshadow; i++)
3684 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3685 numshadowentities_noselfshadow = 0;
3688 // we can convert noselfshadow to regular if there are no casters of that type
3689 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3691 for (i = 0; i < numlightentities_noselfshadow; i++)
3692 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3693 numlightentities_noselfshadow = 0;
3696 // allocate some temporary memory for rendering this light later in the frame
3697 // reusable buffers need to be copied, static data can be used as-is
3698 rtlight->cached_numlightentities = numlightentities;
3699 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3700 rtlight->cached_numshadowentities = numshadowentities;
3701 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3702 rtlight->cached_numsurfaces = numsurfaces;
3703 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3704 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3705 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3706 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3707 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3709 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3710 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3711 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3712 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3713 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3717 // compiled light data
3718 rtlight->cached_shadowtrispvs = shadowtrispvs;
3719 rtlight->cached_lighttrispvs = lighttrispvs;
3720 rtlight->cached_surfacelist = surfacelist;
3723 if (R_Shadow_ShadowMappingEnabled())
3725 // figure out the shadowmapping parameters for this light
3726 vec3_t nearestpoint;
3729 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3730 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3731 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3732 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3733 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3734 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3735 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3736 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3737 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3741 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3745 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3746 int numlightentities;
3747 int numlightentities_noselfshadow;
3748 int numshadowentities;
3749 int numshadowentities_noselfshadow;
3750 entity_render_t **lightentities;
3751 entity_render_t **lightentities_noselfshadow;
3752 entity_render_t **shadowentities;
3753 entity_render_t **shadowentities_noselfshadow;
3755 static unsigned char entitysides[MAX_EDICTS];
3756 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3762 matrix4x4_t radiustolight;
3764 // check if we cached this light this frame (meaning it is worth drawing)
3765 if (!rtlight->draw || !rtlight->castshadows)
3768 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3769 if (rtlight->shadowmapatlassidesize == 0)
3771 rtlight->castshadows = false;
3775 // set up a scissor rectangle for this light
3776 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3779 // don't let sound skip if going slow
3780 if (r_refdef.scene.extraupdate)
3783 numlightentities = rtlight->cached_numlightentities;
3784 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3785 numshadowentities = rtlight->cached_numshadowentities;
3786 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3787 numsurfaces = rtlight->cached_numsurfaces;
3788 lightentities = rtlight->cached_lightentities;
3789 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3790 shadowentities = rtlight->cached_shadowentities;
3791 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3792 shadowtrispvs = rtlight->cached_shadowtrispvs;
3793 lighttrispvs = rtlight->cached_lighttrispvs;
3794 surfacelist = rtlight->cached_surfacelist;
3796 // make this the active rtlight for rendering purposes
3797 R_Shadow_RenderMode_ActiveLight(rtlight);
3799 radiustolight = rtlight->matrix_worldtolight;
3800 Matrix4x4_Abs(&radiustolight);
3802 size = rtlight->shadowmapatlassidesize;
3803 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3805 surfacesides = NULL;
3810 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3812 castermask = rtlight->static_shadowmap_casters;
3813 receivermask = rtlight->static_shadowmap_receivers;
3817 surfacesides = r_shadow_buffer_surfacesides;
3818 for (i = 0; i < numsurfaces; i++)
3820 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3821 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3822 castermask |= surfacesides[i];
3823 receivermask |= surfacesides[i];
3828 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3829 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3830 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3831 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3833 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3837 for (i = 0; i < numshadowentities; i++)
3838 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3839 for (i = 0; i < numshadowentities_noselfshadow; i++)
3840 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3843 // there is no need to render shadows for sides that have no receivers...
3844 castermask &= receivermask;
3846 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3848 // render shadow casters into shadowmaps for this light
3849 for (side = 0; side < 6; side++)
3851 int bit = 1 << side;
3852 if (castermask & bit)
3854 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3856 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3857 for (i = 0; i < numshadowentities; i++)
3858 if (entitysides[i] & bit)
3859 R_Shadow_DrawEntityShadow(shadowentities[i]);
3860 for (i = 0; i < numshadowentities_noselfshadow; i++)
3861 if (entitysides_noselfshadow[i] & bit)
3862 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3865 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3866 if (numshadowentities_noselfshadow)
3868 for (side = 0; side < 6; side++)
3870 int bit = 1 << side;
3871 if (castermask & bit)
3873 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3875 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3876 for (i = 0; i < numshadowentities; i++)
3877 if (entitysides[i] & bit)
3878 R_Shadow_DrawEntityShadow(shadowentities[i]);
3884 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3888 unsigned char *shadowtrispvs, *lighttrispvs;
3889 int numlightentities;
3890 int numlightentities_noselfshadow;
3891 int numshadowentities;
3892 int numshadowentities_noselfshadow;
3893 entity_render_t **lightentities;
3894 entity_render_t **lightentities_noselfshadow;
3895 entity_render_t **shadowentities;
3896 entity_render_t **shadowentities_noselfshadow;
3898 qboolean castshadows;
3900 // check if we cached this light this frame (meaning it is worth drawing)
3904 // set up a scissor rectangle for this light
3905 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3908 // don't let sound skip if going slow
3909 if (r_refdef.scene.extraupdate)
3912 numlightentities = rtlight->cached_numlightentities;
3913 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3914 numshadowentities = rtlight->cached_numshadowentities;
3915 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3916 numsurfaces = rtlight->cached_numsurfaces;
3917 lightentities = rtlight->cached_lightentities;
3918 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3919 shadowentities = rtlight->cached_shadowentities;
3920 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3921 shadowtrispvs = rtlight->cached_shadowtrispvs;
3922 lighttrispvs = rtlight->cached_lighttrispvs;
3923 surfacelist = rtlight->cached_surfacelist;
3924 castshadows = rtlight->castshadows;
3926 // make this the active rtlight for rendering purposes
3927 R_Shadow_RenderMode_ActiveLight(rtlight);
3929 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3931 // optionally draw the illuminated areas
3932 // for performance analysis by level designers
3933 R_Shadow_RenderMode_VisibleLighting(false);
3935 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3936 for (i = 0;i < numlightentities;i++)
3937 R_Shadow_DrawEntityLight(lightentities[i]);
3938 for (i = 0;i < numlightentities_noselfshadow;i++)
3939 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3942 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3946 float shadowmapoffsetnoselfshadow = 0;
3947 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3948 Matrix4x4_Abs(&radiustolight);
3950 size = rtlight->shadowmapatlassidesize;
3951 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3953 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3955 if (rtlight->cached_numshadowentities_noselfshadow)
3956 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3958 // render lighting using the depth texture as shadowmap
3959 // draw lighting in the unmasked areas
3960 if (numsurfaces + numlightentities)
3962 R_Shadow_RenderMode_Lighting(false, true, false);
3963 // draw lighting in the unmasked areas
3965 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3966 for (i = 0; i < numlightentities; i++)
3967 R_Shadow_DrawEntityLight(lightentities[i]);
3969 // offset to the noselfshadow part of the atlas and draw those too
3970 if (numlightentities_noselfshadow)
3972 R_Shadow_RenderMode_Lighting(false, true, true);
3973 for (i = 0; i < numlightentities_noselfshadow; i++)
3974 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3977 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3978 if (r_shadow_usingdeferredprepass)
3979 R_Shadow_RenderMode_DrawDeferredLight(true);
3983 // draw lighting in the unmasked areas
3984 R_Shadow_RenderMode_Lighting(false, false, false);
3986 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3987 for (i = 0;i < numlightentities;i++)
3988 R_Shadow_DrawEntityLight(lightentities[i]);
3989 for (i = 0;i < numlightentities_noselfshadow;i++)
3990 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3992 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3993 if (r_shadow_usingdeferredprepass)
3994 R_Shadow_RenderMode_DrawDeferredLight(false);
3998 static void R_Shadow_FreeDeferred(void)
4000 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4001 r_shadow_prepassgeometryfbo = 0;
4003 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4004 r_shadow_prepasslightingdiffusespecularfbo = 0;
4006 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4007 r_shadow_prepasslightingdiffusefbo = 0;
4009 if (r_shadow_prepassgeometrydepthbuffer)
4010 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4011 r_shadow_prepassgeometrydepthbuffer = NULL;
4013 if (r_shadow_prepassgeometrynormalmaptexture)
4014 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4015 r_shadow_prepassgeometrynormalmaptexture = NULL;
4017 if (r_shadow_prepasslightingdiffusetexture)
4018 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4019 r_shadow_prepasslightingdiffusetexture = NULL;
4021 if (r_shadow_prepasslightingspeculartexture)
4022 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4023 r_shadow_prepasslightingspeculartexture = NULL;
4026 void R_Shadow_DrawPrepass(void)
4030 entity_render_t *ent;
4031 float clearcolor[4];
4033 R_Mesh_ResetTextureState();
4035 GL_ColorMask(1,1,1,1);
4036 GL_BlendFunc(GL_ONE, GL_ZERO);
4039 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4040 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4041 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4042 if (r_timereport_active)
4043 R_TimeReport("prepasscleargeom");
4045 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4046 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4047 if (r_timereport_active)
4048 R_TimeReport("prepassworld");
4050 for (i = 0;i < r_refdef.scene.numentities;i++)
4052 if (!r_refdef.viewcache.entityvisible[i])
4054 ent = r_refdef.scene.entities[i];
4055 if (ent->model && ent->model->DrawPrepass != NULL)
4056 ent->model->DrawPrepass(ent);
4059 if (r_timereport_active)
4060 R_TimeReport("prepassmodels");
4062 GL_DepthMask(false);
4063 GL_ColorMask(1,1,1,1);
4066 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4067 Vector4Set(clearcolor, 0, 0, 0, 0);
4068 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4069 if (r_timereport_active)
4070 R_TimeReport("prepassclearlit");
4072 R_Shadow_RenderMode_Begin();
4074 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4075 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4077 R_Shadow_RenderMode_End();
4079 if (r_timereport_active)
4080 R_TimeReport("prepasslights");
4083 #define MAX_SCENELIGHTS 65536
4084 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4086 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4088 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4090 r_shadow_scenemaxlights *= 2;
4091 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4092 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4094 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4098 void R_Shadow_DrawLightSprites(void);
4099 void R_Shadow_PrepareLights(void)
4108 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4109 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4110 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4112 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4113 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4114 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4115 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4116 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4117 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4118 r_shadow_shadowmapborder != shadowmapborder ||
4119 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4120 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4121 R_Shadow_FreeShadowMaps();
4123 r_shadow_usingshadowmaportho = false;
4125 switch (vid.renderpath)
4127 case RENDERPATH_GL20:
4129 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4131 r_shadow_usingdeferredprepass = false;
4132 if (r_shadow_prepass_width)
4133 R_Shadow_FreeDeferred();
4134 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4138 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4140 R_Shadow_FreeDeferred();
4142 r_shadow_usingdeferredprepass = true;
4143 r_shadow_prepass_width = vid.width;
4144 r_shadow_prepass_height = vid.height;
4145 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4146 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);
4147 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);
4148 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);
4150 // set up the geometry pass fbo (depth + normalmap)
4151 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4152 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4153 // render depth into a renderbuffer and other important properties into the normalmap texture
4155 // set up the lighting pass fbo (diffuse + specular)
4156 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4157 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4158 // render diffuse into one texture and specular into another,
4159 // with depth and normalmap bound as textures,
4160 // with depth bound as attachment as well
4162 // set up the lighting pass fbo (diffuse)
4163 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4164 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4165 // render diffuse into one texture,
4166 // with depth and normalmap bound as textures,
4167 // with depth bound as attachment as well
4171 case RENDERPATH_GLES2:
4172 r_shadow_usingdeferredprepass = false;
4176 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
4178 r_shadow_scenenumlights = 0;
4179 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4180 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4181 for (lightindex = 0; lightindex < range; lightindex++)
4183 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4184 if (light && (light->flags & flag))
4186 R_Shadow_PrepareLight(&light->rtlight);
4187 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4190 if (r_refdef.scene.rtdlight)
4192 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4194 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4195 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4198 else if (gl_flashblend.integer)
4200 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4202 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4203 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4204 VectorScale(rtlight->color, f, rtlight->currentcolor);
4208 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4209 if (r_shadow_debuglight.integer >= 0)
4211 r_shadow_scenenumlights = 0;
4212 lightindex = r_shadow_debuglight.integer;
4213 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4216 R_Shadow_PrepareLight(&light->rtlight);
4217 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4221 // if we're doing shadowmaps we need to prepare the atlas layout now
4222 if (R_Shadow_ShadowMappingEnabled())
4226 // allocate shadowmaps in the atlas now
4227 // 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...
4228 for (lod = 0; lod < 16; lod++)
4230 int packing_success = 0;
4231 int packing_failure = 0;
4232 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4233 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4234 if (r_shadow_shadowmapatlas_modelshadows_size)
4235 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);
4236 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4238 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4239 int size = rtlight->shadowmapsidesize >> lod;
4241 if (!rtlight->castshadows)
4243 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4246 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4247 if (rtlight->cached_numshadowentities_noselfshadow)
4249 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4251 rtlight->shadowmapatlassidesize = size;
4256 // note down that we failed to pack this one, it will have to disable shadows
4257 rtlight->shadowmapatlassidesize = 0;
4261 // generally everything fits and we stop here on the first iteration
4262 if (packing_failure == 0)
4267 if (r_editlights.integer)
4268 R_Shadow_DrawLightSprites();
4271 void R_Shadow_DrawShadowMaps(void)
4273 R_Shadow_RenderMode_Begin();
4274 R_Shadow_RenderMode_ActiveLight(NULL);
4276 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4277 R_Shadow_ClearShadowMapTexture();
4279 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4280 if (r_shadow_shadowmapatlas_modelshadows_size)
4282 R_Shadow_DrawModelShadowMaps();
4283 // don't let sound skip if going slow
4284 if (r_refdef.scene.extraupdate)
4288 if (R_Shadow_ShadowMappingEnabled())
4291 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4292 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4295 R_Shadow_RenderMode_End();
4298 void R_Shadow_DrawLights(void)
4302 R_Shadow_RenderMode_Begin();
4304 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4305 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4307 R_Shadow_RenderMode_End();
4310 #define MAX_MODELSHADOWS 1024
4311 static int r_shadow_nummodelshadows;
4312 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4314 void R_Shadow_PrepareModelShadows(void)
4317 float scale, size, radius, dot1, dot2;
4318 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4319 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4320 entity_render_t *ent;
4322 r_shadow_nummodelshadows = 0;
4323 r_shadow_shadowmapatlas_modelshadows_size = 0;
4325 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4328 size = r_shadow_shadowmaptexturesize / 4;
4329 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4330 radius = 0.5f * size / scale;
4332 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4333 VectorCopy(prvmshadowdir, shadowdir);
4334 VectorNormalize(shadowdir);
4335 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4336 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4337 if (fabs(dot1) <= fabs(dot2))
4338 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4340 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4341 VectorNormalize(shadowforward);
4342 CrossProduct(shadowdir, shadowforward, shadowright);
4343 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4344 VectorCopy(prvmshadowfocus, shadowfocus);
4345 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4346 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4347 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4348 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4349 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4351 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4353 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4354 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4355 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4356 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4357 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4358 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4360 for (i = 0; i < r_refdef.scene.numentities; i++)
4362 ent = r_refdef.scene.entities[i];
4363 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4365 // cast shadows from anything of the map (submodels are optional)
4366 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4368 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4370 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4371 R_AnimCache_GetEntity(ent, false, false);
4375 if (r_shadow_nummodelshadows)
4377 r_shadow_shadowmapatlas_modelshadows_x = 0;
4378 r_shadow_shadowmapatlas_modelshadows_y = 0;
4379 r_shadow_shadowmapatlas_modelshadows_size = size;
4383 static void R_Shadow_DrawModelShadowMaps(void)
4386 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4387 entity_render_t *ent;
4388 vec3_t relativelightorigin;
4389 vec3_t relativelightdirection, relativeforward, relativeright;
4390 vec3_t relativeshadowmins, relativeshadowmaxs;
4391 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4392 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4394 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4395 r_viewport_t viewport;
4397 size = r_shadow_shadowmapatlas_modelshadows_size;
4398 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4399 radius = 0.5f / scale;
4400 nearclip = -r_shadows_throwdistance.value;
4401 farclip = r_shadows_throwdistance.value;
4402 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);
4404 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4405 r_shadow_modelshadowmap_parameters[0] = size;
4406 r_shadow_modelshadowmap_parameters[1] = size;
4407 r_shadow_modelshadowmap_parameters[2] = 1.0;
4408 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4409 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4410 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4411 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4412 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4413 r_shadow_usingshadowmaportho = true;
4415 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4416 VectorCopy(prvmshadowdir, shadowdir);
4417 VectorNormalize(shadowdir);
4418 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4419 VectorCopy(prvmshadowfocus, shadowfocus);
4420 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4421 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4422 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4423 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4424 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4425 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4426 if (fabs(dot1) <= fabs(dot2))
4427 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4429 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4430 VectorNormalize(shadowforward);
4431 VectorM(scale, shadowforward, &m[0]);
4432 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4434 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4435 CrossProduct(shadowdir, shadowforward, shadowright);
4436 VectorM(scale, shadowright, &m[4]);
4437 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4438 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4439 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4440 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4441 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4442 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);
4443 R_SetViewport(&viewport);
4445 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4447 // render into a slightly restricted region so that the borders of the
4448 // shadowmap area fade away, rather than streaking across everything
4449 // outside the usable area
4450 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4452 for (i = 0;i < r_shadow_nummodelshadows;i++)
4454 ent = r_shadow_modelshadows[i];
4455 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4456 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4457 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4458 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4459 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4460 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4461 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4462 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4463 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4464 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4465 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4466 RSurf_ActiveModelEntity(ent, false, false, false);
4467 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4468 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4474 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4476 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4478 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4479 Cvar_SetValueQuick(&r_test, 0);
4484 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4485 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4486 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4487 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4488 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4489 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4492 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4495 vec3_t centerorigin;
4496 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4499 // if it's too close, skip it
4500 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4502 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4505 if (usequery && r_numqueries + 2 <= r_maxqueries)
4507 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4508 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4509 // 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
4510 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4512 switch(vid.renderpath)
4514 case RENDERPATH_GL20:
4515 case RENDERPATH_GLES2:
4516 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4518 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4519 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4520 GL_DepthFunc(GL_ALWAYS);
4521 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4522 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4523 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4524 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4525 GL_DepthFunc(GL_LEQUAL);
4526 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4527 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4528 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4529 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4530 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4536 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4539 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4541 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4544 unsigned int occlude = 0;
4545 GLint allpixels = 0, visiblepixels = 0;
4547 // now we have to check the query result
4548 if (rtlight->corona_queryindex_visiblepixels)
4550 switch(vid.renderpath)
4552 case RENDERPATH_GL20:
4553 case RENDERPATH_GLES2:
4554 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4555 // See if we can use the GPU-side method to prevent implicit sync
4556 if (vid.support.arb_query_buffer_object) {
4557 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4558 if (!r_shadow_occlusion_buf) {
4559 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
4560 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
4561 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
4563 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
4565 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
4566 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
4567 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4568 occlude = MATERIALFLAG_OCCLUDE;
4569 cscale *= rtlight->corona_visibility;
4574 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4575 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4576 if (visiblepixels < 1 || allpixels < 1)
4578 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4579 cscale *= rtlight->corona_visibility;
4589 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4592 VectorScale(rtlight->currentcolor, cscale, color);
4593 if (VectorLength(color) > (1.0f / 256.0f))
4596 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4599 VectorNegate(color, color);
4600 GL_BlendEquationSubtract(true);
4602 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4603 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);
4604 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
4606 GL_BlendEquationSubtract(false);
4610 void R_Shadow_DrawCoronas(void)
4613 qboolean usequery = false;
4618 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4620 if (r_fb.water.renderingscene)
4622 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4623 R_EntityMatrix(&identitymatrix);
4625 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4627 // check occlusion of coronas
4628 // use GL_ARB_occlusion_query if available
4629 // otherwise use raytraces
4631 switch (vid.renderpath)
4633 case RENDERPATH_GL20:
4634 case RENDERPATH_GLES2:
4635 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4636 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4639 GL_ColorMask(0,0,0,0);
4640 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4641 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4644 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4645 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4647 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4650 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4651 GL_BlendFunc(GL_ONE, GL_ZERO);
4652 GL_CullFace(GL_NONE);
4653 GL_DepthMask(false);
4654 GL_DepthRange(0, 1);
4655 GL_PolygonOffset(0, 0);
4657 R_Mesh_ResetTextureState();
4658 R_SetupShader_Generic_NoTexture(false, false);
4663 for (lightindex = 0;lightindex < range;lightindex++)
4665 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4668 rtlight = &light->rtlight;
4669 rtlight->corona_visibility = 0;
4670 rtlight->corona_queryindex_visiblepixels = 0;
4671 rtlight->corona_queryindex_allpixels = 0;
4672 if (!(rtlight->flags & flag))
4674 if (rtlight->corona <= 0)
4676 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4678 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4680 for (i = 0;i < r_refdef.scene.numlights;i++)
4682 rtlight = r_refdef.scene.lights[i];
4683 rtlight->corona_visibility = 0;
4684 rtlight->corona_queryindex_visiblepixels = 0;
4685 rtlight->corona_queryindex_allpixels = 0;
4686 if (!(rtlight->flags & flag))
4688 if (rtlight->corona <= 0)
4690 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4693 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4695 // now draw the coronas using the query data for intensity info
4696 for (lightindex = 0;lightindex < range;lightindex++)
4698 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4701 rtlight = &light->rtlight;
4702 if (rtlight->corona_visibility <= 0)
4704 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4706 for (i = 0;i < r_refdef.scene.numlights;i++)
4708 rtlight = r_refdef.scene.lights[i];
4709 if (rtlight->corona_visibility <= 0)
4711 if (gl_flashblend.integer)
4712 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4714 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4720 static dlight_t *R_Shadow_NewWorldLight(void)
4722 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4725 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)
4729 // 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
4731 // validate parameters
4735 // copy to light properties
4736 VectorCopy(origin, light->origin);
4737 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4738 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4739 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4741 light->color[0] = max(color[0], 0);
4742 light->color[1] = max(color[1], 0);
4743 light->color[2] = max(color[2], 0);
4745 light->color[0] = color[0];
4746 light->color[1] = color[1];
4747 light->color[2] = color[2];
4748 light->radius = max(radius, 0);
4749 light->style = style;
4750 light->shadow = shadowenable;
4751 light->corona = corona;
4752 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4753 light->coronasizescale = coronasizescale;
4754 light->ambientscale = ambientscale;
4755 light->diffusescale = diffusescale;
4756 light->specularscale = specularscale;
4757 light->flags = flags;
4759 // update renderable light data
4760 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4761 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);
4764 static void R_Shadow_FreeWorldLight(dlight_t *light)
4766 if (r_shadow_selectedlight == light)
4767 r_shadow_selectedlight = NULL;
4768 R_RTLight_Uncompile(&light->rtlight);
4769 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4772 void R_Shadow_ClearWorldLights(void)
4776 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4777 for (lightindex = 0;lightindex < range;lightindex++)
4779 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4781 R_Shadow_FreeWorldLight(light);
4783 r_shadow_selectedlight = NULL;
4786 static void R_Shadow_SelectLight(dlight_t *light)
4788 if (r_shadow_selectedlight)
4789 r_shadow_selectedlight->selected = false;
4790 r_shadow_selectedlight = light;
4791 if (r_shadow_selectedlight)
4792 r_shadow_selectedlight->selected = true;
4795 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4797 // this is never batched (there can be only one)
4799 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4800 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4801 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4804 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4809 skinframe_t *skinframe;
4812 // this is never batched (due to the ent parameter changing every time)
4813 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4814 const dlight_t *light = (dlight_t *)ent;
4817 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4820 VectorScale(light->color, intensity, spritecolor);
4821 if (VectorLength(spritecolor) < 0.1732f)
4822 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4823 if (VectorLength(spritecolor) > 1.0f)
4824 VectorNormalize(spritecolor);
4826 // draw light sprite
4827 if (light->cubemapname[0] && !light->shadow)
4828 skinframe = r_editlights_sprcubemapnoshadowlight;
4829 else if (light->cubemapname[0])
4830 skinframe = r_editlights_sprcubemaplight;
4831 else if (!light->shadow)
4832 skinframe = r_editlights_sprnoshadowlight;
4834 skinframe = r_editlights_sprlight;
4836 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);
4837 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4839 // draw selection sprite if light is selected
4840 if (light->selected)
4842 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4843 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4844 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4848 void R_Shadow_DrawLightSprites(void)
4852 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4853 for (lightindex = 0;lightindex < range;lightindex++)
4855 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4857 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4859 if (!r_editlights_lockcursor)
4860 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4863 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4868 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4869 if (lightindex >= range)
4871 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4874 rtlight = &light->rtlight;
4875 //if (!(rtlight->flags & flag))
4877 VectorCopy(rtlight->shadoworigin, origin);
4878 *radius = rtlight->radius;
4879 VectorCopy(rtlight->color, color);
4883 static void R_Shadow_SelectLightInView(void)
4885 float bestrating, rating, temp[3];
4889 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4893 if (r_editlights_lockcursor)
4895 for (lightindex = 0;lightindex < range;lightindex++)
4897 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4900 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4901 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4904 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4905 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)
4907 bestrating = rating;
4912 R_Shadow_SelectLight(best);
4915 void R_Shadow_LoadWorldLights(void)
4917 int n, a, style, shadow, flags;
4918 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4919 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4920 if (cl.worldmodel == NULL)
4922 Con_Print("No map loaded.\n");
4925 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4926 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4936 for (;COM_Parse(t, true) && strcmp(
4937 if (COM_Parse(t, true))
4939 if (com_token[0] == '!')
4942 origin[0] = atof(com_token+1);
4945 origin[0] = atof(com_token);
4950 while (*s && *s != '\n' && *s != '\r')
4956 // check for modifier flags
4963 #if _MSC_VER >= 1400
4964 #define sscanf sscanf_s
4966 cubemapname[sizeof(cubemapname)-1] = 0;
4967 #if MAX_QPATH != 128
4968 #error update this code if MAX_QPATH changes
4970 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
4971 #if _MSC_VER >= 1400
4972 , sizeof(cubemapname)
4974 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4977 flags = LIGHTFLAG_REALTIMEMODE;
4985 coronasizescale = 0.25f;
4987 VectorClear(angles);
4990 if (a < 9 || !strcmp(cubemapname, "\"\""))
4992 // remove quotes on cubemapname
4993 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4996 namelen = strlen(cubemapname) - 2;
4997 memmove(cubemapname, cubemapname + 1, namelen);
4998 cubemapname[namelen] = '\0';
5002 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);
5005 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5013 Con_Printf("invalid rtlights file \"%s\"\n", name);
5014 Mem_Free(lightsstring);
5018 void R_Shadow_SaveWorldLights(void)
5022 size_t bufchars, bufmaxchars;
5024 char name[MAX_QPATH];
5025 char line[MAX_INPUTLINE];
5026 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5027 // I hate lines which are 3 times my screen size :( --blub
5030 if (cl.worldmodel == NULL)
5032 Con_Print("No map loaded.\n");
5035 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5036 bufchars = bufmaxchars = 0;
5038 for (lightindex = 0;lightindex < range;lightindex++)
5040 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5043 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5044 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);
5045 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5046 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]);
5048 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);
5049 if (bufchars + strlen(line) > bufmaxchars)
5051 bufmaxchars = bufchars + strlen(line) + 2048;
5053 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5057 memcpy(buf, oldbuf, bufchars);
5063 memcpy(buf + bufchars, line, strlen(line));
5064 bufchars += strlen(line);
5068 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5073 void R_Shadow_LoadLightsFile(void)
5076 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5077 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5078 if (cl.worldmodel == NULL)
5080 Con_Print("No map loaded.\n");
5083 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5084 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5092 while (*s && *s != '\n' && *s != '\r')
5098 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);
5102 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);
5105 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5106 radius = bound(15, radius, 4096);
5107 VectorScale(color, (2.0f / (8388608.0f)), color);
5108 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5116 Con_Printf("invalid lights file \"%s\"\n", name);
5117 Mem_Free(lightsstring);
5121 // tyrlite/hmap2 light types in the delay field
5122 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5124 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5136 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5137 char key[256], value[MAX_INPUTLINE];
5140 if (cl.worldmodel == NULL)
5142 Con_Print("No map loaded.\n");
5145 // try to load a .ent file first
5146 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5147 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5148 // and if that is not found, fall back to the bsp file entity string
5150 data = cl.worldmodel->brush.entities;
5153 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5155 type = LIGHTTYPE_MINUSX;
5156 origin[0] = origin[1] = origin[2] = 0;
5157 originhack[0] = originhack[1] = originhack[2] = 0;
5158 angles[0] = angles[1] = angles[2] = 0;
5159 color[0] = color[1] = color[2] = 1;
5160 light[0] = light[1] = light[2] = 1;light[3] = 300;
5161 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5171 if (!COM_ParseToken_Simple(&data, false, false, true))
5173 if (com_token[0] == '}')
5174 break; // end of entity
5175 if (com_token[0] == '_')
5176 strlcpy(key, com_token + 1, sizeof(key));
5178 strlcpy(key, com_token, sizeof(key));
5179 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5180 key[strlen(key)-1] = 0;
5181 if (!COM_ParseToken_Simple(&data, false, false, true))
5183 strlcpy(value, com_token, sizeof(value));
5185 // now that we have the key pair worked out...
5186 if (!strcmp("light", key))
5188 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5192 light[0] = vec[0] * (1.0f / 256.0f);
5193 light[1] = vec[0] * (1.0f / 256.0f);
5194 light[2] = vec[0] * (1.0f / 256.0f);
5200 light[0] = vec[0] * (1.0f / 255.0f);
5201 light[1] = vec[1] * (1.0f / 255.0f);
5202 light[2] = vec[2] * (1.0f / 255.0f);
5206 else if (!strcmp("delay", key))
5208 else if (!strcmp("origin", key))
5209 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5210 else if (!strcmp("angle", key))
5211 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5212 else if (!strcmp("angles", key))
5213 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5214 else if (!strcmp("color", key))
5215 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5216 else if (!strcmp("wait", key))
5217 fadescale = atof(value);
5218 else if (!strcmp("classname", key))
5220 if (!strncmp(value, "light", 5))
5223 if (!strcmp(value, "light_fluoro"))
5228 overridecolor[0] = 1;
5229 overridecolor[1] = 1;
5230 overridecolor[2] = 1;
5232 if (!strcmp(value, "light_fluorospark"))
5237 overridecolor[0] = 1;
5238 overridecolor[1] = 1;
5239 overridecolor[2] = 1;
5241 if (!strcmp(value, "light_globe"))
5246 overridecolor[0] = 1;
5247 overridecolor[1] = 0.8;
5248 overridecolor[2] = 0.4;
5250 if (!strcmp(value, "light_flame_large_yellow"))
5255 overridecolor[0] = 1;
5256 overridecolor[1] = 0.5;
5257 overridecolor[2] = 0.1;
5259 if (!strcmp(value, "light_flame_small_yellow"))
5264 overridecolor[0] = 1;
5265 overridecolor[1] = 0.5;
5266 overridecolor[2] = 0.1;
5268 if (!strcmp(value, "light_torch_small_white"))
5273 overridecolor[0] = 1;
5274 overridecolor[1] = 0.5;
5275 overridecolor[2] = 0.1;
5277 if (!strcmp(value, "light_torch_small_walltorch"))
5282 overridecolor[0] = 1;
5283 overridecolor[1] = 0.5;
5284 overridecolor[2] = 0.1;
5288 else if (!strcmp("style", key))
5289 style = atoi(value);
5290 else if (!strcmp("skin", key))
5291 skin = (int)atof(value);
5292 else if (!strcmp("pflags", key))
5293 pflags = (int)atof(value);
5294 //else if (!strcmp("effects", key))
5295 // effects = (int)atof(value);
5296 else if (cl.worldmodel->type == mod_brushq3)
5298 if (!strcmp("scale", key))
5299 lightscale = atof(value);
5300 if (!strcmp("fade", key))
5301 fadescale = atof(value);
5306 if (lightscale <= 0)
5310 if (color[0] == color[1] && color[0] == color[2])
5312 color[0] *= overridecolor[0];
5313 color[1] *= overridecolor[1];
5314 color[2] *= overridecolor[2];
5316 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5317 color[0] = color[0] * light[0];
5318 color[1] = color[1] * light[1];
5319 color[2] = color[2] * light[2];
5322 case LIGHTTYPE_MINUSX:
5324 case LIGHTTYPE_RECIPX:
5326 VectorScale(color, (1.0f / 16.0f), color);
5328 case LIGHTTYPE_RECIPXX:
5330 VectorScale(color, (1.0f / 16.0f), color);
5333 case LIGHTTYPE_NONE:
5337 case LIGHTTYPE_MINUSXX:
5340 VectorAdd(origin, originhack, origin);
5342 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);
5345 Mem_Free(entfiledata);
5349 static void R_Shadow_SetCursorLocationForView(void)
5352 vec3_t dest, endpos;
5354 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5355 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5356 if (trace.fraction < 1)
5358 dist = trace.fraction * r_editlights_cursordistance.value;
5359 push = r_editlights_cursorpushback.value;
5363 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5364 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5368 VectorClear( endpos );
5370 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5371 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5372 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5375 void R_Shadow_UpdateWorldLightSelection(void)
5377 if (r_editlights.integer)
5379 R_Shadow_SetCursorLocationForView();
5380 R_Shadow_SelectLightInView();
5383 R_Shadow_SelectLight(NULL);
5386 static void R_Shadow_EditLights_Clear_f(void)
5388 R_Shadow_ClearWorldLights();
5391 void R_Shadow_EditLights_Reload_f(void)
5395 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5396 R_Shadow_ClearWorldLights();
5397 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5399 R_Shadow_LoadWorldLights();
5400 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5401 R_Shadow_LoadLightsFile();
5403 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5405 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5406 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5410 static void R_Shadow_EditLights_Save_f(void)
5414 R_Shadow_SaveWorldLights();
5417 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5419 R_Shadow_ClearWorldLights();
5420 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5423 static void R_Shadow_EditLights_ImportLightsFile_f(void)
5425 R_Shadow_ClearWorldLights();
5426 R_Shadow_LoadLightsFile();
5429 static void R_Shadow_EditLights_Spawn_f(void)
5432 if (!r_editlights.integer)
5434 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5437 if (Cmd_Argc() != 1)
5439 Con_Print("r_editlights_spawn does not take parameters\n");
5442 color[0] = color[1] = color[2] = 1;
5443 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5446 static void R_Shadow_EditLights_Edit_f(void)
5448 vec3_t origin, angles, color;
5449 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5450 int style, shadows, flags, normalmode, realtimemode;
5451 char cubemapname[MAX_INPUTLINE];
5452 if (!r_editlights.integer)
5454 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5457 if (!r_shadow_selectedlight)
5459 Con_Print("No selected light.\n");
5462 VectorCopy(r_shadow_selectedlight->origin, origin);
5463 VectorCopy(r_shadow_selectedlight->angles, angles);
5464 VectorCopy(r_shadow_selectedlight->color, color);
5465 radius = r_shadow_selectedlight->radius;
5466 style = r_shadow_selectedlight->style;
5467 if (r_shadow_selectedlight->cubemapname)
5468 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5471 shadows = r_shadow_selectedlight->shadow;
5472 corona = r_shadow_selectedlight->corona;
5473 coronasizescale = r_shadow_selectedlight->coronasizescale;
5474 ambientscale = r_shadow_selectedlight->ambientscale;
5475 diffusescale = r_shadow_selectedlight->diffusescale;
5476 specularscale = r_shadow_selectedlight->specularscale;
5477 flags = r_shadow_selectedlight->flags;
5478 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5479 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5480 if (!strcmp(Cmd_Argv(1), "origin"))
5482 if (Cmd_Argc() != 5)
5484 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5487 origin[0] = atof(Cmd_Argv(2));
5488 origin[1] = atof(Cmd_Argv(3));
5489 origin[2] = atof(Cmd_Argv(4));
5491 else if (!strcmp(Cmd_Argv(1), "originscale"))
5493 if (Cmd_Argc() != 5)
5495 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5498 origin[0] *= atof(Cmd_Argv(2));
5499 origin[1] *= atof(Cmd_Argv(3));
5500 origin[2] *= atof(Cmd_Argv(4));
5502 else if (!strcmp(Cmd_Argv(1), "originx"))
5504 if (Cmd_Argc() != 3)
5506 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5509 origin[0] = atof(Cmd_Argv(2));
5511 else if (!strcmp(Cmd_Argv(1), "originy"))
5513 if (Cmd_Argc() != 3)
5515 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5518 origin[1] = atof(Cmd_Argv(2));
5520 else if (!strcmp(Cmd_Argv(1), "originz"))
5522 if (Cmd_Argc() != 3)
5524 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5527 origin[2] = atof(Cmd_Argv(2));
5529 else if (!strcmp(Cmd_Argv(1), "move"))
5531 if (Cmd_Argc() != 5)
5533 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5536 origin[0] += atof(Cmd_Argv(2));
5537 origin[1] += atof(Cmd_Argv(3));
5538 origin[2] += atof(Cmd_Argv(4));
5540 else if (!strcmp(Cmd_Argv(1), "movex"))
5542 if (Cmd_Argc() != 3)
5544 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5547 origin[0] += atof(Cmd_Argv(2));
5549 else if (!strcmp(Cmd_Argv(1), "movey"))
5551 if (Cmd_Argc() != 3)
5553 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5556 origin[1] += atof(Cmd_Argv(2));
5558 else if (!strcmp(Cmd_Argv(1), "movez"))
5560 if (Cmd_Argc() != 3)
5562 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5565 origin[2] += atof(Cmd_Argv(2));
5567 else if (!strcmp(Cmd_Argv(1), "angles"))
5569 if (Cmd_Argc() != 5)
5571 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5574 angles[0] = atof(Cmd_Argv(2));
5575 angles[1] = atof(Cmd_Argv(3));
5576 angles[2] = atof(Cmd_Argv(4));
5578 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5580 if (Cmd_Argc() != 3)
5582 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5585 angles[0] = atof(Cmd_Argv(2));
5587 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5589 if (Cmd_Argc() != 3)
5591 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5594 angles[1] = atof(Cmd_Argv(2));
5596 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5598 if (Cmd_Argc() != 3)
5600 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5603 angles[2] = atof(Cmd_Argv(2));
5605 else if (!strcmp(Cmd_Argv(1), "color"))
5607 if (Cmd_Argc() != 5)
5609 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5612 color[0] = atof(Cmd_Argv(2));
5613 color[1] = atof(Cmd_Argv(3));
5614 color[2] = atof(Cmd_Argv(4));
5616 else if (!strcmp(Cmd_Argv(1), "radius"))
5618 if (Cmd_Argc() != 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5623 radius = atof(Cmd_Argv(2));
5625 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5627 if (Cmd_Argc() == 3)
5629 double scale = atof(Cmd_Argv(2));
5636 if (Cmd_Argc() != 5)
5638 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5641 color[0] *= atof(Cmd_Argv(2));
5642 color[1] *= atof(Cmd_Argv(3));
5643 color[2] *= atof(Cmd_Argv(4));
5646 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5648 if (Cmd_Argc() != 3)
5650 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5653 radius *= atof(Cmd_Argv(2));
5655 else if (!strcmp(Cmd_Argv(1), "style"))
5657 if (Cmd_Argc() != 3)
5659 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5662 style = atoi(Cmd_Argv(2));
5664 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5668 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5671 if (Cmd_Argc() == 3)
5672 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5676 else if (!strcmp(Cmd_Argv(1), "shadows"))
5678 if (Cmd_Argc() != 3)
5680 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5683 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5685 else if (!strcmp(Cmd_Argv(1), "corona"))
5687 if (Cmd_Argc() != 3)
5689 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5692 corona = atof(Cmd_Argv(2));
5694 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5696 if (Cmd_Argc() != 3)
5698 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5701 coronasizescale = atof(Cmd_Argv(2));
5703 else if (!strcmp(Cmd_Argv(1), "ambient"))
5705 if (Cmd_Argc() != 3)
5707 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5710 ambientscale = atof(Cmd_Argv(2));
5712 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5714 if (Cmd_Argc() != 3)
5716 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5719 diffusescale = atof(Cmd_Argv(2));
5721 else if (!strcmp(Cmd_Argv(1), "specular"))
5723 if (Cmd_Argc() != 3)
5725 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5728 specularscale = atof(Cmd_Argv(2));
5730 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5732 if (Cmd_Argc() != 3)
5734 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5737 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5739 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5741 if (Cmd_Argc() != 3)
5743 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5746 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5750 Con_Print("usage: r_editlights_edit [property] [value]\n");
5751 Con_Print("Selected light's properties:\n");
5752 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5753 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5754 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5755 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5756 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5757 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5758 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5759 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5760 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5761 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5762 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5763 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5764 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5765 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5768 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5769 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5772 static void R_Shadow_EditLights_EditAll_f(void)
5775 dlight_t *light, *oldselected;
5778 if (!r_editlights.integer)
5780 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5784 oldselected = r_shadow_selectedlight;
5785 // EditLights doesn't seem to have a "remove" command or something so:
5786 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5787 for (lightindex = 0;lightindex < range;lightindex++)
5789 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5792 R_Shadow_SelectLight(light);
5793 R_Shadow_EditLights_Edit_f();
5795 // return to old selected (to not mess editing once selection is locked)
5796 R_Shadow_SelectLight(oldselected);
5799 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5801 int lightnumber, lightcount;
5802 size_t lightindex, range;
5807 if (!r_editlights.integer)
5810 // update cvars so QC can query them
5811 if (r_shadow_selectedlight)
5813 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5814 Cvar_SetQuick(&r_editlights_current_origin, temp);
5815 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5816 Cvar_SetQuick(&r_editlights_current_angles, temp);
5817 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5818 Cvar_SetQuick(&r_editlights_current_color, temp);
5819 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5820 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5821 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5822 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5823 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5824 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5825 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5826 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5827 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5828 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5829 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5832 // draw properties on screen
5833 if (!r_editlights_drawproperties.integer)
5835 x = vid_conwidth.value - 320;
5837 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5840 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5841 for (lightindex = 0;lightindex < range;lightindex++)
5843 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5846 if (light == r_shadow_selectedlight)
5847 lightnumber = (int)lightindex;
5850 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;
5851 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;
5853 if (r_shadow_selectedlight == NULL)
5855 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;
5856 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;
5857 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;
5858 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;
5859 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;
5860 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;
5861 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;
5862 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;
5863 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;
5864 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;
5865 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;
5866 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;
5867 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;
5868 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;
5869 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;
5871 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;
5872 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;
5873 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;
5874 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;
5875 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;
5876 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;
5877 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;
5878 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;
5879 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;
5880 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;
5883 static void R_Shadow_EditLights_ToggleShadow_f(void)
5885 if (!r_editlights.integer)
5887 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5890 if (!r_shadow_selectedlight)
5892 Con_Print("No selected light.\n");
5895 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);
5898 static void R_Shadow_EditLights_ToggleCorona_f(void)
5900 if (!r_editlights.integer)
5902 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5905 if (!r_shadow_selectedlight)
5907 Con_Print("No selected light.\n");
5910 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);
5913 static void R_Shadow_EditLights_Remove_f(void)
5915 if (!r_editlights.integer)
5917 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5920 if (!r_shadow_selectedlight)
5922 Con_Print("No selected light.\n");
5925 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5926 r_shadow_selectedlight = NULL;
5929 static void R_Shadow_EditLights_Help_f(void)
5932 "Documentation on r_editlights system:\n"
5934 "r_editlights : enable/disable editing mode\n"
5935 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5936 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5937 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5938 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5939 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5941 "r_editlights_help : this help\n"
5942 "r_editlights_clear : remove all lights\n"
5943 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5944 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5945 "r_editlights_save : save to .rtlights file\n"
5946 "r_editlights_spawn : create a light with default settings\n"
5947 "r_editlights_edit command : edit selected light - more documentation below\n"
5948 "r_editlights_remove : remove selected light\n"
5949 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5950 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5951 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5953 "origin x y z : set light location\n"
5954 "originx x: set x component of light location\n"
5955 "originy y: set y component of light location\n"
5956 "originz z: set z component of light location\n"
5957 "move x y z : adjust light location\n"
5958 "movex x: adjust x component of light location\n"
5959 "movey y: adjust y component of light location\n"
5960 "movez z: adjust z component of light location\n"
5961 "angles x y z : set light angles\n"
5962 "anglesx x: set x component of light angles\n"
5963 "anglesy y: set y component of light angles\n"
5964 "anglesz z: set z component of light angles\n"
5965 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5966 "radius radius : set radius (size) of light\n"
5967 "colorscale grey : multiply color of light (1 does nothing)\n"
5968 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5969 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5970 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5971 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5972 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5973 "cubemap basename : set filter cubemap of light\n"
5974 "shadows 1/0 : turn on/off shadows\n"
5975 "corona n : set corona intensity\n"
5976 "coronasize n : set corona size (0-1)\n"
5977 "ambient n : set ambient intensity (0-1)\n"
5978 "diffuse n : set diffuse intensity (0-1)\n"
5979 "specular n : set specular intensity (0-1)\n"
5980 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5981 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5982 "<nothing> : print light properties to console\n"
5986 static void R_Shadow_EditLights_CopyInfo_f(void)
5988 if (!r_editlights.integer)
5990 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5993 if (!r_shadow_selectedlight)
5995 Con_Print("No selected light.\n");
5998 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5999 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6000 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6001 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6002 if (r_shadow_selectedlight->cubemapname)
6003 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6005 r_shadow_bufferlight.cubemapname[0] = 0;
6006 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6007 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6008 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6009 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6010 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6011 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6012 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6015 static void R_Shadow_EditLights_PasteInfo_f(void)
6017 if (!r_editlights.integer)
6019 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6022 if (!r_shadow_selectedlight)
6024 Con_Print("No selected light.\n");
6027 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);
6030 static void R_Shadow_EditLights_Lock_f(void)
6032 if (!r_editlights.integer)
6034 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6037 if (r_editlights_lockcursor)
6039 r_editlights_lockcursor = false;
6042 if (!r_shadow_selectedlight)
6044 Con_Print("No selected light to lock on.\n");
6047 r_editlights_lockcursor = true;
6050 static void R_Shadow_EditLights_Init(void)
6052 Cvar_RegisterVariable(&r_editlights);
6053 Cvar_RegisterVariable(&r_editlights_cursordistance);
6054 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6055 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6056 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6057 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6058 Cvar_RegisterVariable(&r_editlights_drawproperties);
6059 Cvar_RegisterVariable(&r_editlights_current_origin);
6060 Cvar_RegisterVariable(&r_editlights_current_angles);
6061 Cvar_RegisterVariable(&r_editlights_current_color);
6062 Cvar_RegisterVariable(&r_editlights_current_radius);
6063 Cvar_RegisterVariable(&r_editlights_current_corona);
6064 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6065 Cvar_RegisterVariable(&r_editlights_current_style);
6066 Cvar_RegisterVariable(&r_editlights_current_shadows);
6067 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6068 Cvar_RegisterVariable(&r_editlights_current_ambient);
6069 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6070 Cvar_RegisterVariable(&r_editlights_current_specular);
6071 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6072 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6073 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6074 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6075 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)");
6076 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6077 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6078 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6079 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)");
6080 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6081 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6082 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6083 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6084 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6085 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6086 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)");
6087 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6093 =============================================================================
6097 =============================================================================
6100 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6102 int i, numlights, flag, q;
6105 float relativepoint[3];
6110 float sa[3], sx[3], sy[3], sz[3], sd[3];
6113 // use first order spherical harmonics to combine directional lights
6114 for (q = 0; q < 3; q++)
6115 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6117 if (flags & LP_LIGHTMAP)
6119 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6121 float tempambient[3];
6122 for (q = 0; q < 3; q++)
6123 tempambient[q] = color[q] = relativepoint[q] = 0;
6124 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6125 // calculate a weighted average light direction as well
6126 intensity = VectorLength(color);
6127 for (q = 0; q < 3; q++)
6129 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6130 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6131 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6132 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6133 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6138 // unlit map - fullbright but scaled by lightmapintensity
6139 for (q = 0; q < 3; q++)
6140 sa[q] += lightmapintensity;
6144 if (flags & LP_RTWORLD)
6146 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6147 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6148 for (i = 0; i < numlights; i++)
6150 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6153 light = &dlight->rtlight;
6154 if (!(light->flags & flag))
6157 lightradius2 = light->radius * light->radius;
6158 VectorSubtract(light->shadoworigin, p, relativepoint);
6159 dist2 = VectorLength2(relativepoint);
6160 if (dist2 >= lightradius2)
6162 dist = sqrt(dist2) / light->radius;
6163 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6164 if (intensity <= 0.0f)
6166 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)
6168 for (q = 0; q < 3; q++)
6169 color[q] = light->currentcolor[q] * intensity;
6170 intensity = VectorLength(color);
6171 VectorNormalize(relativepoint);
6172 for (q = 0; q < 3; q++)
6174 sa[q] += 0.5f * color[q];
6175 sx[q] += relativepoint[0] * color[q];
6176 sy[q] += relativepoint[1] * color[q];
6177 sz[q] += relativepoint[2] * color[q];
6178 sd[q] += intensity * relativepoint[q];
6181 // FIXME: sample bouncegrid too!
6184 if (flags & LP_DYNLIGHT)
6187 for (i = 0;i < r_refdef.scene.numlights;i++)
6189 light = r_refdef.scene.lights[i];
6191 lightradius2 = light->radius * light->radius;
6192 VectorSubtract(light->shadoworigin, p, relativepoint);
6193 dist2 = VectorLength2(relativepoint);
6194 if (dist2 >= lightradius2)
6196 dist = sqrt(dist2) / light->radius;
6197 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6198 if (intensity <= 0.0f)
6200 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)
6202 for (q = 0; q < 3; q++)
6203 color[q] = light->currentcolor[q] * intensity;
6204 intensity = VectorLength(color);
6205 VectorNormalize(relativepoint);
6206 for (q = 0; q < 3; q++)
6208 sa[q] += 0.5f * color[q];
6209 sx[q] += relativepoint[0] * color[q];
6210 sy[q] += relativepoint[1] * color[q];
6211 sz[q] += relativepoint[2] * color[q];
6212 sd[q] += intensity * relativepoint[q];
6217 // calculate the weighted-average light direction (bentnormal)
6218 for (q = 0; q < 3; q++)
6219 lightdir[q] = sd[q];
6220 VectorNormalize(lightdir);
6221 for (q = 0; q < 3; q++)
6223 // extract the diffuse color along the chosen direction and scale it
6224 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6225 // subtract some of diffuse from ambient
6226 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;