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_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, 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->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)
3351 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3353 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3355 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3356 if (mesh->sidetotals[r_shadow_shadowmapside])
3359 GL_CullFace(GL_NONE);
3360 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3361 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3362 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);
3366 else if (r_refdef.scene.worldentity->model)
3367 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);
3369 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3372 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3374 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3375 vec_t relativeshadowradius;
3376 RSurf_ActiveModelEntity(ent, false, false, false);
3377 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3378 // we need to re-init the shader for each entity because the matrix changed
3379 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3380 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3381 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3382 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3383 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3384 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3385 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3386 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3387 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3390 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3392 // set up properties for rendering light onto this entity
3393 RSurf_ActiveModelEntity(ent, true, true, false);
3394 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3395 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3396 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3397 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3400 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3402 if (!r_refdef.scene.worldmodel->DrawLight)
3405 // set up properties for rendering light onto this entity
3406 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3407 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3408 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3409 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3410 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3412 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3414 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3417 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3419 dp_model_t *model = ent->model;
3420 if (!model->DrawLight)
3423 R_Shadow_SetupEntityLight(ent);
3425 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3427 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3430 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3434 int numleafs, numsurfaces;
3435 int *leaflist, *surfacelist;
3436 unsigned char *leafpvs;
3437 unsigned char *shadowtrispvs;
3438 unsigned char *lighttrispvs;
3439 //unsigned char *surfacesides;
3440 int numlightentities;
3441 int numlightentities_noselfshadow;
3442 int numshadowentities;
3443 int numshadowentities_noselfshadow;
3444 // FIXME: bounds check lightentities and shadowentities, etc.
3445 static entity_render_t *lightentities[MAX_EDICTS];
3446 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3447 static entity_render_t *shadowentities[MAX_EDICTS];
3448 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3450 qboolean castshadows;
3452 rtlight->draw = false;
3453 rtlight->cached_numlightentities = 0;
3454 rtlight->cached_numlightentities_noselfshadow = 0;
3455 rtlight->cached_numshadowentities = 0;
3456 rtlight->cached_numshadowentities_noselfshadow = 0;
3457 rtlight->cached_numsurfaces = 0;
3458 rtlight->cached_lightentities = NULL;
3459 rtlight->cached_lightentities_noselfshadow = NULL;
3460 rtlight->cached_shadowentities = NULL;
3461 rtlight->cached_shadowentities_noselfshadow = NULL;
3462 rtlight->cached_shadowtrispvs = NULL;
3463 rtlight->cached_lighttrispvs = NULL;
3464 rtlight->cached_surfacelist = NULL;
3465 rtlight->shadowmapsidesize = 0;
3467 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3468 // skip lights that are basically invisible (color 0 0 0)
3469 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3471 // loading is done before visibility checks because loading should happen
3472 // all at once at the start of a level, not when it stalls gameplay.
3473 // (especially important to benchmarks)
3475 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3477 if (rtlight->compiled)
3478 R_RTLight_Uncompile(rtlight);
3479 R_RTLight_Compile(rtlight);
3483 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3485 // look up the light style value at this time
3486 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3487 VectorScale(rtlight->color, f, rtlight->currentcolor);
3489 if (rtlight->selected)
3491 f = 2 + sin(realtime * M_PI * 4.0);
3492 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3496 // skip if lightstyle is currently off
3497 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3500 // skip processing on corona-only lights
3504 // skip if the light box is not touching any visible leafs
3505 if (r_shadow_culllights_pvs.integer
3506 && r_refdef.scene.worldmodel
3507 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3508 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3511 // skip if the light box is not visible to traceline
3512 if (r_shadow_culllights_trace.integer)
3514 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))
3515 rtlight->trace_timer = realtime;
3516 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3520 // skip if the light box is off screen
3521 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3524 // in the typical case this will be quickly replaced by GetLightInfo
3525 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3526 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3528 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3530 // 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
3531 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3534 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3536 // compiled light, world available and can receive realtime lighting
3537 // retrieve leaf information
3538 numleafs = rtlight->static_numleafs;
3539 leaflist = rtlight->static_leaflist;
3540 leafpvs = rtlight->static_leafpvs;
3541 numsurfaces = rtlight->static_numsurfaces;
3542 surfacelist = rtlight->static_surfacelist;
3543 //surfacesides = NULL;
3544 shadowtrispvs = rtlight->static_shadowtrispvs;
3545 lighttrispvs = rtlight->static_lighttrispvs;
3547 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3549 // dynamic light, world available and can receive realtime lighting
3550 // calculate lit surfaces and leafs
3551 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);
3552 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3553 leaflist = r_shadow_buffer_leaflist;
3554 leafpvs = r_shadow_buffer_leafpvs;
3555 surfacelist = r_shadow_buffer_surfacelist;
3556 //surfacesides = r_shadow_buffer_surfacesides;
3557 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3558 lighttrispvs = r_shadow_buffer_lighttrispvs;
3559 // if the reduced leaf bounds are offscreen, skip it
3560 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3571 //surfacesides = NULL;
3572 shadowtrispvs = NULL;
3573 lighttrispvs = NULL;
3575 // check if light is illuminating any visible leafs
3578 for (i = 0; i < numleafs; i++)
3579 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3585 // make a list of lit entities and shadow casting entities
3586 numlightentities = 0;
3587 numlightentities_noselfshadow = 0;
3588 numshadowentities = 0;
3589 numshadowentities_noselfshadow = 0;
3591 // add dynamic entities that are lit by the light
3592 for (i = 0; i < r_refdef.scene.numentities; i++)
3595 entity_render_t *ent = r_refdef.scene.entities[i];
3597 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3599 // skip the object entirely if it is not within the valid
3600 // shadow-casting region (which includes the lit region)
3601 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3603 if (!(model = ent->model))
3605 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3607 // this entity wants to receive light, is visible, and is
3608 // inside the light box
3609 // TODO: check if the surfaces in the model can receive light
3610 // so now check if it's in a leaf seen by the light
3611 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))
3613 if (ent->flags & RENDER_NOSELFSHADOW)
3614 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3616 lightentities[numlightentities++] = ent;
3617 // since it is lit, it probably also casts a shadow...
3618 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3619 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3620 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3622 // note: exterior models without the RENDER_NOSELFSHADOW
3623 // flag still create a RENDER_NOSELFSHADOW shadow but
3624 // are lit normally, this means that they are
3625 // self-shadowing but do not shadow other
3626 // RENDER_NOSELFSHADOW entities such as the gun
3627 // (very weird, but keeps the player shadow off the gun)
3628 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3629 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3631 shadowentities[numshadowentities++] = ent;
3634 else if (ent->flags & RENDER_SHADOW)
3636 // this entity is not receiving light, but may still need to
3638 // TODO: check if the surfaces in the model can cast shadow
3639 // now check if it is in a leaf seen by the light
3640 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))
3642 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3643 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3644 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3646 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3647 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3649 shadowentities[numshadowentities++] = ent;
3654 // return if there's nothing at all to light
3655 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3658 // count this light in the r_speeds
3659 r_refdef.stats[r_stat_lights]++;
3661 // flag it as worth drawing later
3662 rtlight->draw = true;
3664 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3665 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3667 numshadowentities = numshadowentities_noselfshadow = 0;
3668 rtlight->castshadows = castshadows;
3670 // cache all the animated entities that cast a shadow but are not visible
3671 for (i = 0; i < numshadowentities; i++)
3672 R_AnimCache_GetEntity(shadowentities[i], false, false);
3673 for (i = 0; i < numshadowentities_noselfshadow; i++)
3674 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3676 // 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)
3677 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3679 for (i = 0; i < numshadowentities_noselfshadow; i++)
3680 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3681 numshadowentities_noselfshadow = 0;
3684 // we can convert noselfshadow to regular if there are no casters of that type
3685 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3687 for (i = 0; i < numlightentities_noselfshadow; i++)
3688 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3689 numlightentities_noselfshadow = 0;
3692 // allocate some temporary memory for rendering this light later in the frame
3693 // reusable buffers need to be copied, static data can be used as-is
3694 rtlight->cached_numlightentities = numlightentities;
3695 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3696 rtlight->cached_numshadowentities = numshadowentities;
3697 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3698 rtlight->cached_numsurfaces = numsurfaces;
3699 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3700 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3701 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3702 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3703 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3705 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3706 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3707 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3708 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3709 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3713 // compiled light data
3714 rtlight->cached_shadowtrispvs = shadowtrispvs;
3715 rtlight->cached_lighttrispvs = lighttrispvs;
3716 rtlight->cached_surfacelist = surfacelist;
3719 if (R_Shadow_ShadowMappingEnabled())
3721 // figure out the shadowmapping parameters for this light
3722 vec3_t nearestpoint;
3725 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3726 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3727 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3728 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3729 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3730 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3731 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3732 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3733 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3737 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3741 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3742 int numlightentities;
3743 int numlightentities_noselfshadow;
3744 int numshadowentities;
3745 int numshadowentities_noselfshadow;
3746 entity_render_t **lightentities;
3747 entity_render_t **lightentities_noselfshadow;
3748 entity_render_t **shadowentities;
3749 entity_render_t **shadowentities_noselfshadow;
3751 static unsigned char entitysides[MAX_EDICTS];
3752 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3758 matrix4x4_t radiustolight;
3760 // check if we cached this light this frame (meaning it is worth drawing)
3761 if (!rtlight->draw || !rtlight->castshadows)
3764 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3765 if (rtlight->shadowmapatlassidesize == 0)
3767 rtlight->castshadows = false;
3771 // set up a scissor rectangle for this light
3772 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3775 // don't let sound skip if going slow
3776 if (r_refdef.scene.extraupdate)
3779 numlightentities = rtlight->cached_numlightentities;
3780 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3781 numshadowentities = rtlight->cached_numshadowentities;
3782 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3783 numsurfaces = rtlight->cached_numsurfaces;
3784 lightentities = rtlight->cached_lightentities;
3785 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3786 shadowentities = rtlight->cached_shadowentities;
3787 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3788 shadowtrispvs = rtlight->cached_shadowtrispvs;
3789 lighttrispvs = rtlight->cached_lighttrispvs;
3790 surfacelist = rtlight->cached_surfacelist;
3792 // make this the active rtlight for rendering purposes
3793 R_Shadow_RenderMode_ActiveLight(rtlight);
3795 radiustolight = rtlight->matrix_worldtolight;
3796 Matrix4x4_Abs(&radiustolight);
3798 size = rtlight->shadowmapatlassidesize;
3799 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3801 surfacesides = NULL;
3806 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3808 castermask = rtlight->static_shadowmap_casters;
3809 receivermask = rtlight->static_shadowmap_receivers;
3813 surfacesides = r_shadow_buffer_surfacesides;
3814 for (i = 0; i < numsurfaces; i++)
3816 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3817 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3818 castermask |= surfacesides[i];
3819 receivermask |= surfacesides[i];
3824 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3825 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3826 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3827 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3829 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3833 for (i = 0; i < numshadowentities; i++)
3834 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3835 for (i = 0; i < numshadowentities_noselfshadow; i++)
3836 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3839 // there is no need to render shadows for sides that have no receivers...
3840 castermask &= receivermask;
3842 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3844 // render shadow casters into shadowmaps for this light
3845 for (side = 0; side < 6; side++)
3847 int bit = 1 << side;
3848 if (castermask & bit)
3850 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3852 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3853 for (i = 0; i < numshadowentities; i++)
3854 if (entitysides[i] & bit)
3855 R_Shadow_DrawEntityShadow(shadowentities[i]);
3856 for (i = 0; i < numshadowentities_noselfshadow; i++)
3857 if (entitysides_noselfshadow[i] & bit)
3858 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3861 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3862 if (numshadowentities_noselfshadow)
3864 for (side = 0; side < 6; side++)
3866 int bit = 1 << side;
3867 if (castermask & bit)
3869 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3871 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3872 for (i = 0; i < numshadowentities; i++)
3873 if (entitysides[i] & bit)
3874 R_Shadow_DrawEntityShadow(shadowentities[i]);
3880 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3884 unsigned char *shadowtrispvs, *lighttrispvs;
3885 int numlightentities;
3886 int numlightentities_noselfshadow;
3887 int numshadowentities;
3888 int numshadowentities_noselfshadow;
3889 entity_render_t **lightentities;
3890 entity_render_t **lightentities_noselfshadow;
3891 entity_render_t **shadowentities;
3892 entity_render_t **shadowentities_noselfshadow;
3894 qboolean castshadows;
3896 // check if we cached this light this frame (meaning it is worth drawing)
3900 // set up a scissor rectangle for this light
3901 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3904 // don't let sound skip if going slow
3905 if (r_refdef.scene.extraupdate)
3908 numlightentities = rtlight->cached_numlightentities;
3909 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3910 numshadowentities = rtlight->cached_numshadowentities;
3911 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3912 numsurfaces = rtlight->cached_numsurfaces;
3913 lightentities = rtlight->cached_lightentities;
3914 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3915 shadowentities = rtlight->cached_shadowentities;
3916 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3917 shadowtrispvs = rtlight->cached_shadowtrispvs;
3918 lighttrispvs = rtlight->cached_lighttrispvs;
3919 surfacelist = rtlight->cached_surfacelist;
3920 castshadows = rtlight->castshadows;
3922 // make this the active rtlight for rendering purposes
3923 R_Shadow_RenderMode_ActiveLight(rtlight);
3925 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3927 // optionally draw the illuminated areas
3928 // for performance analysis by level designers
3929 R_Shadow_RenderMode_VisibleLighting(false);
3931 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3932 for (i = 0;i < numlightentities;i++)
3933 R_Shadow_DrawEntityLight(lightentities[i]);
3934 for (i = 0;i < numlightentities_noselfshadow;i++)
3935 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3938 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3942 float shadowmapoffsetnoselfshadow = 0;
3943 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3944 Matrix4x4_Abs(&radiustolight);
3946 size = rtlight->shadowmapatlassidesize;
3947 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3949 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3951 if (rtlight->cached_numshadowentities_noselfshadow)
3952 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3954 // render lighting using the depth texture as shadowmap
3955 // draw lighting in the unmasked areas
3956 if (numsurfaces + numlightentities)
3958 R_Shadow_RenderMode_Lighting(false, true, false);
3959 // draw lighting in the unmasked areas
3961 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3962 for (i = 0; i < numlightentities; i++)
3963 R_Shadow_DrawEntityLight(lightentities[i]);
3965 // offset to the noselfshadow part of the atlas and draw those too
3966 if (numlightentities_noselfshadow)
3968 R_Shadow_RenderMode_Lighting(false, true, true);
3969 for (i = 0; i < numlightentities_noselfshadow; i++)
3970 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3973 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3974 if (r_shadow_usingdeferredprepass)
3975 R_Shadow_RenderMode_DrawDeferredLight(true);
3979 // draw lighting in the unmasked areas
3980 R_Shadow_RenderMode_Lighting(false, false, false);
3982 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3983 for (i = 0;i < numlightentities;i++)
3984 R_Shadow_DrawEntityLight(lightentities[i]);
3985 for (i = 0;i < numlightentities_noselfshadow;i++)
3986 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3988 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3989 if (r_shadow_usingdeferredprepass)
3990 R_Shadow_RenderMode_DrawDeferredLight(false);
3994 static void R_Shadow_FreeDeferred(void)
3996 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3997 r_shadow_prepassgeometryfbo = 0;
3999 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4000 r_shadow_prepasslightingdiffusespecularfbo = 0;
4002 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4003 r_shadow_prepasslightingdiffusefbo = 0;
4005 if (r_shadow_prepassgeometrydepthbuffer)
4006 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4007 r_shadow_prepassgeometrydepthbuffer = NULL;
4009 if (r_shadow_prepassgeometrynormalmaptexture)
4010 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4011 r_shadow_prepassgeometrynormalmaptexture = NULL;
4013 if (r_shadow_prepasslightingdiffusetexture)
4014 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4015 r_shadow_prepasslightingdiffusetexture = NULL;
4017 if (r_shadow_prepasslightingspeculartexture)
4018 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4019 r_shadow_prepasslightingspeculartexture = NULL;
4022 void R_Shadow_DrawPrepass(void)
4026 entity_render_t *ent;
4027 float clearcolor[4];
4029 R_Mesh_ResetTextureState();
4031 GL_ColorMask(1,1,1,1);
4032 GL_BlendFunc(GL_ONE, GL_ZERO);
4035 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4036 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4037 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4038 if (r_timereport_active)
4039 R_TimeReport("prepasscleargeom");
4041 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4042 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4043 if (r_timereport_active)
4044 R_TimeReport("prepassworld");
4046 for (i = 0;i < r_refdef.scene.numentities;i++)
4048 if (!r_refdef.viewcache.entityvisible[i])
4050 ent = r_refdef.scene.entities[i];
4051 if (ent->model && ent->model->DrawPrepass != NULL)
4052 ent->model->DrawPrepass(ent);
4055 if (r_timereport_active)
4056 R_TimeReport("prepassmodels");
4058 GL_DepthMask(false);
4059 GL_ColorMask(1,1,1,1);
4062 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4063 Vector4Set(clearcolor, 0, 0, 0, 0);
4064 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4065 if (r_timereport_active)
4066 R_TimeReport("prepassclearlit");
4068 R_Shadow_RenderMode_Begin();
4070 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4071 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4073 R_Shadow_RenderMode_End();
4075 if (r_timereport_active)
4076 R_TimeReport("prepasslights");
4079 #define MAX_SCENELIGHTS 65536
4080 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4082 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4084 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4086 r_shadow_scenemaxlights *= 2;
4087 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4088 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4090 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4094 void R_Shadow_DrawLightSprites(void);
4095 void R_Shadow_PrepareLights(void)
4104 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4105 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4106 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4108 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4109 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4110 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4111 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4112 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4113 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4114 r_shadow_shadowmapborder != shadowmapborder ||
4115 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4116 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4117 R_Shadow_FreeShadowMaps();
4119 r_shadow_usingshadowmaportho = false;
4121 switch (vid.renderpath)
4123 case RENDERPATH_GL20:
4125 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4127 r_shadow_usingdeferredprepass = false;
4128 if (r_shadow_prepass_width)
4129 R_Shadow_FreeDeferred();
4130 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4134 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4136 R_Shadow_FreeDeferred();
4138 r_shadow_usingdeferredprepass = true;
4139 r_shadow_prepass_width = vid.width;
4140 r_shadow_prepass_height = vid.height;
4141 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4142 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);
4143 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);
4144 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);
4146 // set up the geometry pass fbo (depth + normalmap)
4147 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4148 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4149 // render depth into a renderbuffer and other important properties into the normalmap texture
4151 // set up the lighting pass fbo (diffuse + specular)
4152 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4153 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4154 // render diffuse into one texture and specular into another,
4155 // with depth and normalmap bound as textures,
4156 // with depth bound as attachment as well
4158 // set up the lighting pass fbo (diffuse)
4159 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4160 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4161 // render diffuse into one texture,
4162 // with depth and normalmap bound as textures,
4163 // with depth bound as attachment as well
4167 case RENDERPATH_GLES2:
4168 r_shadow_usingdeferredprepass = false;
4172 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
4174 r_shadow_scenenumlights = 0;
4175 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4176 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4177 for (lightindex = 0; lightindex < range; lightindex++)
4179 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4180 if (light && (light->flags & flag))
4182 R_Shadow_PrepareLight(&light->rtlight);
4183 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4186 if (r_refdef.scene.rtdlight)
4188 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4190 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4191 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4194 else if (gl_flashblend.integer)
4196 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4198 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4199 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4200 VectorScale(rtlight->color, f, rtlight->currentcolor);
4204 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4205 if (r_shadow_debuglight.integer >= 0)
4207 r_shadow_scenenumlights = 0;
4208 lightindex = r_shadow_debuglight.integer;
4209 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4212 R_Shadow_PrepareLight(&light->rtlight);
4213 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4217 // if we're doing shadowmaps we need to prepare the atlas layout now
4218 if (R_Shadow_ShadowMappingEnabled())
4222 // allocate shadowmaps in the atlas now
4223 // 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...
4224 for (lod = 0; lod < 16; lod++)
4226 int packing_success = 0;
4227 int packing_failure = 0;
4228 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4229 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4230 if (r_shadow_shadowmapatlas_modelshadows_size)
4231 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);
4232 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4234 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4235 int size = rtlight->shadowmapsidesize >> lod;
4237 if (!rtlight->castshadows)
4239 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4242 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4243 if (rtlight->cached_numshadowentities_noselfshadow)
4245 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4247 rtlight->shadowmapatlassidesize = size;
4252 // note down that we failed to pack this one, it will have to disable shadows
4253 rtlight->shadowmapatlassidesize = 0;
4257 // generally everything fits and we stop here on the first iteration
4258 if (packing_failure == 0)
4263 if (r_editlights.integer)
4264 R_Shadow_DrawLightSprites();
4267 void R_Shadow_DrawShadowMaps(void)
4269 R_Shadow_RenderMode_Begin();
4270 R_Shadow_RenderMode_ActiveLight(NULL);
4272 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4273 R_Shadow_ClearShadowMapTexture();
4275 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4276 if (r_shadow_shadowmapatlas_modelshadows_size)
4278 R_Shadow_DrawModelShadowMaps();
4279 // don't let sound skip if going slow
4280 if (r_refdef.scene.extraupdate)
4284 if (R_Shadow_ShadowMappingEnabled())
4287 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4288 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4291 R_Shadow_RenderMode_End();
4294 void R_Shadow_DrawLights(void)
4298 R_Shadow_RenderMode_Begin();
4300 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4301 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4303 R_Shadow_RenderMode_End();
4306 #define MAX_MODELSHADOWS 1024
4307 static int r_shadow_nummodelshadows;
4308 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4310 void R_Shadow_PrepareModelShadows(void)
4313 float scale, size, radius, dot1, dot2;
4314 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4315 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4316 entity_render_t *ent;
4318 r_shadow_nummodelshadows = 0;
4319 r_shadow_shadowmapatlas_modelshadows_size = 0;
4321 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4324 size = r_shadow_shadowmaptexturesize / 4;
4325 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4326 radius = 0.5f * size / scale;
4328 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4329 VectorCopy(prvmshadowdir, shadowdir);
4330 VectorNormalize(shadowdir);
4331 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4332 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4333 if (fabs(dot1) <= fabs(dot2))
4334 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4336 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4337 VectorNormalize(shadowforward);
4338 CrossProduct(shadowdir, shadowforward, shadowright);
4339 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4340 VectorCopy(prvmshadowfocus, shadowfocus);
4341 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4342 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4343 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4344 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4345 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4347 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4349 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4350 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4351 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4352 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4353 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4354 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4356 for (i = 0; i < r_refdef.scene.numentities; i++)
4358 ent = r_refdef.scene.entities[i];
4359 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4361 // cast shadows from anything of the map (submodels are optional)
4362 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4364 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4366 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4367 R_AnimCache_GetEntity(ent, false, false);
4371 if (r_shadow_nummodelshadows)
4373 r_shadow_shadowmapatlas_modelshadows_x = 0;
4374 r_shadow_shadowmapatlas_modelshadows_y = 0;
4375 r_shadow_shadowmapatlas_modelshadows_size = size;
4379 static void R_Shadow_DrawModelShadowMaps(void)
4382 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4383 entity_render_t *ent;
4384 vec3_t relativelightorigin;
4385 vec3_t relativelightdirection, relativeforward, relativeright;
4386 vec3_t relativeshadowmins, relativeshadowmaxs;
4387 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4388 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4390 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4391 r_viewport_t viewport;
4393 size = r_shadow_shadowmapatlas_modelshadows_size;
4394 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4395 radius = 0.5f / scale;
4396 nearclip = -r_shadows_throwdistance.value;
4397 farclip = r_shadows_throwdistance.value;
4398 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);
4400 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4401 r_shadow_modelshadowmap_parameters[0] = size;
4402 r_shadow_modelshadowmap_parameters[1] = size;
4403 r_shadow_modelshadowmap_parameters[2] = 1.0;
4404 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4405 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4406 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4407 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4408 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4409 r_shadow_usingshadowmaportho = true;
4411 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4412 VectorCopy(prvmshadowdir, shadowdir);
4413 VectorNormalize(shadowdir);
4414 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4415 VectorCopy(prvmshadowfocus, shadowfocus);
4416 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4417 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4418 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4419 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4420 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4421 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4422 if (fabs(dot1) <= fabs(dot2))
4423 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4425 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4426 VectorNormalize(shadowforward);
4427 VectorM(scale, shadowforward, &m[0]);
4428 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4430 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4431 CrossProduct(shadowdir, shadowforward, shadowright);
4432 VectorM(scale, shadowright, &m[4]);
4433 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4434 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4435 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4436 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4437 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4438 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);
4439 R_SetViewport(&viewport);
4441 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4443 // render into a slightly restricted region so that the borders of the
4444 // shadowmap area fade away, rather than streaking across everything
4445 // outside the usable area
4446 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4448 for (i = 0;i < r_shadow_nummodelshadows;i++)
4450 ent = r_shadow_modelshadows[i];
4451 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4452 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4453 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4454 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4455 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4456 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4457 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4458 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4459 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4460 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4461 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4462 RSurf_ActiveModelEntity(ent, false, false, false);
4463 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4464 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4470 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4472 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4474 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4475 Cvar_SetValueQuick(&r_test, 0);
4480 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4481 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4482 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4483 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4484 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4485 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4488 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4491 vec3_t centerorigin;
4492 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4495 // if it's too close, skip it
4496 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4498 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4501 if (usequery && r_numqueries + 2 <= r_maxqueries)
4503 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4504 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4505 // 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
4506 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4508 switch(vid.renderpath)
4510 case RENDERPATH_GL20:
4511 case RENDERPATH_GLES2:
4512 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4514 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4515 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4516 GL_DepthFunc(GL_ALWAYS);
4517 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4518 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4519 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4520 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4521 GL_DepthFunc(GL_LEQUAL);
4522 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4523 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4524 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4525 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4526 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4532 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4535 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4537 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4540 unsigned int occlude = 0;
4541 GLint allpixels = 0, visiblepixels = 0;
4543 // now we have to check the query result
4544 if (rtlight->corona_queryindex_visiblepixels)
4546 switch(vid.renderpath)
4548 case RENDERPATH_GL20:
4549 case RENDERPATH_GLES2:
4550 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4551 // See if we can use the GPU-side method to prevent implicit sync
4552 if (vid.support.arb_query_buffer_object) {
4553 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4554 if (!r_shadow_occlusion_buf) {
4555 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
4556 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
4557 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
4559 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
4561 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
4562 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
4563 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4564 occlude = MATERIALFLAG_OCCLUDE;
4565 cscale *= rtlight->corona_visibility;
4570 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4571 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4572 if (visiblepixels < 1 || allpixels < 1)
4574 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4575 cscale *= rtlight->corona_visibility;
4585 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4588 VectorScale(rtlight->currentcolor, cscale, color);
4589 if (VectorLength(color) > (1.0f / 256.0f))
4592 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4595 VectorNegate(color, color);
4596 GL_BlendEquationSubtract(true);
4598 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4599 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);
4600 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
4602 GL_BlendEquationSubtract(false);
4606 void R_Shadow_DrawCoronas(void)
4609 qboolean usequery = false;
4614 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4616 if (r_fb.water.renderingscene)
4618 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4619 R_EntityMatrix(&identitymatrix);
4621 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4623 // check occlusion of coronas
4624 // use GL_ARB_occlusion_query if available
4625 // otherwise use raytraces
4627 switch (vid.renderpath)
4629 case RENDERPATH_GL20:
4630 case RENDERPATH_GLES2:
4631 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4632 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
4635 GL_ColorMask(0,0,0,0);
4636 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4637 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4640 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4641 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4643 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4646 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4647 GL_BlendFunc(GL_ONE, GL_ZERO);
4648 GL_CullFace(GL_NONE);
4649 GL_DepthMask(false);
4650 GL_DepthRange(0, 1);
4651 GL_PolygonOffset(0, 0);
4653 R_Mesh_ResetTextureState();
4654 R_SetupShader_Generic_NoTexture(false, false);
4659 for (lightindex = 0;lightindex < range;lightindex++)
4661 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4664 rtlight = &light->rtlight;
4665 rtlight->corona_visibility = 0;
4666 rtlight->corona_queryindex_visiblepixels = 0;
4667 rtlight->corona_queryindex_allpixels = 0;
4668 if (!(rtlight->flags & flag))
4670 if (rtlight->corona <= 0)
4672 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4674 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4676 for (i = 0;i < r_refdef.scene.numlights;i++)
4678 rtlight = r_refdef.scene.lights[i];
4679 rtlight->corona_visibility = 0;
4680 rtlight->corona_queryindex_visiblepixels = 0;
4681 rtlight->corona_queryindex_allpixels = 0;
4682 if (!(rtlight->flags & flag))
4684 if (rtlight->corona <= 0)
4686 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4689 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4691 // now draw the coronas using the query data for intensity info
4692 for (lightindex = 0;lightindex < range;lightindex++)
4694 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4697 rtlight = &light->rtlight;
4698 if (rtlight->corona_visibility <= 0)
4700 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4702 for (i = 0;i < r_refdef.scene.numlights;i++)
4704 rtlight = r_refdef.scene.lights[i];
4705 if (rtlight->corona_visibility <= 0)
4707 if (gl_flashblend.integer)
4708 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4710 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4716 static dlight_t *R_Shadow_NewWorldLight(void)
4718 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4721 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)
4725 // 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
4727 // validate parameters
4731 // copy to light properties
4732 VectorCopy(origin, light->origin);
4733 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4734 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4735 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4737 light->color[0] = max(color[0], 0);
4738 light->color[1] = max(color[1], 0);
4739 light->color[2] = max(color[2], 0);
4741 light->color[0] = color[0];
4742 light->color[1] = color[1];
4743 light->color[2] = color[2];
4744 light->radius = max(radius, 0);
4745 light->style = style;
4746 light->shadow = shadowenable;
4747 light->corona = corona;
4748 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4749 light->coronasizescale = coronasizescale;
4750 light->ambientscale = ambientscale;
4751 light->diffusescale = diffusescale;
4752 light->specularscale = specularscale;
4753 light->flags = flags;
4755 // update renderable light data
4756 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4757 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);
4760 static void R_Shadow_FreeWorldLight(dlight_t *light)
4762 if (r_shadow_selectedlight == light)
4763 r_shadow_selectedlight = NULL;
4764 R_RTLight_Uncompile(&light->rtlight);
4765 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4768 void R_Shadow_ClearWorldLights(void)
4772 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4773 for (lightindex = 0;lightindex < range;lightindex++)
4775 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4777 R_Shadow_FreeWorldLight(light);
4779 r_shadow_selectedlight = NULL;
4782 static void R_Shadow_SelectLight(dlight_t *light)
4784 if (r_shadow_selectedlight)
4785 r_shadow_selectedlight->selected = false;
4786 r_shadow_selectedlight = light;
4787 if (r_shadow_selectedlight)
4788 r_shadow_selectedlight->selected = true;
4791 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4793 // this is never batched (there can be only one)
4795 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4796 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4797 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4800 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4805 skinframe_t *skinframe;
4808 // this is never batched (due to the ent parameter changing every time)
4809 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4810 const dlight_t *light = (dlight_t *)ent;
4813 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4816 VectorScale(light->color, intensity, spritecolor);
4817 if (VectorLength(spritecolor) < 0.1732f)
4818 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4819 if (VectorLength(spritecolor) > 1.0f)
4820 VectorNormalize(spritecolor);
4822 // draw light sprite
4823 if (light->cubemapname[0] && !light->shadow)
4824 skinframe = r_editlights_sprcubemapnoshadowlight;
4825 else if (light->cubemapname[0])
4826 skinframe = r_editlights_sprcubemaplight;
4827 else if (!light->shadow)
4828 skinframe = r_editlights_sprnoshadowlight;
4830 skinframe = r_editlights_sprlight;
4832 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);
4833 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4835 // draw selection sprite if light is selected
4836 if (light->selected)
4838 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4839 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4840 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4844 void R_Shadow_DrawLightSprites(void)
4848 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4849 for (lightindex = 0;lightindex < range;lightindex++)
4851 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4853 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4855 if (!r_editlights_lockcursor)
4856 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4859 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4864 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4865 if (lightindex >= range)
4867 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4870 rtlight = &light->rtlight;
4871 //if (!(rtlight->flags & flag))
4873 VectorCopy(rtlight->shadoworigin, origin);
4874 *radius = rtlight->radius;
4875 VectorCopy(rtlight->color, color);
4879 static void R_Shadow_SelectLightInView(void)
4881 float bestrating, rating, temp[3];
4885 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4889 if (r_editlights_lockcursor)
4891 for (lightindex = 0;lightindex < range;lightindex++)
4893 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4896 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4897 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4900 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4901 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)
4903 bestrating = rating;
4908 R_Shadow_SelectLight(best);
4911 void R_Shadow_LoadWorldLights(void)
4913 int n, a, style, shadow, flags;
4914 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4915 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4916 if (cl.worldmodel == NULL)
4918 Con_Print("No map loaded.\n");
4921 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4922 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4932 for (;COM_Parse(t, true) && strcmp(
4933 if (COM_Parse(t, true))
4935 if (com_token[0] == '!')
4938 origin[0] = atof(com_token+1);
4941 origin[0] = atof(com_token);
4946 while (*s && *s != '\n' && *s != '\r')
4952 // check for modifier flags
4959 #if _MSC_VER >= 1400
4960 #define sscanf sscanf_s
4962 cubemapname[sizeof(cubemapname)-1] = 0;
4963 #if MAX_QPATH != 128
4964 #error update this code if MAX_QPATH changes
4966 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
4967 #if _MSC_VER >= 1400
4968 , sizeof(cubemapname)
4970 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4973 flags = LIGHTFLAG_REALTIMEMODE;
4981 coronasizescale = 0.25f;
4983 VectorClear(angles);
4986 if (a < 9 || !strcmp(cubemapname, "\"\""))
4988 // remove quotes on cubemapname
4989 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4992 namelen = strlen(cubemapname) - 2;
4993 memmove(cubemapname, cubemapname + 1, namelen);
4994 cubemapname[namelen] = '\0';
4998 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);
5001 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5009 Con_Printf("invalid rtlights file \"%s\"\n", name);
5010 Mem_Free(lightsstring);
5014 void R_Shadow_SaveWorldLights(void)
5018 size_t bufchars, bufmaxchars;
5020 char name[MAX_QPATH];
5021 char line[MAX_INPUTLINE];
5022 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5023 // I hate lines which are 3 times my screen size :( --blub
5026 if (cl.worldmodel == NULL)
5028 Con_Print("No map loaded.\n");
5031 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5032 bufchars = bufmaxchars = 0;
5034 for (lightindex = 0;lightindex < range;lightindex++)
5036 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5039 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5040 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);
5041 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5042 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]);
5044 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);
5045 if (bufchars + strlen(line) > bufmaxchars)
5047 bufmaxchars = bufchars + strlen(line) + 2048;
5049 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5053 memcpy(buf, oldbuf, bufchars);
5059 memcpy(buf + bufchars, line, strlen(line));
5060 bufchars += strlen(line);
5064 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5069 void R_Shadow_LoadLightsFile(void)
5072 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5073 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5074 if (cl.worldmodel == NULL)
5076 Con_Print("No map loaded.\n");
5079 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5080 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5088 while (*s && *s != '\n' && *s != '\r')
5094 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);
5098 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);
5101 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5102 radius = bound(15, radius, 4096);
5103 VectorScale(color, (2.0f / (8388608.0f)), color);
5104 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5112 Con_Printf("invalid lights file \"%s\"\n", name);
5113 Mem_Free(lightsstring);
5117 // tyrlite/hmap2 light types in the delay field
5118 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5120 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5132 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5133 char key[256], value[MAX_INPUTLINE];
5136 if (cl.worldmodel == NULL)
5138 Con_Print("No map loaded.\n");
5141 // try to load a .ent file first
5142 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5143 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5144 // and if that is not found, fall back to the bsp file entity string
5146 data = cl.worldmodel->brush.entities;
5149 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5151 type = LIGHTTYPE_MINUSX;
5152 origin[0] = origin[1] = origin[2] = 0;
5153 originhack[0] = originhack[1] = originhack[2] = 0;
5154 angles[0] = angles[1] = angles[2] = 0;
5155 color[0] = color[1] = color[2] = 1;
5156 light[0] = light[1] = light[2] = 1;light[3] = 300;
5157 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5167 if (!COM_ParseToken_Simple(&data, false, false, true))
5169 if (com_token[0] == '}')
5170 break; // end of entity
5171 if (com_token[0] == '_')
5172 strlcpy(key, com_token + 1, sizeof(key));
5174 strlcpy(key, com_token, sizeof(key));
5175 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5176 key[strlen(key)-1] = 0;
5177 if (!COM_ParseToken_Simple(&data, false, false, true))
5179 strlcpy(value, com_token, sizeof(value));
5181 // now that we have the key pair worked out...
5182 if (!strcmp("light", key))
5184 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5188 light[0] = vec[0] * (1.0f / 256.0f);
5189 light[1] = vec[0] * (1.0f / 256.0f);
5190 light[2] = vec[0] * (1.0f / 256.0f);
5196 light[0] = vec[0] * (1.0f / 255.0f);
5197 light[1] = vec[1] * (1.0f / 255.0f);
5198 light[2] = vec[2] * (1.0f / 255.0f);
5202 else if (!strcmp("delay", key))
5204 else if (!strcmp("origin", key))
5205 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5206 else if (!strcmp("angle", key))
5207 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5208 else if (!strcmp("angles", key))
5209 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5210 else if (!strcmp("color", key))
5211 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5212 else if (!strcmp("wait", key))
5213 fadescale = atof(value);
5214 else if (!strcmp("classname", key))
5216 if (!strncmp(value, "light", 5))
5219 if (!strcmp(value, "light_fluoro"))
5224 overridecolor[0] = 1;
5225 overridecolor[1] = 1;
5226 overridecolor[2] = 1;
5228 if (!strcmp(value, "light_fluorospark"))
5233 overridecolor[0] = 1;
5234 overridecolor[1] = 1;
5235 overridecolor[2] = 1;
5237 if (!strcmp(value, "light_globe"))
5242 overridecolor[0] = 1;
5243 overridecolor[1] = 0.8;
5244 overridecolor[2] = 0.4;
5246 if (!strcmp(value, "light_flame_large_yellow"))
5251 overridecolor[0] = 1;
5252 overridecolor[1] = 0.5;
5253 overridecolor[2] = 0.1;
5255 if (!strcmp(value, "light_flame_small_yellow"))
5260 overridecolor[0] = 1;
5261 overridecolor[1] = 0.5;
5262 overridecolor[2] = 0.1;
5264 if (!strcmp(value, "light_torch_small_white"))
5269 overridecolor[0] = 1;
5270 overridecolor[1] = 0.5;
5271 overridecolor[2] = 0.1;
5273 if (!strcmp(value, "light_torch_small_walltorch"))
5278 overridecolor[0] = 1;
5279 overridecolor[1] = 0.5;
5280 overridecolor[2] = 0.1;
5284 else if (!strcmp("style", key))
5285 style = atoi(value);
5286 else if (!strcmp("skin", key))
5287 skin = (int)atof(value);
5288 else if (!strcmp("pflags", key))
5289 pflags = (int)atof(value);
5290 //else if (!strcmp("effects", key))
5291 // effects = (int)atof(value);
5292 else if (cl.worldmodel->type == mod_brushq3)
5294 if (!strcmp("scale", key))
5295 lightscale = atof(value);
5296 if (!strcmp("fade", key))
5297 fadescale = atof(value);
5302 if (lightscale <= 0)
5306 if (color[0] == color[1] && color[0] == color[2])
5308 color[0] *= overridecolor[0];
5309 color[1] *= overridecolor[1];
5310 color[2] *= overridecolor[2];
5312 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5313 color[0] = color[0] * light[0];
5314 color[1] = color[1] * light[1];
5315 color[2] = color[2] * light[2];
5318 case LIGHTTYPE_MINUSX:
5320 case LIGHTTYPE_RECIPX:
5322 VectorScale(color, (1.0f / 16.0f), color);
5324 case LIGHTTYPE_RECIPXX:
5326 VectorScale(color, (1.0f / 16.0f), color);
5329 case LIGHTTYPE_NONE:
5333 case LIGHTTYPE_MINUSXX:
5336 VectorAdd(origin, originhack, origin);
5338 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);
5341 Mem_Free(entfiledata);
5345 static void R_Shadow_SetCursorLocationForView(void)
5348 vec3_t dest, endpos;
5350 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5351 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5352 if (trace.fraction < 1)
5354 dist = trace.fraction * r_editlights_cursordistance.value;
5355 push = r_editlights_cursorpushback.value;
5359 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5360 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5364 VectorClear( endpos );
5366 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5367 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5368 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5371 void R_Shadow_UpdateWorldLightSelection(void)
5373 if (r_editlights.integer)
5375 R_Shadow_SetCursorLocationForView();
5376 R_Shadow_SelectLightInView();
5379 R_Shadow_SelectLight(NULL);
5382 static void R_Shadow_EditLights_Clear_f(void)
5384 R_Shadow_ClearWorldLights();
5387 void R_Shadow_EditLights_Reload_f(void)
5391 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5392 R_Shadow_ClearWorldLights();
5393 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5395 R_Shadow_LoadWorldLights();
5396 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5397 R_Shadow_LoadLightsFile();
5399 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5401 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5402 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5406 static void R_Shadow_EditLights_Save_f(void)
5410 R_Shadow_SaveWorldLights();
5413 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5415 R_Shadow_ClearWorldLights();
5416 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5419 static void R_Shadow_EditLights_ImportLightsFile_f(void)
5421 R_Shadow_ClearWorldLights();
5422 R_Shadow_LoadLightsFile();
5425 static void R_Shadow_EditLights_Spawn_f(void)
5428 if (!r_editlights.integer)
5430 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5433 if (Cmd_Argc() != 1)
5435 Con_Print("r_editlights_spawn does not take parameters\n");
5438 color[0] = color[1] = color[2] = 1;
5439 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5442 static void R_Shadow_EditLights_Edit_f(void)
5444 vec3_t origin, angles, color;
5445 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5446 int style, shadows, flags, normalmode, realtimemode;
5447 char cubemapname[MAX_INPUTLINE];
5448 if (!r_editlights.integer)
5450 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5453 if (!r_shadow_selectedlight)
5455 Con_Print("No selected light.\n");
5458 VectorCopy(r_shadow_selectedlight->origin, origin);
5459 VectorCopy(r_shadow_selectedlight->angles, angles);
5460 VectorCopy(r_shadow_selectedlight->color, color);
5461 radius = r_shadow_selectedlight->radius;
5462 style = r_shadow_selectedlight->style;
5463 if (r_shadow_selectedlight->cubemapname)
5464 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5467 shadows = r_shadow_selectedlight->shadow;
5468 corona = r_shadow_selectedlight->corona;
5469 coronasizescale = r_shadow_selectedlight->coronasizescale;
5470 ambientscale = r_shadow_selectedlight->ambientscale;
5471 diffusescale = r_shadow_selectedlight->diffusescale;
5472 specularscale = r_shadow_selectedlight->specularscale;
5473 flags = r_shadow_selectedlight->flags;
5474 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5475 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5476 if (!strcmp(Cmd_Argv(1), "origin"))
5478 if (Cmd_Argc() != 5)
5480 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5483 origin[0] = atof(Cmd_Argv(2));
5484 origin[1] = atof(Cmd_Argv(3));
5485 origin[2] = atof(Cmd_Argv(4));
5487 else if (!strcmp(Cmd_Argv(1), "originscale"))
5489 if (Cmd_Argc() != 5)
5491 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5494 origin[0] *= atof(Cmd_Argv(2));
5495 origin[1] *= atof(Cmd_Argv(3));
5496 origin[2] *= atof(Cmd_Argv(4));
5498 else if (!strcmp(Cmd_Argv(1), "originx"))
5500 if (Cmd_Argc() != 3)
5502 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5505 origin[0] = atof(Cmd_Argv(2));
5507 else if (!strcmp(Cmd_Argv(1), "originy"))
5509 if (Cmd_Argc() != 3)
5511 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5514 origin[1] = atof(Cmd_Argv(2));
5516 else if (!strcmp(Cmd_Argv(1), "originz"))
5518 if (Cmd_Argc() != 3)
5520 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5523 origin[2] = atof(Cmd_Argv(2));
5525 else if (!strcmp(Cmd_Argv(1), "move"))
5527 if (Cmd_Argc() != 5)
5529 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5532 origin[0] += atof(Cmd_Argv(2));
5533 origin[1] += atof(Cmd_Argv(3));
5534 origin[2] += atof(Cmd_Argv(4));
5536 else if (!strcmp(Cmd_Argv(1), "movex"))
5538 if (Cmd_Argc() != 3)
5540 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5543 origin[0] += atof(Cmd_Argv(2));
5545 else if (!strcmp(Cmd_Argv(1), "movey"))
5547 if (Cmd_Argc() != 3)
5549 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5552 origin[1] += atof(Cmd_Argv(2));
5554 else if (!strcmp(Cmd_Argv(1), "movez"))
5556 if (Cmd_Argc() != 3)
5558 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5561 origin[2] += atof(Cmd_Argv(2));
5563 else if (!strcmp(Cmd_Argv(1), "angles"))
5565 if (Cmd_Argc() != 5)
5567 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5570 angles[0] = atof(Cmd_Argv(2));
5571 angles[1] = atof(Cmd_Argv(3));
5572 angles[2] = atof(Cmd_Argv(4));
5574 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5576 if (Cmd_Argc() != 3)
5578 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5581 angles[0] = atof(Cmd_Argv(2));
5583 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5585 if (Cmd_Argc() != 3)
5587 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5590 angles[1] = atof(Cmd_Argv(2));
5592 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5594 if (Cmd_Argc() != 3)
5596 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5599 angles[2] = atof(Cmd_Argv(2));
5601 else if (!strcmp(Cmd_Argv(1), "color"))
5603 if (Cmd_Argc() != 5)
5605 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5608 color[0] = atof(Cmd_Argv(2));
5609 color[1] = atof(Cmd_Argv(3));
5610 color[2] = atof(Cmd_Argv(4));
5612 else if (!strcmp(Cmd_Argv(1), "radius"))
5614 if (Cmd_Argc() != 3)
5616 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5619 radius = atof(Cmd_Argv(2));
5621 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5623 if (Cmd_Argc() == 3)
5625 double scale = atof(Cmd_Argv(2));
5632 if (Cmd_Argc() != 5)
5634 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5637 color[0] *= atof(Cmd_Argv(2));
5638 color[1] *= atof(Cmd_Argv(3));
5639 color[2] *= atof(Cmd_Argv(4));
5642 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5644 if (Cmd_Argc() != 3)
5646 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5649 radius *= atof(Cmd_Argv(2));
5651 else if (!strcmp(Cmd_Argv(1), "style"))
5653 if (Cmd_Argc() != 3)
5655 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5658 style = atoi(Cmd_Argv(2));
5660 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5664 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5667 if (Cmd_Argc() == 3)
5668 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5672 else if (!strcmp(Cmd_Argv(1), "shadows"))
5674 if (Cmd_Argc() != 3)
5676 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5679 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5681 else if (!strcmp(Cmd_Argv(1), "corona"))
5683 if (Cmd_Argc() != 3)
5685 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5688 corona = atof(Cmd_Argv(2));
5690 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5692 if (Cmd_Argc() != 3)
5694 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5697 coronasizescale = atof(Cmd_Argv(2));
5699 else if (!strcmp(Cmd_Argv(1), "ambient"))
5701 if (Cmd_Argc() != 3)
5703 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5706 ambientscale = atof(Cmd_Argv(2));
5708 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5710 if (Cmd_Argc() != 3)
5712 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5715 diffusescale = atof(Cmd_Argv(2));
5717 else if (!strcmp(Cmd_Argv(1), "specular"))
5719 if (Cmd_Argc() != 3)
5721 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5724 specularscale = atof(Cmd_Argv(2));
5726 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5728 if (Cmd_Argc() != 3)
5730 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5733 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5735 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5737 if (Cmd_Argc() != 3)
5739 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5742 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5746 Con_Print("usage: r_editlights_edit [property] [value]\n");
5747 Con_Print("Selected light's properties:\n");
5748 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5749 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5750 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5751 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5752 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5753 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5754 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5755 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5756 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5757 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5758 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5759 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5760 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5761 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5764 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5765 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5768 static void R_Shadow_EditLights_EditAll_f(void)
5771 dlight_t *light, *oldselected;
5774 if (!r_editlights.integer)
5776 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5780 oldselected = r_shadow_selectedlight;
5781 // EditLights doesn't seem to have a "remove" command or something so:
5782 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5783 for (lightindex = 0;lightindex < range;lightindex++)
5785 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5788 R_Shadow_SelectLight(light);
5789 R_Shadow_EditLights_Edit_f();
5791 // return to old selected (to not mess editing once selection is locked)
5792 R_Shadow_SelectLight(oldselected);
5795 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5797 int lightnumber, lightcount;
5798 size_t lightindex, range;
5803 if (!r_editlights.integer)
5806 // update cvars so QC can query them
5807 if (r_shadow_selectedlight)
5809 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5810 Cvar_SetQuick(&r_editlights_current_origin, temp);
5811 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5812 Cvar_SetQuick(&r_editlights_current_angles, temp);
5813 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5814 Cvar_SetQuick(&r_editlights_current_color, temp);
5815 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5816 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5817 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5818 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5819 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5820 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5821 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5822 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5823 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5824 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5825 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5828 // draw properties on screen
5829 if (!r_editlights_drawproperties.integer)
5831 x = vid_conwidth.value - 320;
5833 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5836 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5837 for (lightindex = 0;lightindex < range;lightindex++)
5839 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5842 if (light == r_shadow_selectedlight)
5843 lightnumber = (int)lightindex;
5846 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;
5847 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;
5849 if (r_shadow_selectedlight == NULL)
5851 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;
5852 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;
5853 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;
5854 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;
5855 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;
5856 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;
5857 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;
5858 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;
5859 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;
5860 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;
5861 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;
5862 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;
5863 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;
5864 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;
5865 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;
5867 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;
5868 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;
5869 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;
5870 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;
5871 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;
5872 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;
5873 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;
5874 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;
5875 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;
5876 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;
5879 static void R_Shadow_EditLights_ToggleShadow_f(void)
5881 if (!r_editlights.integer)
5883 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5886 if (!r_shadow_selectedlight)
5888 Con_Print("No selected light.\n");
5891 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);
5894 static void R_Shadow_EditLights_ToggleCorona_f(void)
5896 if (!r_editlights.integer)
5898 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5901 if (!r_shadow_selectedlight)
5903 Con_Print("No selected light.\n");
5906 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);
5909 static void R_Shadow_EditLights_Remove_f(void)
5911 if (!r_editlights.integer)
5913 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5916 if (!r_shadow_selectedlight)
5918 Con_Print("No selected light.\n");
5921 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5922 r_shadow_selectedlight = NULL;
5925 static void R_Shadow_EditLights_Help_f(void)
5928 "Documentation on r_editlights system:\n"
5930 "r_editlights : enable/disable editing mode\n"
5931 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5932 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5933 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5934 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5935 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5937 "r_editlights_help : this help\n"
5938 "r_editlights_clear : remove all lights\n"
5939 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5940 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5941 "r_editlights_save : save to .rtlights file\n"
5942 "r_editlights_spawn : create a light with default settings\n"
5943 "r_editlights_edit command : edit selected light - more documentation below\n"
5944 "r_editlights_remove : remove selected light\n"
5945 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5946 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5947 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5949 "origin x y z : set light location\n"
5950 "originx x: set x component of light location\n"
5951 "originy y: set y component of light location\n"
5952 "originz z: set z component of light location\n"
5953 "move x y z : adjust light location\n"
5954 "movex x: adjust x component of light location\n"
5955 "movey y: adjust y component of light location\n"
5956 "movez z: adjust z component of light location\n"
5957 "angles x y z : set light angles\n"
5958 "anglesx x: set x component of light angles\n"
5959 "anglesy y: set y component of light angles\n"
5960 "anglesz z: set z component of light angles\n"
5961 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5962 "radius radius : set radius (size) of light\n"
5963 "colorscale grey : multiply color of light (1 does nothing)\n"
5964 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5965 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5966 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5967 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5968 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5969 "cubemap basename : set filter cubemap of light\n"
5970 "shadows 1/0 : turn on/off shadows\n"
5971 "corona n : set corona intensity\n"
5972 "coronasize n : set corona size (0-1)\n"
5973 "ambient n : set ambient intensity (0-1)\n"
5974 "diffuse n : set diffuse intensity (0-1)\n"
5975 "specular n : set specular intensity (0-1)\n"
5976 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5977 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5978 "<nothing> : print light properties to console\n"
5982 static void R_Shadow_EditLights_CopyInfo_f(void)
5984 if (!r_editlights.integer)
5986 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5989 if (!r_shadow_selectedlight)
5991 Con_Print("No selected light.\n");
5994 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5995 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5996 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5997 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5998 if (r_shadow_selectedlight->cubemapname)
5999 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6001 r_shadow_bufferlight.cubemapname[0] = 0;
6002 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6003 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6004 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6005 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6006 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6007 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6008 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6011 static void R_Shadow_EditLights_PasteInfo_f(void)
6013 if (!r_editlights.integer)
6015 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6018 if (!r_shadow_selectedlight)
6020 Con_Print("No selected light.\n");
6023 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);
6026 static void R_Shadow_EditLights_Lock_f(void)
6028 if (!r_editlights.integer)
6030 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6033 if (r_editlights_lockcursor)
6035 r_editlights_lockcursor = false;
6038 if (!r_shadow_selectedlight)
6040 Con_Print("No selected light to lock on.\n");
6043 r_editlights_lockcursor = true;
6046 static void R_Shadow_EditLights_Init(void)
6048 Cvar_RegisterVariable(&r_editlights);
6049 Cvar_RegisterVariable(&r_editlights_cursordistance);
6050 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6051 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6052 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6053 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6054 Cvar_RegisterVariable(&r_editlights_drawproperties);
6055 Cvar_RegisterVariable(&r_editlights_current_origin);
6056 Cvar_RegisterVariable(&r_editlights_current_angles);
6057 Cvar_RegisterVariable(&r_editlights_current_color);
6058 Cvar_RegisterVariable(&r_editlights_current_radius);
6059 Cvar_RegisterVariable(&r_editlights_current_corona);
6060 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6061 Cvar_RegisterVariable(&r_editlights_current_style);
6062 Cvar_RegisterVariable(&r_editlights_current_shadows);
6063 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6064 Cvar_RegisterVariable(&r_editlights_current_ambient);
6065 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6066 Cvar_RegisterVariable(&r_editlights_current_specular);
6067 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6068 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6069 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6070 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6071 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)");
6072 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6073 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6074 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6075 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)");
6076 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6077 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6078 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6079 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6080 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6081 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6082 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)");
6083 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6089 =============================================================================
6093 =============================================================================
6096 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6098 int i, numlights, flag, q;
6101 float relativepoint[3];
6106 float sa[3], sx[3], sy[3], sz[3], sd[3];
6109 // use first order spherical harmonics to combine directional lights
6110 for (q = 0; q < 3; q++)
6111 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6113 if (flags & LP_LIGHTMAP)
6115 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6117 float tempambient[3];
6118 for (q = 0; q < 3; q++)
6119 tempambient[q] = color[q] = relativepoint[q] = 0;
6120 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6121 // calculate a weighted average light direction as well
6122 intensity = VectorLength(color);
6123 for (q = 0; q < 3; q++)
6125 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6126 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6127 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6128 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6129 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6134 // unlit map - fullbright but scaled by lightmapintensity
6135 for (q = 0; q < 3; q++)
6136 sa[q] += lightmapintensity;
6140 if (flags & LP_RTWORLD)
6142 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6143 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6144 for (i = 0; i < numlights; i++)
6146 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6149 light = &dlight->rtlight;
6150 if (!(light->flags & flag))
6153 lightradius2 = light->radius * light->radius;
6154 VectorSubtract(light->shadoworigin, p, relativepoint);
6155 dist2 = VectorLength2(relativepoint);
6156 if (dist2 >= lightradius2)
6158 dist = sqrt(dist2) / light->radius;
6159 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6160 if (intensity <= 0.0f)
6162 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)
6164 for (q = 0; q < 3; q++)
6165 color[q] = light->currentcolor[q] * intensity;
6166 intensity = VectorLength(color);
6167 VectorNormalize(relativepoint);
6168 for (q = 0; q < 3; q++)
6170 sa[q] += 0.5f * color[q];
6171 sx[q] += relativepoint[0] * color[q];
6172 sy[q] += relativepoint[1] * color[q];
6173 sz[q] += relativepoint[2] * color[q];
6174 sd[q] += intensity * relativepoint[q];
6177 // FIXME: sample bouncegrid too!
6180 if (flags & LP_DYNLIGHT)
6183 for (i = 0;i < r_refdef.scene.numlights;i++)
6185 light = r_refdef.scene.lights[i];
6187 lightradius2 = light->radius * light->radius;
6188 VectorSubtract(light->shadoworigin, p, relativepoint);
6189 dist2 = VectorLength2(relativepoint);
6190 if (dist2 >= lightradius2)
6192 dist = sqrt(dist2) / light->radius;
6193 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6194 if (intensity <= 0.0f)
6196 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)
6198 for (q = 0; q < 3; q++)
6199 color[q] = light->currentcolor[q] * intensity;
6200 intensity = VectorLength(color);
6201 VectorNormalize(relativepoint);
6202 for (q = 0; q < 3; q++)
6204 sa[q] += 0.5f * color[q];
6205 sx[q] += relativepoint[0] * color[q];
6206 sy[q] += relativepoint[1] * color[q];
6207 sz[q] += relativepoint[2] * color[q];
6208 sd[q] += intensity * relativepoint[q];
6213 // calculate the weighted-average light direction (bentnormal)
6214 for (q = 0; q < 3; q++)
6215 lightdir[q] = sd[q];
6216 VectorNormalize(lightdir);
6217 for (q = 0; q < 3; q++)
6219 // extract the diffuse color along the chosen direction and scale it
6220 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6221 // subtract some of diffuse from ambient
6222 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;