3 #include "cl_collision.h"
7 static void R_Shadow_EditLights_Init(void);
9 typedef enum r_shadow_rendermode_e
11 R_SHADOW_RENDERMODE_NONE,
12 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
13 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
14 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
15 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
16 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
17 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
18 R_SHADOW_RENDERMODE_LIGHT_GLSL,
19 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
20 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
21 R_SHADOW_RENDERMODE_SHADOWMAP2D
23 r_shadow_rendermode_t;
25 typedef enum r_shadow_shadowmode_e
27 R_SHADOW_SHADOWMODE_SHADOWMAP2D
29 r_shadow_shadowmode_t;
31 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
32 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
33 int r_shadow_scenemaxlights;
34 int r_shadow_scenenumlights;
35 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
36 qboolean r_shadow_usingshadowmap2d;
37 qboolean r_shadow_usingshadowmaportho;
38 int r_shadow_shadowmapside;
39 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
40 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
41 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
42 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
44 int r_shadow_drawbuffer;
45 int r_shadow_readbuffer;
47 int r_shadow_cullface_front, r_shadow_cullface_back;
48 GLuint r_shadow_fbo2d;
49 r_shadow_shadowmode_t r_shadow_shadowmode;
50 int r_shadow_shadowmapfilterquality;
51 int r_shadow_shadowmapdepthbits;
52 int r_shadow_shadowmapmaxsize;
53 int r_shadow_shadowmaptexturesize;
54 qboolean r_shadow_shadowmapvsdct;
55 qboolean r_shadow_shadowmapsampler;
56 qboolean r_shadow_shadowmapshadowsampler;
57 int r_shadow_shadowmappcf;
58 int r_shadow_shadowmapborder;
59 matrix4x4_t r_shadow_shadowmapmatrix;
60 int r_shadow_lightscissor[4];
61 qboolean r_shadow_usingdeferredprepass;
62 qboolean r_shadow_shadowmapdepthtexture;
63 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
64 int r_shadow_shadowmapatlas_modelshadows_x;
65 int r_shadow_shadowmapatlas_modelshadows_y;
66 int r_shadow_shadowmapatlas_modelshadows_size;
67 int maxshadowtriangles;
70 int maxshadowvertices;
71 float *shadowvertex3f;
81 unsigned char *shadowsides;
89 int r_shadow_buffer_numleafpvsbytes;
90 unsigned char *r_shadow_buffer_visitingleafpvs;
91 unsigned char *r_shadow_buffer_leafpvs;
92 int *r_shadow_buffer_leaflist;
94 int r_shadow_buffer_numsurfacepvsbytes;
95 unsigned char *r_shadow_buffer_surfacepvs;
96 int *r_shadow_buffer_surfacelist;
97 unsigned char *r_shadow_buffer_surfacesides;
99 int r_shadow_buffer_numshadowtrispvsbytes;
100 unsigned char *r_shadow_buffer_shadowtrispvs;
101 int r_shadow_buffer_numlighttrispvsbytes;
102 unsigned char *r_shadow_buffer_lighttrispvs;
104 rtexturepool_t *r_shadow_texturepool;
105 rtexture_t *r_shadow_attenuationgradienttexture;
106 skinframe_t *r_shadow_lightcorona;
107 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
108 rtexture_t *r_shadow_shadowmap2ddepthtexture;
109 rtexture_t *r_shadow_shadowmapvsdcttexture;
111 GLuint r_shadow_prepassgeometryfbo;
112 GLuint r_shadow_prepasslightingdiffusespecularfbo;
113 GLuint r_shadow_prepasslightingdiffusefbo;
114 int r_shadow_prepass_width;
115 int r_shadow_prepass_height;
116 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
117 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
118 rtexture_t *r_shadow_prepasslightingdiffusetexture;
119 rtexture_t *r_shadow_prepasslightingspeculartexture;
121 int r_shadow_viewfbo;
122 rtexture_t *r_shadow_viewdepthtexture;
123 rtexture_t *r_shadow_viewcolortexture;
126 int r_shadow_viewwidth;
127 int r_shadow_viewheight;
129 // lights are reloaded when this changes
130 char r_shadow_mapname[MAX_QPATH];
132 // buffer for doing corona fading
133 unsigned int r_shadow_occlusion_buf = 0;
135 // used only for light filters (cubemaps)
136 rtexturepool_t *r_shadow_filters_texturepool;
138 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
139 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
140 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
141 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
142 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
143 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
144 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
145 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
146 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
147 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
148 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
149 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
150 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
151 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
152 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
153 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
154 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
155 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
156 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
157 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
158 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
159 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
160 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
161 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
162 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
163 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
164 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
165 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
166 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
167 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
168 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
169 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
170 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
171 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
172 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
173 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
174 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
175 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
176 cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
177 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
178 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
179 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
180 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
181 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
182 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
183 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
184 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
185 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
186 cvar_t r_shadow_culllights_pvs = {CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
187 cvar_t r_shadow_culllights_trace = {CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
188 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
189 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
190 cvar_t r_shadow_culllights_trace_expand = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
191 cvar_t r_shadow_culllights_trace_pad = {CVAR_SAVE, "r_shadow_culllights_trace_pad", "8", "accept traces that hit within this many units of the light bounds"};
192 cvar_t r_shadow_culllights_trace_samples = {CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
193 cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"};
194 cvar_t r_shadow_culllights_trace_delay = {CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
195 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
196 cvar_t r_shadow_bouncegrid_blur = {CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
197 cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"};
198 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color" };
199 cvar_t r_shadow_bouncegrid_dynamic_culllightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_culllightpaths", "1", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
200 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "1", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
201 cvar_t r_shadow_bouncegrid_dynamic_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_dlightparticlemultiplier", "1", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
202 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
203 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1)"};
204 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0)"};
205 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxphotons", "25000", "upper bound on photons to shoot per update, divided proportionately between lights - normally the number of photons is calculated by energyperphoton"};
206 cvar_t r_shadow_bouncegrid_dynamic_quality = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_quality", "1", "amount of photons that should be fired (this is multiplied by spacing ^ 2 to make it adaptive with spacing changes)"};
207 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
208 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
209 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
210 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
211 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
212 cvar_t r_shadow_bouncegrid_floatcolors = {CVAR_SAVE, "r_shadow_bouncegrid_floatcolors", "1", "upload texture as RGBA16F (or RGBA32F when set to 2) rather than RGBA8 format - this gives more dynamic range and accuracy"};
213 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
214 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "1", "overall brightness of bouncegrid texture"};
215 cvar_t r_shadow_bouncegrid_lightpathsize = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize", "64", "radius (in game units) of the light path for accumulation of light in the bouncegrid texture"};
216 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)" };
217 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"};
218 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
219 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" };
220 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)" };
221 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
222 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" };
223 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
224 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
225 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"};
226 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
227 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)" };
228 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
229 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
230 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"};
231 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"};
232 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
233 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
234 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
235 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
236 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
237 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
238 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
239 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
240 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
241 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
242 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
243 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
244 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
245 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
246 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
247 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
248 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
249 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
250 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
251 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
252 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
253 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
255 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
257 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
258 #define ATTENTABLESIZE 256
259 // 1D gradient, 2D circle and 3D sphere attenuation textures
260 #define ATTEN1DSIZE 32
261 #define ATTEN2DSIZE 64
262 #define ATTEN3DSIZE 32
264 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
265 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
266 static float r_shadow_attentable[ATTENTABLESIZE+1];
268 rtlight_t *r_shadow_compilingrtlight;
269 static memexpandablearray_t r_shadow_worldlightsarray;
270 dlight_t *r_shadow_selectedlight;
271 dlight_t r_shadow_bufferlight;
272 vec3_t r_editlights_cursorlocation;
273 qboolean r_editlights_lockcursor;
275 extern int con_vislines;
277 void R_Shadow_UncompileWorldLights(void);
278 void R_Shadow_ClearWorldLights(void);
279 void R_Shadow_SaveWorldLights(void);
280 void R_Shadow_LoadWorldLights(void);
281 void R_Shadow_LoadLightsFile(void);
282 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
283 void R_Shadow_EditLights_Reload_f(void);
284 static void R_Shadow_MakeTextures(void);
286 #define EDLIGHTSPRSIZE 8
287 skinframe_t *r_editlights_sprcursor;
288 skinframe_t *r_editlights_sprlight;
289 skinframe_t *r_editlights_sprnoshadowlight;
290 skinframe_t *r_editlights_sprcubemaplight;
291 skinframe_t *r_editlights_sprcubemapnoshadowlight;
292 skinframe_t *r_editlights_sprselection;
294 static void R_Shadow_DrawModelShadowMaps(void);
295 static void R_Shadow_MakeShadowMap(int texturesize);
296 static void R_Shadow_MakeVSDCT(void);
297 static void R_Shadow_SetShadowMode(void)
299 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
300 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
301 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
302 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
303 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
304 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
305 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
306 r_shadow_shadowmapsampler = false;
307 r_shadow_shadowmappcf = 0;
308 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
309 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
310 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
311 if (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)
313 switch(vid.renderpath)
315 case RENDERPATH_GL32:
316 if(r_shadow_shadowmapfilterquality < 0)
318 if (!r_fb.usedepthtextures)
319 r_shadow_shadowmappcf = 1;
320 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
322 r_shadow_shadowmapsampler = true;
323 r_shadow_shadowmappcf = 1;
325 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
326 r_shadow_shadowmappcf = 1;
327 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
328 r_shadow_shadowmappcf = 1;
330 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
334 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
335 switch (r_shadow_shadowmapfilterquality)
340 r_shadow_shadowmappcf = 1;
343 r_shadow_shadowmappcf = 1;
346 r_shadow_shadowmappcf = 2;
350 if (!r_fb.usedepthtextures)
351 r_shadow_shadowmapsampler = false;
352 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
354 case RENDERPATH_GLES2:
359 if(R_CompileShader_CheckStaticParms())
363 qboolean R_Shadow_ShadowMappingEnabled(void)
365 switch (r_shadow_shadowmode)
367 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
374 static void R_Shadow_FreeShadowMaps(void)
376 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
378 R_Shadow_SetShadowMode();
380 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
384 if (r_shadow_shadowmap2ddepthtexture)
385 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
386 r_shadow_shadowmap2ddepthtexture = NULL;
388 if (r_shadow_shadowmap2ddepthbuffer)
389 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
390 r_shadow_shadowmap2ddepthbuffer = NULL;
392 if (r_shadow_shadowmapvsdcttexture)
393 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
394 r_shadow_shadowmapvsdcttexture = NULL;
397 static void r_shadow_start(void)
399 // allocate vertex processing arrays
400 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
401 r_shadow_attenuationgradienttexture = NULL;
402 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
403 r_shadow_shadowmap2ddepthtexture = NULL;
404 r_shadow_shadowmap2ddepthbuffer = NULL;
405 r_shadow_shadowmapvsdcttexture = NULL;
406 r_shadow_shadowmapmaxsize = 0;
407 r_shadow_shadowmaptexturesize = 0;
408 r_shadow_shadowmapfilterquality = -1;
409 r_shadow_shadowmapdepthbits = 0;
410 r_shadow_shadowmapvsdct = false;
411 r_shadow_shadowmapsampler = false;
412 r_shadow_shadowmappcf = 0;
415 R_Shadow_FreeShadowMaps();
417 r_shadow_texturepool = NULL;
418 r_shadow_filters_texturepool = NULL;
419 R_Shadow_MakeTextures();
420 r_shadow_scenemaxlights = 0;
421 r_shadow_scenenumlights = 0;
422 r_shadow_scenelightlist = NULL;
423 maxshadowtriangles = 0;
424 shadowelements = NULL;
425 maxshadowvertices = 0;
426 shadowvertex3f = NULL;
434 shadowmarklist = NULL;
439 shadowsideslist = NULL;
440 r_shadow_buffer_numleafpvsbytes = 0;
441 r_shadow_buffer_visitingleafpvs = NULL;
442 r_shadow_buffer_leafpvs = NULL;
443 r_shadow_buffer_leaflist = NULL;
444 r_shadow_buffer_numsurfacepvsbytes = 0;
445 r_shadow_buffer_surfacepvs = NULL;
446 r_shadow_buffer_surfacelist = NULL;
447 r_shadow_buffer_surfacesides = NULL;
448 r_shadow_buffer_numshadowtrispvsbytes = 0;
449 r_shadow_buffer_shadowtrispvs = NULL;
450 r_shadow_buffer_numlighttrispvsbytes = 0;
451 r_shadow_buffer_lighttrispvs = NULL;
453 r_shadow_usingdeferredprepass = false;
454 r_shadow_prepass_width = r_shadow_prepass_height = 0;
456 // determine renderpath specific capabilities, we don't need to figure
457 // these out per frame...
458 switch(vid.renderpath)
460 case RENDERPATH_GL32:
461 r_shadow_bouncegrid_state.allowdirectionalshading = true;
462 r_shadow_bouncegrid_state.capable = true;
464 case RENDERPATH_GLES2:
465 // for performance reasons, do not use directional shading on GLES devices
466 r_shadow_bouncegrid_state.capable = true;
471 static void R_Shadow_FreeDeferred(void);
472 static void r_shadow_shutdown(void)
475 R_Shadow_UncompileWorldLights();
477 R_Shadow_FreeShadowMaps();
479 r_shadow_usingdeferredprepass = false;
480 if (r_shadow_prepass_width)
481 R_Shadow_FreeDeferred();
482 r_shadow_prepass_width = r_shadow_prepass_height = 0;
485 r_shadow_scenemaxlights = 0;
486 r_shadow_scenenumlights = 0;
487 if (r_shadow_scenelightlist)
488 Mem_Free(r_shadow_scenelightlist);
489 r_shadow_scenelightlist = NULL;
490 r_shadow_bouncegrid_state.highpixels = NULL;
491 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
492 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
493 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
494 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
495 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
496 r_shadow_bouncegrid_state.maxsplatpaths = 0;
497 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
498 r_shadow_attenuationgradienttexture = NULL;
499 R_FreeTexturePool(&r_shadow_texturepool);
500 R_FreeTexturePool(&r_shadow_filters_texturepool);
501 maxshadowtriangles = 0;
503 Mem_Free(shadowelements);
504 shadowelements = NULL;
506 Mem_Free(shadowvertex3f);
507 shadowvertex3f = NULL;
510 Mem_Free(vertexupdate);
513 Mem_Free(vertexremap);
519 Mem_Free(shadowmark);
522 Mem_Free(shadowmarklist);
523 shadowmarklist = NULL;
528 Mem_Free(shadowsides);
531 Mem_Free(shadowsideslist);
532 shadowsideslist = NULL;
533 r_shadow_buffer_numleafpvsbytes = 0;
534 if (r_shadow_buffer_visitingleafpvs)
535 Mem_Free(r_shadow_buffer_visitingleafpvs);
536 r_shadow_buffer_visitingleafpvs = NULL;
537 if (r_shadow_buffer_leafpvs)
538 Mem_Free(r_shadow_buffer_leafpvs);
539 r_shadow_buffer_leafpvs = NULL;
540 if (r_shadow_buffer_leaflist)
541 Mem_Free(r_shadow_buffer_leaflist);
542 r_shadow_buffer_leaflist = NULL;
543 r_shadow_buffer_numsurfacepvsbytes = 0;
544 if (r_shadow_buffer_surfacepvs)
545 Mem_Free(r_shadow_buffer_surfacepvs);
546 r_shadow_buffer_surfacepvs = NULL;
547 if (r_shadow_buffer_surfacelist)
548 Mem_Free(r_shadow_buffer_surfacelist);
549 r_shadow_buffer_surfacelist = NULL;
550 if (r_shadow_buffer_surfacesides)
551 Mem_Free(r_shadow_buffer_surfacesides);
552 r_shadow_buffer_surfacesides = NULL;
553 r_shadow_buffer_numshadowtrispvsbytes = 0;
554 if (r_shadow_buffer_shadowtrispvs)
555 Mem_Free(r_shadow_buffer_shadowtrispvs);
556 r_shadow_buffer_numlighttrispvsbytes = 0;
557 if (r_shadow_buffer_lighttrispvs)
558 Mem_Free(r_shadow_buffer_lighttrispvs);
561 static void r_shadow_newmap(void)
563 r_shadow_bouncegrid_state.highpixels = NULL;
564 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
565 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
566 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
567 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
568 if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
570 r_shadow_bouncegrid_state.maxsplatpaths = 0;
572 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
573 if (r_shadow_lightcorona) { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
574 if (r_editlights_sprcursor) { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
575 if (r_editlights_sprlight) { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
576 if (r_editlights_sprnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
577 if (r_editlights_sprcubemaplight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
578 if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
579 if (r_editlights_sprselection) { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
580 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
581 R_Shadow_EditLights_Reload_f();
584 void R_Shadow_Init(void)
586 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
587 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
588 Cvar_RegisterVariable(&r_shadow_usebihculling);
589 Cvar_RegisterVariable(&r_shadow_usenormalmap);
590 Cvar_RegisterVariable(&r_shadow_debuglight);
591 Cvar_RegisterVariable(&r_shadow_deferred);
592 Cvar_RegisterVariable(&r_shadow_gloss);
593 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
594 Cvar_RegisterVariable(&r_shadow_glossintensity);
595 Cvar_RegisterVariable(&r_shadow_glossexponent);
596 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
597 Cvar_RegisterVariable(&r_shadow_glossexact);
598 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
599 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
600 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
601 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
602 Cvar_RegisterVariable(&r_shadow_projectdistance);
603 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
604 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
605 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
606 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
607 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
608 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
609 Cvar_RegisterVariable(&r_shadow_realtime_world);
610 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
611 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
612 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
613 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
614 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
615 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
616 Cvar_RegisterVariable(&r_shadow_scissor);
617 Cvar_RegisterVariable(&r_shadow_shadowmapping);
618 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
619 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
620 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
621 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
622 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
623 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
624 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
625 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
626 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
627 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
628 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
629 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
630 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
631 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
632 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
633 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
634 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
635 Cvar_RegisterVariable(&r_shadow_culllights_trace);
636 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
637 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
638 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
639 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
640 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
641 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
642 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
643 Cvar_RegisterVariable(&r_shadow_bouncegrid);
644 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
645 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
646 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
647 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
648 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
649 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
650 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
651 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
652 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
653 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
654 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
655 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
656 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
657 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
658 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
659 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
660 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
661 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
662 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
663 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
664 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
665 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
666 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
667 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
668 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
669 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
670 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
671 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
672 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
673 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
674 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
675 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
676 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
677 Cvar_RegisterVariable(&r_coronas);
678 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
679 Cvar_RegisterVariable(&r_coronas_occlusionquery);
680 Cvar_RegisterVariable(&gl_flashblend);
681 R_Shadow_EditLights_Init();
682 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
683 r_shadow_scenemaxlights = 0;
684 r_shadow_scenenumlights = 0;
685 r_shadow_scenelightlist = NULL;
686 maxshadowtriangles = 0;
687 shadowelements = NULL;
688 maxshadowvertices = 0;
689 shadowvertex3f = NULL;
697 shadowmarklist = NULL;
702 shadowsideslist = NULL;
703 r_shadow_buffer_numleafpvsbytes = 0;
704 r_shadow_buffer_visitingleafpvs = NULL;
705 r_shadow_buffer_leafpvs = NULL;
706 r_shadow_buffer_leaflist = NULL;
707 r_shadow_buffer_numsurfacepvsbytes = 0;
708 r_shadow_buffer_surfacepvs = NULL;
709 r_shadow_buffer_surfacelist = NULL;
710 r_shadow_buffer_surfacesides = NULL;
711 r_shadow_buffer_shadowtrispvs = NULL;
712 r_shadow_buffer_lighttrispvs = NULL;
713 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
716 matrix4x4_t matrix_attenuationxyz =
719 {0.5, 0.0, 0.0, 0.5},
720 {0.0, 0.5, 0.0, 0.5},
721 {0.0, 0.0, 0.5, 0.5},
726 matrix4x4_t matrix_attenuationz =
729 {0.0, 0.0, 0.5, 0.5},
730 {0.0, 0.0, 0.0, 0.5},
731 {0.0, 0.0, 0.0, 0.5},
736 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
738 numvertices = ((numvertices + 255) & ~255) * vertscale;
739 numtriangles = ((numtriangles + 255) & ~255) * triscale;
740 // make sure shadowelements is big enough for this volume
741 if (maxshadowtriangles < numtriangles)
743 maxshadowtriangles = numtriangles;
745 Mem_Free(shadowelements);
746 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
748 // make sure shadowvertex3f is big enough for this volume
749 if (maxshadowvertices < numvertices)
751 maxshadowvertices = numvertices;
753 Mem_Free(shadowvertex3f);
754 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
758 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
760 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
761 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
762 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
763 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
764 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
766 if (r_shadow_buffer_visitingleafpvs)
767 Mem_Free(r_shadow_buffer_visitingleafpvs);
768 if (r_shadow_buffer_leafpvs)
769 Mem_Free(r_shadow_buffer_leafpvs);
770 if (r_shadow_buffer_leaflist)
771 Mem_Free(r_shadow_buffer_leaflist);
772 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
773 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
774 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
775 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
777 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
779 if (r_shadow_buffer_surfacepvs)
780 Mem_Free(r_shadow_buffer_surfacepvs);
781 if (r_shadow_buffer_surfacelist)
782 Mem_Free(r_shadow_buffer_surfacelist);
783 if (r_shadow_buffer_surfacesides)
784 Mem_Free(r_shadow_buffer_surfacesides);
785 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
786 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
787 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
788 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
790 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
792 if (r_shadow_buffer_shadowtrispvs)
793 Mem_Free(r_shadow_buffer_shadowtrispvs);
794 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
795 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
797 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
799 if (r_shadow_buffer_lighttrispvs)
800 Mem_Free(r_shadow_buffer_lighttrispvs);
801 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
802 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
806 void R_Shadow_PrepareShadowMark(int numtris)
808 // make sure shadowmark is big enough for this volume
809 if (maxshadowmark < numtris)
811 maxshadowmark = numtris;
813 Mem_Free(shadowmark);
815 Mem_Free(shadowmarklist);
816 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
817 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
821 // if shadowmarkcount wrapped we clear the array and adjust accordingly
822 if (shadowmarkcount == 0)
825 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
830 void R_Shadow_PrepareShadowSides(int numtris)
832 if (maxshadowsides < numtris)
834 maxshadowsides = numtris;
836 Mem_Free(shadowsides);
838 Mem_Free(shadowsideslist);
839 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
840 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
845 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
847 // p1, p2, p3 are in the cubemap's local coordinate system
848 // bias = border/(size - border)
851 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
852 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
853 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
854 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
856 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
857 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
858 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
859 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
861 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
862 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
863 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
865 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
866 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
867 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
868 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
870 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
871 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
872 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
873 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
875 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
876 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
877 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
879 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
880 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
881 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
882 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
884 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
885 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
886 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
887 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
889 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
890 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
891 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
896 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
898 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
899 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
902 VectorSubtract(maxs, mins, radius);
903 VectorScale(radius, 0.5f, radius);
904 VectorAdd(mins, radius, center);
905 Matrix4x4_Transform(worldtolight, center, lightcenter);
906 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
907 VectorSubtract(lightcenter, lightradius, pmin);
908 VectorAdd(lightcenter, lightradius, pmax);
910 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
911 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
912 if(ap1 > bias*an1 && ap2 > bias*an2)
914 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
915 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
916 if(an1 > bias*ap1 && an2 > bias*ap2)
918 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
919 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
921 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
922 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
923 if(ap1 > bias*an1 && ap2 > bias*an2)
925 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
926 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
927 if(an1 > bias*ap1 && an2 > bias*ap2)
929 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
930 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
932 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
933 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
934 if(ap1 > bias*an1 && ap2 > bias*an2)
936 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
937 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
938 if(an1 > bias*ap1 && an2 > bias*ap2)
940 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
941 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
946 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
948 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
950 // p is in the cubemap's local coordinate system
951 // bias = border/(size - border)
952 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
953 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
954 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
956 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
957 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
958 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
959 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
960 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
961 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
965 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
969 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
970 float scale = (size - 2*border)/size, len;
971 float bias = border / (float)(size - border), dp, dn, ap, an;
972 // check if cone enclosing side would cross frustum plane
973 scale = 2 / (scale*scale + 2);
974 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
975 for (i = 0;i < 5;i++)
977 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
979 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
980 len = scale*VectorLength2(n);
981 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
982 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
983 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
985 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
987 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
988 len = scale*VectorLength2(n);
989 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
990 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
991 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
993 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
994 // check if frustum corners/origin cross plane sides
996 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
997 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
998 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
999 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1000 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1001 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1002 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1003 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1004 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1005 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1006 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1007 for (i = 0;i < 4;i++)
1009 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1010 VectorSubtract(n, p, n);
1011 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1012 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1013 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1014 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1015 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1016 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1017 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1018 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1019 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1022 // finite version, assumes corners are a finite distance from origin dependent on far plane
1023 for (i = 0;i < 5;i++)
1025 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1026 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1027 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1028 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1029 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1030 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1031 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1032 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1033 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1034 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1037 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1040 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)
1048 int mask, surfacemask = 0;
1049 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1051 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1052 tend = firsttriangle + numtris;
1053 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1055 // surface box entirely inside light box, no box cull
1056 if (projectdirection)
1058 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1060 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1061 TriangleNormal(v[0], v[1], v[2], normal);
1062 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1064 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1065 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1066 surfacemask |= mask;
1069 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;
1070 shadowsides[numshadowsides] = mask;
1071 shadowsideslist[numshadowsides++] = t;
1078 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1080 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1081 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1083 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1084 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1085 surfacemask |= mask;
1088 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;
1089 shadowsides[numshadowsides] = mask;
1090 shadowsideslist[numshadowsides++] = t;
1098 // surface box not entirely inside light box, cull each triangle
1099 if (projectdirection)
1101 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1103 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1104 TriangleNormal(v[0], v[1], v[2], normal);
1105 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1106 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1108 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1109 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1110 surfacemask |= mask;
1113 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;
1114 shadowsides[numshadowsides] = mask;
1115 shadowsideslist[numshadowsides++] = t;
1122 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1124 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1125 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1126 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1128 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1129 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1130 surfacemask |= mask;
1133 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;
1134 shadowsides[numshadowsides] = mask;
1135 shadowsideslist[numshadowsides++] = t;
1144 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)
1146 int i, j, outtriangles = 0;
1147 int *outelement3i[6];
1148 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1150 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1151 // make sure shadowelements is big enough for this mesh
1152 if (maxshadowtriangles < outtriangles)
1153 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1155 // compute the offset and size of the separate index lists for each cubemap side
1157 for (i = 0;i < 6;i++)
1159 outelement3i[i] = shadowelements + outtriangles * 3;
1160 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1161 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1162 outtriangles += sidetotals[i];
1165 // gather up the (sparse) triangles into separate index lists for each cubemap side
1166 for (i = 0;i < numsidetris;i++)
1168 const int *element = elements + sidetris[i] * 3;
1169 for (j = 0;j < 6;j++)
1171 if (sides[i] & (1 << j))
1173 outelement3i[j][0] = element[0];
1174 outelement3i[j][1] = element[1];
1175 outelement3i[j][2] = element[2];
1176 outelement3i[j] += 3;
1181 Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1184 static void R_Shadow_MakeTextures_MakeCorona(void)
1188 unsigned char pixels[32][32][4];
1189 for (y = 0;y < 32;y++)
1191 dy = (y - 15.5f) * (1.0f / 16.0f);
1192 for (x = 0;x < 32;x++)
1194 dx = (x - 15.5f) * (1.0f / 16.0f);
1195 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1196 a = bound(0, a, 255);
1197 pixels[y][x][0] = a;
1198 pixels[y][x][1] = a;
1199 pixels[y][x][2] = a;
1200 pixels[y][x][3] = 255;
1203 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1206 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1208 float dist = sqrt(x*x+y*y+z*z);
1209 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1210 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1211 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1214 static void R_Shadow_MakeTextures(void)
1217 float intensity, dist;
1219 R_Shadow_FreeShadowMaps();
1220 R_FreeTexturePool(&r_shadow_texturepool);
1221 r_shadow_texturepool = R_AllocTexturePool();
1222 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1223 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1224 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1225 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1226 for (x = 0;x <= ATTENTABLESIZE;x++)
1228 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1229 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1230 r_shadow_attentable[x] = bound(0, intensity, 1);
1232 // 1D gradient texture
1233 for (x = 0;x < ATTEN1DSIZE;x++)
1234 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1235 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1238 R_Shadow_MakeTextures_MakeCorona();
1240 // Editor light sprites
1241 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1258 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1259 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1276 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1277 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1294 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1295 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1312 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1313 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1330 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1331 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1348 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1351 void R_Shadow_RenderMode_Begin(void)
1358 if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1359 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1360 R_Shadow_MakeTextures();
1363 R_Mesh_ResetTextureState();
1364 GL_BlendFunc(GL_ONE, GL_ZERO);
1365 GL_DepthRange(0, 1);
1366 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1368 GL_DepthMask(false);
1369 GL_Color(0, 0, 0, 1);
1370 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1372 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1373 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1377 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1378 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1379 r_shadow_drawbuffer = drawbuffer;
1380 r_shadow_readbuffer = readbuffer;
1382 r_shadow_cullface_front = r_refdef.view.cullface_front;
1383 r_shadow_cullface_back = r_refdef.view.cullface_back;
1386 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1388 rsurface.rtlight = rtlight;
1391 void R_Shadow_RenderMode_Reset(void)
1393 R_Mesh_ResetTextureState();
1394 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1395 R_SetViewport(&r_refdef.view.viewport);
1396 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1397 GL_DepthRange(0, 1);
1399 GL_DepthMask(false);
1400 GL_DepthFunc(GL_LEQUAL);
1401 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1402 r_refdef.view.cullface_front = r_shadow_cullface_front;
1403 r_refdef.view.cullface_back = r_shadow_cullface_back;
1404 GL_CullFace(r_refdef.view.cullface_back);
1405 GL_Color(1, 1, 1, 1);
1406 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1407 GL_BlendFunc(GL_ONE, GL_ZERO);
1408 R_SetupShader_Generic_NoTexture(false, false);
1409 r_shadow_usingshadowmap2d = false;
1412 void R_Shadow_ClearStencil(void)
1414 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1415 r_refdef.stats[r_stat_lights_clears]++;
1418 static void R_Shadow_MakeVSDCT(void)
1420 // maps to a 2x3 texture rectangle with normalized coordinates
1425 // stores abs(dir.xy), offset.xy/2.5
1426 unsigned char data[4*6] =
1428 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1429 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1430 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1431 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1432 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1433 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1435 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1438 static void R_Shadow_MakeShadowMap(int texturesize)
1440 switch (r_shadow_shadowmode)
1442 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1443 if (r_shadow_shadowmap2ddepthtexture) return;
1444 if (r_fb.usedepthtextures)
1446 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);
1447 r_shadow_shadowmap2ddepthbuffer = NULL;
1448 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1452 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1453 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1454 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1462 void R_Shadow_ClearShadowMapTexture(void)
1464 r_viewport_t viewport;
1465 float clearcolor[4];
1467 // if they don't exist, create our textures now
1468 if (!r_shadow_shadowmap2ddepthtexture)
1469 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1470 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1471 R_Shadow_MakeVSDCT();
1473 // we're setting up to render shadowmaps, so change rendermode
1474 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1476 R_Mesh_ResetTextureState();
1477 R_Shadow_RenderMode_Reset();
1478 if (r_shadow_shadowmap2ddepthbuffer)
1479 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1481 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1482 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1483 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1487 // we have to set a viewport to clear anything in some renderpaths (D3D)
1488 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1489 R_SetViewport(&viewport);
1490 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1491 if (r_shadow_shadowmap2ddepthbuffer)
1492 GL_ColorMask(1, 1, 1, 1);
1494 GL_ColorMask(0, 0, 0, 0);
1495 switch (vid.renderpath)
1497 case RENDERPATH_GL32:
1498 case RENDERPATH_GLES2:
1499 GL_CullFace(r_refdef.view.cullface_back);
1502 Vector4Set(clearcolor, 1, 1, 1, 1);
1503 if (r_shadow_shadowmap2ddepthbuffer)
1504 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1506 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1509 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1511 int size = rsurface.rtlight->shadowmapatlassidesize;
1512 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1513 float farclip = 1.0f;
1514 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1515 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1516 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1517 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1518 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1519 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1520 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1521 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1522 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1523 if (r_shadow_shadowmap2ddepthbuffer)
1525 // completely different meaning than in depthtexture approach
1526 r_shadow_lightshadowmap_parameters[1] = 0;
1527 r_shadow_lightshadowmap_parameters[3] = -bias;
1531 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1533 float nearclip, farclip, bias;
1534 r_viewport_t viewport;
1536 float clearcolor[4];
1538 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1540 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1542 R_Mesh_ResetTextureState();
1543 R_Shadow_RenderMode_Reset();
1544 if (r_shadow_shadowmap2ddepthbuffer)
1545 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1547 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1548 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1549 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1554 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1556 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1558 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1559 R_SetViewport(&viewport);
1560 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1561 flipped = (side & 1) ^ (side >> 2);
1562 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1563 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1565 Vector4Set(clearcolor, 1,1,1,1);
1566 if (r_shadow_shadowmap2ddepthbuffer)
1567 GL_ColorMask(1,1,1,1);
1569 GL_ColorMask(0,0,0,0);
1570 switch(vid.renderpath)
1572 case RENDERPATH_GL32:
1573 case RENDERPATH_GLES2:
1574 GL_CullFace(r_refdef.view.cullface_back);
1578 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1579 r_shadow_shadowmapside = side;
1582 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1584 R_Mesh_ResetTextureState();
1587 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1588 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1589 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1590 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1593 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1594 R_Shadow_RenderMode_Reset();
1595 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1597 GL_DepthFunc(GL_EQUAL);
1598 // do global setup needed for the chosen lighting mode
1599 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1600 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1601 r_shadow_usingshadowmap2d = shadowmapping;
1602 r_shadow_rendermode = r_shadow_lightingrendermode;
1605 static const unsigned short bboxelements[36] =
1615 static const float bboxpoints[8][3] =
1627 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1630 float vertex3f[8*3];
1631 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1632 // do global setup needed for the chosen lighting mode
1633 R_Shadow_RenderMode_Reset();
1634 r_shadow_rendermode = r_shadow_lightingrendermode;
1635 R_EntityMatrix(&identitymatrix);
1636 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1637 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1638 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1640 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1642 r_shadow_usingshadowmap2d = shadowmapping;
1644 // render the lighting
1645 R_SetupShader_DeferredLight(rsurface.rtlight);
1646 for (i = 0;i < 8;i++)
1647 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1648 GL_ColorMask(1,1,1,1);
1649 GL_DepthMask(false);
1650 GL_DepthRange(0, 1);
1651 GL_PolygonOffset(0, 0);
1653 GL_DepthFunc(GL_GREATER);
1654 GL_CullFace(r_refdef.view.cullface_back);
1655 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1656 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1659 #define MAXBOUNCEGRIDSPLATSIZE 7
1660 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
1662 // these are temporary data per-frame, to be cache friendly the texture is
1663 // generated in slices (on Z), rendering each slice one after another and each
1664 // row in the slice one after another to be more cache friendly than randomly
1665 // seeking around a large memory space. Each slice keeps track of a linked list
1666 // of splat paths that are relevant to it. Also these are canonically flipped
1667 // to ensure that start[2] <= end[2].
1668 typedef struct r_shadow_bouncegrid_splatpath_s
1670 int nextpathonslice;
1677 vec_t splatintensity;
1678 vec_t splatsize_current;
1679 vec_t splatsize_perstep;
1681 r_shadow_bouncegrid_splatpath_t;
1683 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
1688 r_shadow_bouncegrid_splatpath_t *path;
1690 // cull paths that fail R_CullBox in dynamic mode
1691 if (!r_shadow_bouncegrid_state.settings.staticmode
1692 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
1694 vec3_t cullmins, cullmaxs;
1695 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
1696 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
1697 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
1698 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
1699 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
1700 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
1701 if (R_CullBox(cullmins, cullmaxs))
1705 // if the light path is going upward, reverse it - we always draw down.
1706 if (originalend[2] < originalstart[2])
1708 VectorCopy(originalend, start);
1709 VectorCopy(originalstart, end);
1713 VectorCopy(originalstart, start);
1714 VectorCopy(originalend, end);
1717 // transform to texture pixels
1718 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]);
1719 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]);
1720 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]);
1721 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]);
1722 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]);
1723 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]);
1725 // check if we need to grow the splatpaths array
1726 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
1728 // double the limit, this will persist from frame to frame so we don't
1729 // make the same mistake each time
1730 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
1731 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
1732 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
1733 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);
1736 VectorSubtract(originalstart, originalend, originaldir);
1737 VectorNormalize(originaldir);
1739 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
1740 VectorCopy(start, path->start);
1741 VectorCopy(end, path->end);
1742 VectorCopy(color, path->splatcolor);
1743 VectorCopy(originaldir, path->splatdir);
1744 path->splatintensity = VectorLength(color);
1747 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1749 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1756 // see if there are really any lights to render...
1757 if (enable && r_shadow_bouncegrid_static.integer)
1760 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1761 for (lightindex = 0;lightindex < range;lightindex++)
1763 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1764 if (!light || !(light->flags & flag))
1766 rtlight = &light->rtlight;
1767 // when static, we skip styled lights because they tend to change...
1768 if (rtlight->style > 0)
1770 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1771 if (!VectorLength2(lightcolor))
1781 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1783 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1784 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1785 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1786 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1788 // prevent any garbage in alignment padded areas as we'll be using memcmp
1789 memset(settings, 0, sizeof(*settings));
1791 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1792 settings->staticmode = s;
1793 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1794 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1795 settings->lightpathsize = bound(0.0f, r_shadow_bouncegrid_lightpathsize.value, 1024.0f);
1796 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
1797 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1798 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1799 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1800 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1801 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1802 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1803 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1804 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) / 65536.0f;
1805 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1806 settings->energyperphoton = 4096.0f / quality;
1807 settings->spacing[0] = spacing;
1808 settings->spacing[1] = spacing;
1809 settings->spacing[2] = spacing;
1810 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1811 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1812 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1813 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1814 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1816 // bound the values for sanity
1817 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1818 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1819 settings->maxbounce = bound(0, settings->maxbounce, 16);
1820 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1821 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1822 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1825 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1836 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1838 // get the spacing values
1839 spacing[0] = settings->spacing[0];
1840 spacing[1] = settings->spacing[1];
1841 spacing[2] = settings->spacing[2];
1842 ispacing[0] = 1.0f / spacing[0];
1843 ispacing[1] = 1.0f / spacing[1];
1844 ispacing[2] = 1.0f / spacing[2];
1846 // calculate texture size enclosing entire world bounds at the spacing
1847 if (r_refdef.scene.worldmodel)
1851 qboolean bounds_set = false;
1855 // calculate bounds enclosing world lights as they should be noticably tighter
1856 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1857 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1858 for (lightindex = 0;lightindex < range;lightindex++)
1860 const vec_t *rtlmins, *rtlmaxs;
1862 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1866 rtlight = &light->rtlight;
1867 rtlmins = rtlight->cullmins;
1868 rtlmaxs = rtlight->cullmaxs;
1872 VectorCopy(rtlmins, mins);
1873 VectorCopy(rtlmaxs, maxs);
1878 mins[0] = min(mins[0], rtlmins[0]);
1879 mins[1] = min(mins[1], rtlmins[1]);
1880 mins[2] = min(mins[2], rtlmins[2]);
1881 maxs[0] = max(maxs[0], rtlmaxs[0]);
1882 maxs[1] = max(maxs[1], rtlmaxs[1]);
1883 maxs[2] = max(maxs[2], rtlmaxs[2]);
1887 // limit to no larger than the world bounds
1888 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1889 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1890 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1891 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1892 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1893 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1895 VectorMA(mins, -2.0f, spacing, mins);
1896 VectorMA(maxs, 2.0f, spacing, maxs);
1900 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1901 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1903 VectorSubtract(maxs, mins, size);
1904 // now we can calculate the resolution we want
1905 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1906 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1907 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1908 // figure out the exact texture size (honoring power of 2 if required)
1909 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1910 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1911 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1912 size[0] = spacing[0] * resolution[0];
1913 size[1] = spacing[1] * resolution[1];
1914 size[2] = spacing[2] * resolution[2];
1916 // if dynamic we may or may not want to use the world bounds
1917 // if the dynamic size is smaller than the world bounds, use it instead
1918 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]))
1920 // we know the resolution we want
1921 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1922 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1923 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1924 // now we can calculate the texture size
1925 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1926 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1927 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1928 size[0] = spacing[0] * resolution[0];
1929 size[1] = spacing[1] * resolution[1];
1930 size[2] = spacing[2] * resolution[2];
1931 // center the rendering on the view
1932 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1933 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1934 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1937 // recalculate the maxs in case the resolution was not satisfactory
1938 VectorAdd(mins, size, maxs);
1940 // check if this changed the texture size
1941 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);
1942 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1943 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1944 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1945 VectorCopy(size, r_shadow_bouncegrid_state.size);
1946 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1947 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1948 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1950 // reallocate pixels for this update if needed...
1951 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1952 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1953 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1954 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1955 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1957 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1959 r_shadow_bouncegrid_state.highpixels = NULL;
1961 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1962 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1963 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1964 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1965 if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
1967 r_shadow_bouncegrid_state.maxsplatpaths = 0;
1968 r_shadow_bouncegrid_state.numpixels = numpixels;
1971 // update the bouncegrid matrix to put it in the world properly
1972 memset(m, 0, sizeof(m));
1973 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1974 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1975 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1976 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1977 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1978 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1980 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1983 // enumerate world rtlights and sum the overall amount of light in the world,
1984 // from that we can calculate a scaling factor to fairly distribute photons
1985 // to all the lights
1987 // this modifies rtlight->photoncolor and rtlight->photons
1988 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
1990 float normalphotonscaling;
1991 float photonscaling;
1992 float photonintensity;
1993 float photoncount = 0.0f;
1994 float lightintensity;
2000 unsigned int lightindex;
2003 normalphotonscaling = 1.0f / max(0.0000001f, settings->energyperphoton);
2004 for (lightindex = 0;lightindex < range2;lightindex++)
2006 if (lightindex < range)
2008 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2011 rtlight = &light->rtlight;
2012 VectorClear(rtlight->bouncegrid_photoncolor);
2013 rtlight->bouncegrid_photons = 0;
2014 rtlight->bouncegrid_hits = 0;
2015 rtlight->bouncegrid_traces = 0;
2016 rtlight->bouncegrid_effectiveradius = 0;
2017 if (!(light->flags & flag))
2019 if (settings->staticmode)
2021 // when static, we skip styled lights because they tend to change...
2022 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2025 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2030 rtlight = r_refdef.scene.lights[lightindex - range];
2031 VectorClear(rtlight->bouncegrid_photoncolor);
2032 rtlight->bouncegrid_photons = 0;
2033 rtlight->bouncegrid_hits = 0;
2034 rtlight->bouncegrid_traces = 0;
2035 rtlight->bouncegrid_effectiveradius = 0;
2037 // draw only visible lights (major speedup)
2038 radius = rtlight->radius * settings->lightradiusscale;
2039 cullmins[0] = rtlight->shadoworigin[0] - radius;
2040 cullmins[1] = rtlight->shadoworigin[1] - radius;
2041 cullmins[2] = rtlight->shadoworigin[2] - radius;
2042 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2043 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2044 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2045 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2046 if (!settings->staticmode)
2048 // skip if the expanded light box does not touch any visible leafs
2049 if (r_refdef.scene.worldmodel
2050 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2051 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2053 // skip if the expanded light box is not visible to traceline
2054 // note that PrepareLight already did this check but for a smaller box, so we
2055 // end up casting more traces per frame per light when using bouncegrid, which
2056 // is probably fine (and they use the same timer)
2057 if (r_shadow_culllights_trace.integer)
2059 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))
2060 rtlight->trace_timer = realtime;
2061 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2064 // skip if expanded light box is offscreen
2065 if (R_CullBox(cullmins, cullmaxs))
2067 // skip if overall light intensity is zero
2068 if (w * VectorLength2(rtlight->color) == 0.0f)
2071 // a light that does not emit any light before style is applied, can be
2072 // skipped entirely (it may just be a corona)
2073 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2075 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2076 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2077 // skip lights that will emit no photons
2078 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2080 // shoot particles from this light
2081 // use a calculation for the number of particles that will not
2082 // vary with lightstyle, otherwise we get randomized particle
2083 // distribution, the seeded random is only consistent for a
2084 // consistent number of particles on this light...
2085 s = rtlight->radius;
2086 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2087 if (lightindex >= range)
2088 lightintensity *= settings->dlightparticlemultiplier;
2089 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2090 photoncount += rtlight->bouncegrid_photons;
2091 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2092 // if the lightstyle happens to be off right now, we can skip actually
2093 // firing the photons, but we did have to count them in the total.
2094 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2095 // rtlight->bouncegrid_photons = 0;
2097 // the user provided an energyperphoton value which we try to use
2098 // if that results in too many photons to shoot this frame, then we cap it
2099 // which causes photons to appear/disappear from frame to frame, so we don't
2100 // like doing that in the typical case
2101 photonscaling = 1.0f;
2102 photonintensity = 1.0f;
2103 if (photoncount > settings->maxphotons)
2105 photonscaling = settings->maxphotons / photoncount;
2106 photonintensity = 1.0f / photonscaling;
2109 // modify the lights to reflect our computed scaling
2110 for (lightindex = 0; lightindex < range2; lightindex++)
2112 if (lightindex < range)
2114 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2117 rtlight = &light->rtlight;
2120 rtlight = r_refdef.scene.lights[lightindex - range];
2121 rtlight->bouncegrid_photons *= photonscaling;
2122 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2126 static void R_Shadow_BounceGrid_ClearPixels(void)
2128 // clear the highpixels array we'll be accumulating into
2129 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2130 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2131 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2132 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2133 r_shadow_bouncegrid_state.highpixels_index = 0;
2134 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2135 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2138 static void R_Shadow_BounceGrid_PerformSplats(void)
2140 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2141 r_shadow_bouncegrid_splatpath_t *splatpath;
2142 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2143 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2145 int xi, yi, zi; // pixel increments
2146 float xf, yf, zf; // pixel centers
2147 float splatcolor[32] = { 0 };
2148 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2149 float iradius = 1.0f / radius;
2151 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2152 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2154 // we use these a lot, so get a local copy
2155 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2157 for (pathindex = 0, splatpath = splatpaths; pathindex < numsplatpaths; pathindex++, splatpath++)
2159 splatpath->slicerange[0] = (int)floor((min(splatpath->start[2], splatpath->end[2]) - radius) * r_shadow_bouncegrid_state.ispacing[2] - 0.5f);
2160 splatpath->slicerange[1] = (int)floor((max(splatpath->start[2], splatpath->end[2]) + radius) * r_shadow_bouncegrid_state.ispacing[2] - 0.5f + 1.0f);
2163 // we keep a 1 pixel border around the whole texture to make sure that GL_CLAMP_TO_EDGE filtering doesn't create streaks if the texture is smaller than the visible scene (instead it goes black out there, which isn't ideal either)
2164 for (zi = 1, zf = (zi + 0.5f) * r_shadow_bouncegrid_state.spacing[2]; zi < resolution[2] - 1; zi++, zf += r_shadow_bouncegrid_state.spacing[2])
2166 int slicefirstpathindex = -1;
2167 for (pathindex = 0, splatpath = splatpaths; pathindex < numsplatpaths; pathindex++, splatpath++)
2169 if (zi >= splatpath->slicerange[0] && zi < splatpath->slicerange[1])
2171 if (zf < splatpath->start[2])
2172 VectorCopy(splatpath->start, splatpath->slicecenter);
2173 else if (zf > splatpath->end[2])
2174 VectorCopy(splatpath->end, splatpath->slicecenter);
2177 float lerp = (zf - splatpath->start[2]) / (splatpath->end[2] - splatpath->start[2]);
2178 splatpath->slicecenter[2] = zf;
2179 splatpath->slicecenter[0] = splatpath->start[0] + lerp * (splatpath->end[0] - splatpath->start[0]);
2180 splatpath->slicecenter[1] = splatpath->start[1] + lerp * (splatpath->end[1] - splatpath->start[1]);
2182 float distz = (splatpath->slicecenter[2] - zf) * iradius;
2183 if (distz * distz < 1.0f)
2185 splatpath->nextpathonslice = slicefirstpathindex;
2186 slicefirstpathindex = pathindex;
2190 for (yi = 1, yf = (yi + 0.5f) * r_shadow_bouncegrid_state.spacing[1]; yi < resolution[1] - 1; yi++, yf += r_shadow_bouncegrid_state.spacing[1])
2192 for (pathindex = slicefirstpathindex; pathindex >= 0; pathindex = splatpaths[pathindex].nextpathonslice)
2194 splatpath = splatpaths + pathindex;
2195 float disty = (splatpath->slicecenter[1] - yf) * iradius;
2196 float distz = (splatpath->slicecenter[2] - zf) * iradius;
2197 float distyz = disty * disty + distz * distz;
2200 int xstart = (int)floor((splatpath->slicecenter[0] - radius) * r_shadow_bouncegrid_state.ispacing[0] - 0.5f);
2201 int xend = (int)floor((splatpath->slicecenter[0] + radius) * r_shadow_bouncegrid_state.ispacing[0] - 0.5f + 1.0f);
2203 xstart = max(1, xstart);
2204 xend = min(resolution[0] - 2, xend);
2207 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2208 // accumulate average shotcolor
2209 VectorCopy(splatpath->splatdir, dir);
2210 splatcolor[0] = splatpath->splatcolor[0];
2211 splatcolor[1] = splatpath->splatcolor[1];
2212 splatcolor[2] = splatpath->splatcolor[2];
2213 splatcolor[3] = 0.0f;
2216 // store bentnormal in case the shader has a use for it,
2217 // bentnormal is an intensity-weighted average of the directions,
2218 // and will be normalized on conversion to texture pixels.
2219 splatcolor[4] = dir[0] * splatpath->splatintensity;
2220 splatcolor[5] = dir[1] * splatpath->splatintensity;
2221 splatcolor[6] = dir[2] * splatpath->splatintensity;
2222 splatcolor[7] = splatpath->splatintensity;
2223 // for each color component (R, G, B) calculate the amount that a
2224 // direction contributes
2225 splatcolor[8] = splatcolor[0] * max(0.0f, dir[0]);
2226 splatcolor[9] = splatcolor[0] * max(0.0f, dir[1]);
2227 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2228 splatcolor[11] = 0.0f;
2229 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2230 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2231 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2232 splatcolor[15] = 0.0f;
2233 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2234 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2235 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2236 splatcolor[19] = 0.0f;
2237 // and do the same for negative directions
2238 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2239 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2240 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2241 splatcolor[23] = 0.0f;
2242 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2243 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2244 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2245 splatcolor[27] = 0.0f;
2246 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2247 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2248 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2249 splatcolor[31] = 0.0f;
2251 for (xi = xstart, xf = (xi + 0.5f) * r_shadow_bouncegrid_state.spacing[0]; xi < xend; xi++, xf += r_shadow_bouncegrid_state.spacing[0])
2253 float distx = (splatpath->slicecenter[0] - xf) * iradius;
2254 float distxyz = (distx * distx + distyz);
2257 // contribute some color to this pixel, across all bands
2258 float w = 1.0f - 1.0f * sqrt(distxyz);
2260 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2264 // small optimization for alpha - only splatcolor[7] is non-zero, so skip the rest of the alpha elements.
2265 p[pixelsperband * 4 + 3] += splatcolor[7] * w;
2267 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
2269 // add to the pixel color (RGB only - see above)
2270 p[0] += splatcolor[band * 4 + 0] * w;
2271 p[1] += splatcolor[band * 4 + 1] * w;
2272 p[2] += splatcolor[band * 4 + 2] * w;
2282 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2284 const float *inpixel;
2286 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2289 unsigned int x, y, z;
2290 unsigned int resolution[3];
2291 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2292 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2294 for (z = 1;z < resolution[2]-1;z++)
2296 for (y = 1;y < resolution[1]-1;y++)
2299 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2300 inpixel = inpixels + 4*index;
2301 outpixel = outpixels + 4*index;
2302 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2304 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2305 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2306 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2307 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2314 static void R_Shadow_BounceGrid_BlurPixels(void)
2317 unsigned int resolution[3];
2319 if (!r_shadow_bouncegrid_state.settings.blur)
2322 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2324 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2325 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2326 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2327 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2330 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2332 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2334 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2336 // toggle the state, highpixels now points to pixels[3] result
2337 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2338 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2341 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2343 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2344 unsigned char *pixelsbgra8 = NULL;
2345 unsigned char *pixelbgra8;
2346 unsigned short *pixelsrgba16f = NULL;
2347 unsigned short *pixelrgba16f;
2348 float *pixelsrgba32f = NULL;
2349 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2352 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2353 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2354 unsigned int pixelband;
2355 unsigned int x, y, z;
2356 unsigned int index, bandindex;
2357 unsigned int resolution[3];
2359 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2361 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2363 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2364 r_shadow_bouncegrid_state.texture = NULL;
2367 // if bentnormals exist, we need to normalize and bias them for the shader
2371 for (z = 0;z < resolution[2]-1;z++)
2373 for (y = 0;y < resolution[1]-1;y++)
2376 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2377 highpixel = highpixels + 4*index;
2378 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2380 // only convert pixels that were hit by photons
2381 if (highpixel[3] != 0.0f)
2382 VectorNormalize(highpixel);
2383 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2384 highpixel[pixelsperband * 4 + 3] = 1.0f;
2390 // start by clearing the pixels array - we won't be writing to all of it
2392 // then process only the pixels that have at least some color, skipping
2393 // the higher bands for speed on pixels that are black
2394 switch (floatcolors)
2397 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2398 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2399 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2400 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2403 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2405 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2407 for (z = 1;z < resolution[2]-1;z++)
2409 for (y = 1;y < resolution[1]-1;y++)
2413 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2414 highpixel = highpixels + 4*index;
2415 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2417 // only convert pixels that were hit by photons
2418 if (VectorLength2(highpixel))
2420 // normalize the bentnormal now
2423 VectorNormalize(highpixel + pixelsperband * 4);
2424 highpixel[pixelsperband * 4 + 3] = 1.0f;
2426 // process all of the pixelbands for this pixel
2427 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2429 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2430 bandpixel = highpixels + 4*bandindex;
2431 c[0] = (int)(bandpixel[0]*256.0f);
2432 c[1] = (int)(bandpixel[1]*256.0f);
2433 c[2] = (int)(bandpixel[2]*256.0f);
2434 c[3] = (int)(bandpixel[3]*256.0f);
2435 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2436 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2437 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2438 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2445 if (!r_shadow_bouncegrid_state.createtexture)
2446 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2448 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);
2451 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2452 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2453 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2454 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2455 for (z = 1;z < resolution[2]-1;z++)
2457 for (y = 1;y < resolution[1]-1;y++)
2461 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2462 highpixel = highpixels + 4*index;
2463 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2465 // only convert pixels that were hit by photons
2466 if (VectorLength2(highpixel))
2468 // process all of the pixelbands for this pixel
2469 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2471 // time to have fun with IEEE 754 bit hacking...
2474 unsigned int raw[4];
2476 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2477 bandpixel = highpixels + 4*bandindex;
2478 VectorCopy4(bandpixel, u.f);
2479 VectorCopy4(u.raw, c);
2480 // this math supports negative numbers, snaps denormals to zero
2481 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2482 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2483 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2484 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2485 // this math does not support negative
2486 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2487 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2488 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2489 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2496 if (!r_shadow_bouncegrid_state.createtexture)
2497 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2499 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, (const unsigned char *)pixelsrgba16f, TEXTYPE_COLORBUFFER16F, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2502 // our native format happens to match, so this is easy.
2503 pixelsrgba32f = highpixels;
2505 if (!r_shadow_bouncegrid_state.createtexture)
2506 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2508 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);
2512 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2515 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2517 vec3_t bouncerandom[10];
2520 int hitsupercontentsmask;
2521 int skipsupercontentsmask;
2522 int skipmaterialflagsmask;
2526 float bounceminimumintensity2;
2528 //trace_t cliptrace2;
2529 //trace_t cliptrace3;
2530 unsigned int lightindex;
2532 randomseed_t randomseed;
2534 vec3_t baseshotcolor;
2540 vec_t distancetraveled;
2544 // compute a seed for the unstable random modes
2545 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2546 seed = realtime * 1000.0;
2548 r_shadow_bouncegrid_state.numsplatpaths = 0;
2550 // figure out what we want to interact with
2551 if (settings.hitmodels)
2552 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2554 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2555 skipsupercontentsmask = 0;
2556 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
2557 maxbounce = settings.maxbounce;
2559 for (lightindex = 0;lightindex < range2;lightindex++)
2561 if (lightindex < range)
2563 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2566 rtlight = &light->rtlight;
2569 rtlight = r_refdef.scene.lights[lightindex - range];
2570 // note that this code used to keep track of residual photons and
2571 // distribute them evenly to achieve exactly a desired photon count,
2572 // but that caused unwanted flickering in dynamic mode
2573 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2574 // skip if we won't be shooting any photons
2575 if (!shootparticles)
2577 radius = rtlight->radius * settings.lightradiusscale;
2578 //s = settings.particleintensity / shootparticles;
2579 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2580 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2581 if (VectorLength2(baseshotcolor) <= 0.0f)
2583 r_refdef.stats[r_stat_bouncegrid_lights]++;
2584 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2585 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2586 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
2588 // for seeded random we start the RNG with the position of the light
2589 if (settings.rng_seed >= 0)
2597 u.f[0] = rtlight->shadoworigin[0];
2598 u.f[1] = rtlight->shadoworigin[1];
2599 u.f[2] = rtlight->shadoworigin[2];
2601 switch (settings.rng_type)
2605 // we have to shift the seed provided by the user because the result must be odd
2606 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
2609 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
2614 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2616 VectorCopy(baseshotcolor, shotcolor);
2617 VectorCopy(rtlight->shadoworigin, clipstart);
2618 switch (settings.rng_type)
2622 VectorLehmerRandom(&randomseed, clipend);
2623 if (settings.bounceanglediffuse)
2625 // we want random to be stable, so we still have to do all the random we would have done
2626 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2627 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
2631 VectorCheeseRandom(seed, clipend);
2632 if (settings.bounceanglediffuse)
2634 // we want random to be stable, so we still have to do all the random we would have done
2635 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
2636 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
2641 // we want a uniform distribution spherically, not merely within the sphere
2642 if (settings.normalizevectors)
2643 VectorNormalize(clipend);
2645 VectorMA(clipstart, radius, clipend, clipend);
2646 distancetraveled = 0.0f;
2647 for (bouncecount = 0;;bouncecount++)
2649 r_refdef.stats[r_stat_bouncegrid_traces]++;
2650 rtlight->bouncegrid_traces++;
2651 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2652 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2653 if (settings.staticmode || settings.rng_seed < 0)
2655 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2656 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2657 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);
2661 // dynamic mode fires many rays and most will match the cache from the previous frame
2662 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
2664 if (bouncecount > 0 || settings.includedirectlighting)
2667 VectorCopy(cliptrace.endpos, hitpos);
2668 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
2670 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
2671 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
2672 if (rtlight->bouncegrid_effectiveradius < s)
2673 rtlight->bouncegrid_effectiveradius = s;
2674 if (cliptrace.fraction >= 1.0f)
2676 r_refdef.stats[r_stat_bouncegrid_hits]++;
2677 rtlight->bouncegrid_hits++;
2678 if (bouncecount >= maxbounce)
2680 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2681 // also clamp the resulting color to never add energy, even if the user requests extreme values
2682 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2683 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2685 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2686 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2687 surfcolor[0] = min(surfcolor[0], 1.0f);
2688 surfcolor[1] = min(surfcolor[1], 1.0f);
2689 surfcolor[2] = min(surfcolor[2], 1.0f);
2690 VectorMultiply(shotcolor, surfcolor, shotcolor);
2691 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
2693 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2694 if (settings.bounceanglediffuse)
2696 // random direction, primarily along plane normal
2697 s = VectorDistance(cliptrace.endpos, clipend);
2698 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
2699 VectorNormalize(clipend);
2700 VectorScale(clipend, s, clipend);
2704 // reflect the remaining portion of the line across plane normal
2705 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2706 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2708 // calculate the new line start and end
2709 VectorCopy(cliptrace.endpos, clipstart);
2710 VectorAdd(clipstart, clipend, clipend);
2716 void R_Shadow_UpdateBounceGridTexture(void)
2718 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2719 r_shadow_bouncegrid_settings_t settings;
2720 qboolean enable = false;
2721 qboolean settingschanged;
2722 unsigned int range; // number of world lights
2723 unsigned int range1; // number of dynamic lights (or zero if disabled)
2724 unsigned int range2; // range+range1
2726 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2728 R_Shadow_BounceGrid_GenerateSettings(&settings);
2730 // changing intensity does not require an update
2731 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2733 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2735 // when settings change, we free everything as it is just simpler that way.
2736 if (settingschanged || !enable)
2738 // not enabled, make sure we free anything we don't need anymore.
2739 if (r_shadow_bouncegrid_state.texture)
2741 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2742 r_shadow_bouncegrid_state.texture = NULL;
2744 r_shadow_bouncegrid_state.highpixels = NULL;
2745 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2746 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2747 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2748 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2749 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2750 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2751 r_shadow_bouncegrid_state.numpixels = 0;
2752 r_shadow_bouncegrid_state.directional = false;
2758 // if all the settings seem identical to the previous update, return
2759 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2762 // store the new settings
2763 r_shadow_bouncegrid_state.settings = settings;
2765 R_Shadow_BounceGrid_UpdateSpacing();
2767 // get the range of light numbers we'll be looping over:
2768 // range = static lights
2769 // range1 = dynamic lights (optional)
2770 // range2 = range + range1
2771 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2772 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2773 range2 = range + range1;
2775 // calculate weighting factors for distributing photons among the lights
2776 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
2777 R_TimeReport("bg_assignphotons");
2779 // trace the photons from lights and accumulate illumination
2780 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
2781 R_TimeReport("bg_tracephotons");
2783 // clear the texture
2784 R_Shadow_BounceGrid_ClearPixels();
2785 R_TimeReport("bg_cleartex");
2787 // accumulate the light splatting into texture
2788 R_Shadow_BounceGrid_PerformSplats();
2789 R_TimeReport("bg_lighttex");
2791 // apply a mild blur filter to the texture
2792 R_Shadow_BounceGrid_BlurPixels();
2793 R_TimeReport("bg_blurtex");
2795 // convert the pixels to lower precision and upload the texture
2796 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2797 R_TimeReport("bg_uploadtex");
2799 // after we compute the static lighting we don't need to keep the highpixels array around
2800 if (settings.staticmode)
2802 r_shadow_bouncegrid_state.highpixels = NULL;
2803 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2804 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2805 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2806 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2807 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2808 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2812 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2814 R_Shadow_RenderMode_Reset();
2815 GL_BlendFunc(GL_ONE, GL_ONE);
2816 GL_DepthRange(0, 1);
2817 GL_DepthTest(r_showlighting.integer < 2);
2818 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2820 GL_DepthFunc(GL_EQUAL);
2821 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2824 void R_Shadow_RenderMode_End(void)
2826 R_Shadow_RenderMode_Reset();
2827 R_Shadow_RenderMode_ActiveLight(NULL);
2829 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2830 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2833 int bboxedges[12][2] =
2852 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2854 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2856 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2857 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2858 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2859 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2862 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2863 return true; // invisible
2864 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2865 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2866 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2867 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2868 r_refdef.stats[r_stat_lights_scissored]++;
2872 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2874 // used to display how many times a surface is lit for level design purposes
2875 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2876 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2880 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])
2882 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2883 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2887 extern cvar_t gl_lightmaps;
2888 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2891 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2892 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2893 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2894 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2895 if (!r_shadow_usenormalmap.integer)
2897 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2898 VectorClear(diffusecolor);
2899 VectorClear(specularcolor);
2901 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2902 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2903 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2904 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2906 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2909 VectorNegate(ambientcolor, ambientcolor);
2910 VectorNegate(diffusecolor, diffusecolor);
2911 VectorNegate(specularcolor, specularcolor);
2912 GL_BlendEquationSubtract(true);
2914 RSurf_SetupDepthAndCulling();
2915 switch (r_shadow_rendermode)
2917 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2918 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2919 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2921 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2922 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2925 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2929 GL_BlendEquationSubtract(false);
2932 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)
2934 matrix4x4_t tempmatrix = *matrix;
2935 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2937 // if this light has been compiled before, free the associated data
2938 R_RTLight_Uncompile(rtlight);
2940 // clear it completely to avoid any lingering data
2941 memset(rtlight, 0, sizeof(*rtlight));
2943 // copy the properties
2944 rtlight->matrix_lighttoworld = tempmatrix;
2945 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2946 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2947 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2948 VectorCopy(color, rtlight->color);
2949 rtlight->cubemapname[0] = 0;
2950 if (cubemapname && cubemapname[0])
2951 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2952 rtlight->shadow = shadow;
2953 rtlight->corona = corona;
2954 rtlight->style = style;
2955 rtlight->isstatic = isstatic;
2956 rtlight->coronasizescale = coronasizescale;
2957 rtlight->ambientscale = ambientscale;
2958 rtlight->diffusescale = diffusescale;
2959 rtlight->specularscale = specularscale;
2960 rtlight->flags = flags;
2962 // compute derived data
2963 //rtlight->cullradius = rtlight->radius;
2964 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2965 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2966 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2967 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2968 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2969 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2970 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2973 // compiles rtlight geometry
2974 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2975 void R_RTLight_Compile(rtlight_t *rtlight)
2978 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2979 int lighttris, shadowtris;
2980 entity_render_t *ent = r_refdef.scene.worldentity;
2981 dp_model_t *model = r_refdef.scene.worldmodel;
2982 unsigned char *data;
2984 // compile the light
2985 rtlight->compiled = true;
2986 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2987 rtlight->static_numleafs = 0;
2988 rtlight->static_numleafpvsbytes = 0;
2989 rtlight->static_leaflist = NULL;
2990 rtlight->static_leafpvs = NULL;
2991 rtlight->static_numsurfaces = 0;
2992 rtlight->static_surfacelist = NULL;
2993 rtlight->static_shadowmap_receivers = 0x3F;
2994 rtlight->static_shadowmap_casters = 0x3F;
2995 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2996 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2997 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2998 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2999 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3000 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3002 if (model && model->GetLightInfo)
3004 // this variable must be set for the CompileShadowMap code
3005 r_shadow_compilingrtlight = rtlight;
3006 R_FrameData_SetMark();
3007 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);
3008 R_FrameData_ReturnToMark();
3009 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3010 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3011 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3012 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3013 rtlight->static_numsurfaces = numsurfaces;
3014 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3015 rtlight->static_numleafs = numleafs;
3016 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3017 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3018 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3019 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3020 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3021 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3022 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3023 if (rtlight->static_numsurfaces)
3024 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3025 if (rtlight->static_numleafs)
3026 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3027 if (rtlight->static_numleafpvsbytes)
3028 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3029 if (rtlight->static_numshadowtrispvsbytes)
3030 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3031 if (rtlight->static_numlighttrispvsbytes)
3032 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3033 R_FrameData_SetMark();
3034 if (model->CompileShadowMap && rtlight->shadow)
3035 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3036 R_FrameData_ReturnToMark();
3037 // now we're done compiling the rtlight
3038 r_shadow_compilingrtlight = NULL;
3042 // use smallest available cullradius - box radius or light radius
3043 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3044 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3047 if (rtlight->static_numlighttrispvsbytes)
3048 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3049 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3053 if (rtlight->static_numshadowtrispvsbytes)
3054 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3055 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3058 if (developer_extra.integer)
3059 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);
3062 void R_RTLight_Uncompile(rtlight_t *rtlight)
3064 if (rtlight->compiled)
3066 if (rtlight->static_meshchain_shadow_shadowmap)
3067 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3068 rtlight->static_meshchain_shadow_shadowmap = NULL;
3069 // these allocations are grouped
3070 if (rtlight->static_surfacelist)
3071 Mem_Free(rtlight->static_surfacelist);
3072 rtlight->static_numleafs = 0;
3073 rtlight->static_numleafpvsbytes = 0;
3074 rtlight->static_leaflist = NULL;
3075 rtlight->static_leafpvs = NULL;
3076 rtlight->static_numsurfaces = 0;
3077 rtlight->static_surfacelist = NULL;
3078 rtlight->static_numshadowtrispvsbytes = 0;
3079 rtlight->static_shadowtrispvs = NULL;
3080 rtlight->static_numlighttrispvsbytes = 0;
3081 rtlight->static_lighttrispvs = NULL;
3082 rtlight->compiled = false;
3086 void R_Shadow_UncompileWorldLights(void)
3090 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3091 for (lightindex = 0;lightindex < range;lightindex++)
3093 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3096 R_RTLight_Uncompile(&light->rtlight);
3100 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3104 // reset the count of frustum planes
3105 // see rtlight->cached_frustumplanes definition for how much this array
3107 rtlight->cached_numfrustumplanes = 0;
3109 if (r_trippy.integer)
3112 // haven't implemented a culling path for ortho rendering
3113 if (!r_refdef.view.useperspective)
3115 // check if the light is on screen and copy the 4 planes if it is
3116 for (i = 0;i < 4;i++)
3117 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3120 for (i = 0;i < 4;i++)
3121 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3126 // generate a deformed frustum that includes the light origin, this is
3127 // used to cull shadow casting surfaces that can not possibly cast a
3128 // shadow onto the visible light-receiving surfaces, which can be a
3131 // if the light origin is onscreen the result will be 4 planes exactly
3132 // if the light origin is offscreen on only one axis the result will
3133 // be exactly 5 planes (split-side case)
3134 // if the light origin is offscreen on two axes the result will be
3135 // exactly 4 planes (stretched corner case)
3136 for (i = 0;i < 4;i++)
3138 // quickly reject standard frustum planes that put the light
3139 // origin outside the frustum
3140 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3143 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3145 // if all the standard frustum planes were accepted, the light is onscreen
3146 // otherwise we need to generate some more planes below...
3147 if (rtlight->cached_numfrustumplanes < 4)
3149 // at least one of the stock frustum planes failed, so we need to
3150 // create one or two custom planes to enclose the light origin
3151 for (i = 0;i < 4;i++)
3153 // create a plane using the view origin and light origin, and a
3154 // single point from the frustum corner set
3155 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3156 VectorNormalize(plane.normal);
3157 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3158 // see if this plane is backwards and flip it if so
3159 for (j = 0;j < 4;j++)
3160 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3164 VectorNegate(plane.normal, plane.normal);
3166 // flipped plane, test again to see if it is now valid
3167 for (j = 0;j < 4;j++)
3168 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3170 // if the plane is still not valid, then it is dividing the
3171 // frustum and has to be rejected
3175 // we have created a valid plane, compute extra info
3176 PlaneClassify(&plane);
3178 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3180 // if we've found 5 frustum planes then we have constructed a
3181 // proper split-side case and do not need to keep searching for
3182 // planes to enclose the light origin
3183 if (rtlight->cached_numfrustumplanes == 5)
3191 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3193 plane = rtlight->cached_frustumplanes[i];
3194 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));
3199 // now add the light-space box planes if the light box is rotated, as any
3200 // caster outside the oriented light box is irrelevant (even if it passed
3201 // the worldspace light box, which is axial)
3202 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3204 for (i = 0;i < 6;i++)
3208 v[i >> 1] = (i & 1) ? -1 : 1;
3209 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3210 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3211 plane.dist = VectorNormalizeLength(plane.normal);
3212 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3213 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3219 // add the world-space reduced box planes
3220 for (i = 0;i < 6;i++)
3222 VectorClear(plane.normal);
3223 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3224 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3225 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3234 // reduce all plane distances to tightly fit the rtlight cull box, which
3236 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3237 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3238 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3239 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3240 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3241 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3242 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3243 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3244 oldnum = rtlight->cached_numfrustumplanes;
3245 rtlight->cached_numfrustumplanes = 0;
3246 for (j = 0;j < oldnum;j++)
3248 // find the nearest point on the box to this plane
3249 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3250 for (i = 1;i < 8;i++)
3252 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3253 if (bestdist > dist)
3256 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);
3257 // if the nearest point is near or behind the plane, we want this
3258 // plane, otherwise the plane is useless as it won't cull anything
3259 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3261 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3262 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3269 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3271 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3273 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3275 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3276 if (mesh->sidetotals[r_shadow_shadowmapside])
3279 GL_CullFace(GL_NONE);
3280 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3281 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3282 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);
3286 else if (r_refdef.scene.worldentity->model)
3287 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);
3289 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3292 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3294 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3295 vec_t relativeshadowradius;
3296 RSurf_ActiveModelEntity(ent, false, false, false);
3297 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3298 // we need to re-init the shader for each entity because the matrix changed
3299 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3300 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3301 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3302 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3303 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3304 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3305 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3306 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3307 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3310 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3312 // set up properties for rendering light onto this entity
3313 RSurf_ActiveModelEntity(ent, true, true, false);
3314 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3315 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3316 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3317 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3320 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3322 if (!r_refdef.scene.worldmodel->DrawLight)
3325 // set up properties for rendering light onto this entity
3326 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3327 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3328 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3329 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3330 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3332 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3334 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3337 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3339 dp_model_t *model = ent->model;
3340 if (!model->DrawLight)
3343 R_Shadow_SetupEntityLight(ent);
3345 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3347 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3350 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3354 int numleafs, numsurfaces;
3355 int *leaflist, *surfacelist;
3356 unsigned char *leafpvs;
3357 unsigned char *shadowtrispvs;
3358 unsigned char *lighttrispvs;
3359 //unsigned char *surfacesides;
3360 int numlightentities;
3361 int numlightentities_noselfshadow;
3362 int numshadowentities;
3363 int numshadowentities_noselfshadow;
3364 // FIXME: bounds check lightentities and shadowentities, etc.
3365 static entity_render_t *lightentities[MAX_EDICTS];
3366 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3367 static entity_render_t *shadowentities[MAX_EDICTS];
3368 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3370 qboolean castshadows;
3372 rtlight->draw = false;
3373 rtlight->cached_numlightentities = 0;
3374 rtlight->cached_numlightentities_noselfshadow = 0;
3375 rtlight->cached_numshadowentities = 0;
3376 rtlight->cached_numshadowentities_noselfshadow = 0;
3377 rtlight->cached_numsurfaces = 0;
3378 rtlight->cached_lightentities = NULL;
3379 rtlight->cached_lightentities_noselfshadow = NULL;
3380 rtlight->cached_shadowentities = NULL;
3381 rtlight->cached_shadowentities_noselfshadow = NULL;
3382 rtlight->cached_shadowtrispvs = NULL;
3383 rtlight->cached_lighttrispvs = NULL;
3384 rtlight->cached_surfacelist = NULL;
3385 rtlight->shadowmapsidesize = 0;
3387 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3388 // skip lights that are basically invisible (color 0 0 0)
3389 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3391 // loading is done before visibility checks because loading should happen
3392 // all at once at the start of a level, not when it stalls gameplay.
3393 // (especially important to benchmarks)
3395 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3397 if (rtlight->compiled)
3398 R_RTLight_Uncompile(rtlight);
3399 R_RTLight_Compile(rtlight);
3403 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3405 // look up the light style value at this time
3406 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3407 VectorScale(rtlight->color, f, rtlight->currentcolor);
3409 if (rtlight->selected)
3411 f = 2 + sin(realtime * M_PI * 4.0);
3412 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3416 // skip if lightstyle is currently off
3417 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3420 // skip processing on corona-only lights
3424 // skip if the light box is not touching any visible leafs
3425 if (r_shadow_culllights_pvs.integer
3426 && r_refdef.scene.worldmodel
3427 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3428 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3431 // skip if the light box is not visible to traceline
3432 if (r_shadow_culllights_trace.integer)
3434 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))
3435 rtlight->trace_timer = realtime;
3436 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3440 // skip if the light box is off screen
3441 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3444 // in the typical case this will be quickly replaced by GetLightInfo
3445 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3446 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3448 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3450 // 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
3451 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3454 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3456 // compiled light, world available and can receive realtime lighting
3457 // retrieve leaf information
3458 numleafs = rtlight->static_numleafs;
3459 leaflist = rtlight->static_leaflist;
3460 leafpvs = rtlight->static_leafpvs;
3461 numsurfaces = rtlight->static_numsurfaces;
3462 surfacelist = rtlight->static_surfacelist;
3463 //surfacesides = NULL;
3464 shadowtrispvs = rtlight->static_shadowtrispvs;
3465 lighttrispvs = rtlight->static_lighttrispvs;
3467 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3469 // dynamic light, world available and can receive realtime lighting
3470 // calculate lit surfaces and leafs
3471 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);
3472 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3473 leaflist = r_shadow_buffer_leaflist;
3474 leafpvs = r_shadow_buffer_leafpvs;
3475 surfacelist = r_shadow_buffer_surfacelist;
3476 //surfacesides = r_shadow_buffer_surfacesides;
3477 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3478 lighttrispvs = r_shadow_buffer_lighttrispvs;
3479 // if the reduced leaf bounds are offscreen, skip it
3480 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3491 //surfacesides = NULL;
3492 shadowtrispvs = NULL;
3493 lighttrispvs = NULL;
3495 // check if light is illuminating any visible leafs
3498 for (i = 0; i < numleafs; i++)
3499 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3505 // make a list of lit entities and shadow casting entities
3506 numlightentities = 0;
3507 numlightentities_noselfshadow = 0;
3508 numshadowentities = 0;
3509 numshadowentities_noselfshadow = 0;
3511 // add dynamic entities that are lit by the light
3512 for (i = 0; i < r_refdef.scene.numentities; i++)
3515 entity_render_t *ent = r_refdef.scene.entities[i];
3517 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3519 // skip the object entirely if it is not within the valid
3520 // shadow-casting region (which includes the lit region)
3521 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3523 if (!(model = ent->model))
3525 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3527 // this entity wants to receive light, is visible, and is
3528 // inside the light box
3529 // TODO: check if the surfaces in the model can receive light
3530 // so now check if it's in a leaf seen by the light
3531 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))
3533 if (ent->flags & RENDER_NOSELFSHADOW)
3534 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3536 lightentities[numlightentities++] = ent;
3537 // since it is lit, it probably also casts a shadow...
3538 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3539 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3540 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3542 // note: exterior models without the RENDER_NOSELFSHADOW
3543 // flag still create a RENDER_NOSELFSHADOW shadow but
3544 // are lit normally, this means that they are
3545 // self-shadowing but do not shadow other
3546 // RENDER_NOSELFSHADOW entities such as the gun
3547 // (very weird, but keeps the player shadow off the gun)
3548 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3549 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3551 shadowentities[numshadowentities++] = ent;
3554 else if (ent->flags & RENDER_SHADOW)
3556 // this entity is not receiving light, but may still need to
3558 // TODO: check if the surfaces in the model can cast shadow
3559 // now check if it is in a leaf seen by the light
3560 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))
3562 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3563 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3564 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3566 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3567 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3569 shadowentities[numshadowentities++] = ent;
3574 // return if there's nothing at all to light
3575 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3578 // count this light in the r_speeds
3579 r_refdef.stats[r_stat_lights]++;
3581 // flag it as worth drawing later
3582 rtlight->draw = true;
3584 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3585 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3587 numshadowentities = numshadowentities_noselfshadow = 0;
3588 rtlight->castshadows = castshadows;
3590 // cache all the animated entities that cast a shadow but are not visible
3591 for (i = 0; i < numshadowentities; i++)
3592 R_AnimCache_GetEntity(shadowentities[i], false, false);
3593 for (i = 0; i < numshadowentities_noselfshadow; i++)
3594 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3596 // 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)
3597 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3599 for (i = 0; i < numshadowentities_noselfshadow; i++)
3600 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3601 numshadowentities_noselfshadow = 0;
3604 // we can convert noselfshadow to regular if there are no casters of that type
3605 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3607 for (i = 0; i < numlightentities_noselfshadow; i++)
3608 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3609 numlightentities_noselfshadow = 0;
3612 // allocate some temporary memory for rendering this light later in the frame
3613 // reusable buffers need to be copied, static data can be used as-is
3614 rtlight->cached_numlightentities = numlightentities;
3615 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3616 rtlight->cached_numshadowentities = numshadowentities;
3617 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3618 rtlight->cached_numsurfaces = numsurfaces;
3619 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3620 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3621 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3622 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3623 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3625 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3626 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3627 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3628 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3629 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3633 // compiled light data
3634 rtlight->cached_shadowtrispvs = shadowtrispvs;
3635 rtlight->cached_lighttrispvs = lighttrispvs;
3636 rtlight->cached_surfacelist = surfacelist;
3639 if (R_Shadow_ShadowMappingEnabled())
3641 // figure out the shadowmapping parameters for this light
3642 vec3_t nearestpoint;
3645 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3646 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3647 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3648 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3649 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3650 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3651 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3652 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3653 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3657 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3661 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3662 int numlightentities;
3663 int numlightentities_noselfshadow;
3664 int numshadowentities;
3665 int numshadowentities_noselfshadow;
3666 entity_render_t **lightentities;
3667 entity_render_t **lightentities_noselfshadow;
3668 entity_render_t **shadowentities;
3669 entity_render_t **shadowentities_noselfshadow;
3671 static unsigned char entitysides[MAX_EDICTS];
3672 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3678 matrix4x4_t radiustolight;
3680 // check if we cached this light this frame (meaning it is worth drawing)
3681 if (!rtlight->draw || !rtlight->castshadows)
3684 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3685 if (rtlight->shadowmapatlassidesize == 0)
3687 rtlight->castshadows = false;
3691 // set up a scissor rectangle for this light
3692 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3695 // don't let sound skip if going slow
3696 if (r_refdef.scene.extraupdate)
3699 numlightentities = rtlight->cached_numlightentities;
3700 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3701 numshadowentities = rtlight->cached_numshadowentities;
3702 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3703 numsurfaces = rtlight->cached_numsurfaces;
3704 lightentities = rtlight->cached_lightentities;
3705 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3706 shadowentities = rtlight->cached_shadowentities;
3707 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3708 shadowtrispvs = rtlight->cached_shadowtrispvs;
3709 lighttrispvs = rtlight->cached_lighttrispvs;
3710 surfacelist = rtlight->cached_surfacelist;
3712 // make this the active rtlight for rendering purposes
3713 R_Shadow_RenderMode_ActiveLight(rtlight);
3715 radiustolight = rtlight->matrix_worldtolight;
3716 Matrix4x4_Abs(&radiustolight);
3718 size = rtlight->shadowmapatlassidesize;
3719 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3721 surfacesides = NULL;
3726 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3728 castermask = rtlight->static_shadowmap_casters;
3729 receivermask = rtlight->static_shadowmap_receivers;
3733 surfacesides = r_shadow_buffer_surfacesides;
3734 for (i = 0; i < numsurfaces; i++)
3736 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3737 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3738 castermask |= surfacesides[i];
3739 receivermask |= surfacesides[i];
3744 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3745 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3746 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3747 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3749 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3753 for (i = 0; i < numshadowentities; i++)
3754 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3755 for (i = 0; i < numshadowentities_noselfshadow; i++)
3756 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3759 // there is no need to render shadows for sides that have no receivers...
3760 castermask &= receivermask;
3762 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3764 // render shadow casters into shadowmaps for this light
3765 for (side = 0; side < 6; side++)
3767 int bit = 1 << side;
3768 if (castermask & bit)
3770 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3772 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3773 for (i = 0; i < numshadowentities; i++)
3774 if (entitysides[i] & bit)
3775 R_Shadow_DrawEntityShadow(shadowentities[i]);
3776 for (i = 0; i < numshadowentities_noselfshadow; i++)
3777 if (entitysides_noselfshadow[i] & bit)
3778 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3781 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3782 if (numshadowentities_noselfshadow)
3784 for (side = 0; side < 6; side++)
3786 int bit = 1 << side;
3787 if (castermask & bit)
3789 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3791 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3792 for (i = 0; i < numshadowentities; i++)
3793 if (entitysides[i] & bit)
3794 R_Shadow_DrawEntityShadow(shadowentities[i]);
3800 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3804 unsigned char *shadowtrispvs, *lighttrispvs;
3805 int numlightentities;
3806 int numlightentities_noselfshadow;
3807 int numshadowentities;
3808 int numshadowentities_noselfshadow;
3809 entity_render_t **lightentities;
3810 entity_render_t **lightentities_noselfshadow;
3811 entity_render_t **shadowentities;
3812 entity_render_t **shadowentities_noselfshadow;
3814 qboolean castshadows;
3816 // check if we cached this light this frame (meaning it is worth drawing)
3820 // set up a scissor rectangle for this light
3821 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3824 // don't let sound skip if going slow
3825 if (r_refdef.scene.extraupdate)
3828 numlightentities = rtlight->cached_numlightentities;
3829 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3830 numshadowentities = rtlight->cached_numshadowentities;
3831 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3832 numsurfaces = rtlight->cached_numsurfaces;
3833 lightentities = rtlight->cached_lightentities;
3834 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3835 shadowentities = rtlight->cached_shadowentities;
3836 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3837 shadowtrispvs = rtlight->cached_shadowtrispvs;
3838 lighttrispvs = rtlight->cached_lighttrispvs;
3839 surfacelist = rtlight->cached_surfacelist;
3840 castshadows = rtlight->castshadows;
3842 // make this the active rtlight for rendering purposes
3843 R_Shadow_RenderMode_ActiveLight(rtlight);
3845 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3847 // optionally draw the illuminated areas
3848 // for performance analysis by level designers
3849 R_Shadow_RenderMode_VisibleLighting(false);
3851 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3852 for (i = 0;i < numlightentities;i++)
3853 R_Shadow_DrawEntityLight(lightentities[i]);
3854 for (i = 0;i < numlightentities_noselfshadow;i++)
3855 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3858 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3862 float shadowmapoffsetnoselfshadow = 0;
3863 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3864 Matrix4x4_Abs(&radiustolight);
3866 size = rtlight->shadowmapatlassidesize;
3867 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3869 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3871 if (rtlight->cached_numshadowentities_noselfshadow)
3872 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3874 // render lighting using the depth texture as shadowmap
3875 // draw lighting in the unmasked areas
3876 if (numsurfaces + numlightentities)
3878 R_Shadow_RenderMode_Lighting(false, true, false);
3879 // draw lighting in the unmasked areas
3881 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3882 for (i = 0; i < numlightentities; i++)
3883 R_Shadow_DrawEntityLight(lightentities[i]);
3885 // offset to the noselfshadow part of the atlas and draw those too
3886 if (numlightentities_noselfshadow)
3888 R_Shadow_RenderMode_Lighting(false, true, true);
3889 for (i = 0; i < numlightentities_noselfshadow; i++)
3890 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3893 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3894 if (r_shadow_usingdeferredprepass)
3895 R_Shadow_RenderMode_DrawDeferredLight(true);
3899 // draw lighting in the unmasked areas
3900 R_Shadow_RenderMode_Lighting(false, false, false);
3902 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3903 for (i = 0;i < numlightentities;i++)
3904 R_Shadow_DrawEntityLight(lightentities[i]);
3905 for (i = 0;i < numlightentities_noselfshadow;i++)
3906 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3908 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3909 if (r_shadow_usingdeferredprepass)
3910 R_Shadow_RenderMode_DrawDeferredLight(false);
3914 static void R_Shadow_FreeDeferred(void)
3916 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3917 r_shadow_prepassgeometryfbo = 0;
3919 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3920 r_shadow_prepasslightingdiffusespecularfbo = 0;
3922 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3923 r_shadow_prepasslightingdiffusefbo = 0;
3925 if (r_shadow_prepassgeometrydepthbuffer)
3926 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3927 r_shadow_prepassgeometrydepthbuffer = NULL;
3929 if (r_shadow_prepassgeometrynormalmaptexture)
3930 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3931 r_shadow_prepassgeometrynormalmaptexture = NULL;
3933 if (r_shadow_prepasslightingdiffusetexture)
3934 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3935 r_shadow_prepasslightingdiffusetexture = NULL;
3937 if (r_shadow_prepasslightingspeculartexture)
3938 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3939 r_shadow_prepasslightingspeculartexture = NULL;
3942 void R_Shadow_DrawPrepass(void)
3946 entity_render_t *ent;
3947 float clearcolor[4];
3949 R_Mesh_ResetTextureState();
3951 GL_ColorMask(1,1,1,1);
3952 GL_BlendFunc(GL_ONE, GL_ZERO);
3955 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3956 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3957 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3958 if (r_timereport_active)
3959 R_TimeReport("prepasscleargeom");
3961 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3962 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3963 if (r_timereport_active)
3964 R_TimeReport("prepassworld");
3966 for (i = 0;i < r_refdef.scene.numentities;i++)
3968 if (!r_refdef.viewcache.entityvisible[i])
3970 ent = r_refdef.scene.entities[i];
3971 if (ent->model && ent->model->DrawPrepass != NULL)
3972 ent->model->DrawPrepass(ent);
3975 if (r_timereport_active)
3976 R_TimeReport("prepassmodels");
3978 GL_DepthMask(false);
3979 GL_ColorMask(1,1,1,1);
3982 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3983 Vector4Set(clearcolor, 0, 0, 0, 0);
3984 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3985 if (r_timereport_active)
3986 R_TimeReport("prepassclearlit");
3988 R_Shadow_RenderMode_Begin();
3990 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
3991 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
3993 R_Shadow_RenderMode_End();
3995 if (r_timereport_active)
3996 R_TimeReport("prepasslights");
3999 #define MAX_SCENELIGHTS 65536
4000 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4002 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4004 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4006 r_shadow_scenemaxlights *= 2;
4007 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4008 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4010 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4014 void R_Shadow_DrawLightSprites(void);
4015 void R_Shadow_PrepareLights(void)
4024 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4025 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4026 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4028 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4029 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4030 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4031 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4032 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4033 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4034 r_shadow_shadowmapborder != shadowmapborder ||
4035 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4036 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4037 R_Shadow_FreeShadowMaps();
4039 r_shadow_usingshadowmaportho = false;
4041 switch (vid.renderpath)
4043 case RENDERPATH_GL32:
4045 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4047 r_shadow_usingdeferredprepass = false;
4048 if (r_shadow_prepass_width)
4049 R_Shadow_FreeDeferred();
4050 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4054 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4056 R_Shadow_FreeDeferred();
4058 r_shadow_usingdeferredprepass = true;
4059 r_shadow_prepass_width = vid.width;
4060 r_shadow_prepass_height = vid.height;
4061 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4062 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);
4063 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);
4064 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);
4066 // set up the geometry pass fbo (depth + normalmap)
4067 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4068 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4069 // render depth into a renderbuffer and other important properties into the normalmap texture
4071 // set up the lighting pass fbo (diffuse + specular)
4072 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4073 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4074 // render diffuse into one texture and specular into another,
4075 // with depth and normalmap bound as textures,
4076 // with depth bound as attachment as well
4078 // set up the lighting pass fbo (diffuse)
4079 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4080 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4081 // render diffuse into one texture,
4082 // with depth and normalmap bound as textures,
4083 // with depth bound as attachment as well
4087 case RENDERPATH_GLES2:
4088 r_shadow_usingdeferredprepass = false;
4092 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);
4094 r_shadow_scenenumlights = 0;
4095 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4096 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4097 for (lightindex = 0; lightindex < range; lightindex++)
4099 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4100 if (light && (light->flags & flag))
4102 R_Shadow_PrepareLight(&light->rtlight);
4103 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4106 if (r_refdef.scene.rtdlight)
4108 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4110 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4111 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4114 else if (gl_flashblend.integer)
4116 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4118 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4119 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4120 VectorScale(rtlight->color, f, rtlight->currentcolor);
4124 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4125 if (r_shadow_debuglight.integer >= 0)
4127 r_shadow_scenenumlights = 0;
4128 lightindex = r_shadow_debuglight.integer;
4129 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4132 R_Shadow_PrepareLight(&light->rtlight);
4133 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4137 // if we're doing shadowmaps we need to prepare the atlas layout now
4138 if (R_Shadow_ShadowMappingEnabled())
4142 // allocate shadowmaps in the atlas now
4143 // 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...
4144 for (lod = 0; lod < 16; lod++)
4146 int packing_success = 0;
4147 int packing_failure = 0;
4148 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4149 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4150 if (r_shadow_shadowmapatlas_modelshadows_size)
4151 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);
4152 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4154 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4155 int size = rtlight->shadowmapsidesize >> lod;
4157 if (!rtlight->castshadows)
4159 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4162 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4163 if (rtlight->cached_numshadowentities_noselfshadow)
4165 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4167 rtlight->shadowmapatlassidesize = size;
4172 // note down that we failed to pack this one, it will have to disable shadows
4173 rtlight->shadowmapatlassidesize = 0;
4177 // generally everything fits and we stop here on the first iteration
4178 if (packing_failure == 0)
4183 if (r_editlights.integer)
4184 R_Shadow_DrawLightSprites();
4187 void R_Shadow_DrawShadowMaps(void)
4189 R_Shadow_RenderMode_Begin();
4190 R_Shadow_RenderMode_ActiveLight(NULL);
4192 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4193 R_Shadow_ClearShadowMapTexture();
4195 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4196 if (r_shadow_shadowmapatlas_modelshadows_size)
4198 R_Shadow_DrawModelShadowMaps();
4199 // don't let sound skip if going slow
4200 if (r_refdef.scene.extraupdate)
4204 if (R_Shadow_ShadowMappingEnabled())
4207 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4208 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4211 R_Shadow_RenderMode_End();
4214 void R_Shadow_DrawLights(void)
4218 R_Shadow_RenderMode_Begin();
4220 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4221 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4223 R_Shadow_RenderMode_End();
4226 #define MAX_MODELSHADOWS 1024
4227 static int r_shadow_nummodelshadows;
4228 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4230 void R_Shadow_PrepareModelShadows(void)
4233 float scale, size, radius, dot1, dot2;
4234 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4235 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4236 entity_render_t *ent;
4238 r_shadow_nummodelshadows = 0;
4239 r_shadow_shadowmapatlas_modelshadows_size = 0;
4241 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4244 size = r_shadow_shadowmaptexturesize / 4;
4245 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4246 radius = 0.5f * size / scale;
4248 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4249 VectorCopy(prvmshadowdir, shadowdir);
4250 VectorNormalize(shadowdir);
4251 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4252 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4253 if (fabs(dot1) <= fabs(dot2))
4254 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4256 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4257 VectorNormalize(shadowforward);
4258 CrossProduct(shadowdir, shadowforward, shadowright);
4259 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4260 VectorCopy(prvmshadowfocus, shadowfocus);
4261 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4262 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4263 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4264 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4265 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4267 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4269 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4270 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4271 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4272 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4273 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4274 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4276 for (i = 0; i < r_refdef.scene.numentities; i++)
4278 ent = r_refdef.scene.entities[i];
4279 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4281 // cast shadows from anything of the map (submodels are optional)
4282 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4284 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4286 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4287 R_AnimCache_GetEntity(ent, false, false);
4291 if (r_shadow_nummodelshadows)
4293 r_shadow_shadowmapatlas_modelshadows_x = 0;
4294 r_shadow_shadowmapatlas_modelshadows_y = 0;
4295 r_shadow_shadowmapatlas_modelshadows_size = size;
4299 static void R_Shadow_DrawModelShadowMaps(void)
4302 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4303 entity_render_t *ent;
4304 vec3_t relativelightorigin;
4305 vec3_t relativelightdirection, relativeforward, relativeright;
4306 vec3_t relativeshadowmins, relativeshadowmaxs;
4307 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4308 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4310 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4311 r_viewport_t viewport;
4313 size = r_shadow_shadowmapatlas_modelshadows_size;
4314 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4315 radius = 0.5f / scale;
4316 nearclip = -r_shadows_throwdistance.value;
4317 farclip = r_shadows_throwdistance.value;
4318 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);
4320 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4321 r_shadow_modelshadowmap_parameters[0] = size;
4322 r_shadow_modelshadowmap_parameters[1] = size;
4323 r_shadow_modelshadowmap_parameters[2] = 1.0;
4324 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4325 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4326 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4327 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4328 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4329 r_shadow_usingshadowmaportho = true;
4331 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4332 VectorCopy(prvmshadowdir, shadowdir);
4333 VectorNormalize(shadowdir);
4334 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4335 VectorCopy(prvmshadowfocus, shadowfocus);
4336 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4337 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4338 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4339 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4340 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4341 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4342 if (fabs(dot1) <= fabs(dot2))
4343 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4345 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4346 VectorNormalize(shadowforward);
4347 VectorM(scale, shadowforward, &m[0]);
4348 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4350 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4351 CrossProduct(shadowdir, shadowforward, shadowright);
4352 VectorM(scale, shadowright, &m[4]);
4353 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4354 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4355 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4356 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4357 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4358 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);
4359 R_SetViewport(&viewport);
4361 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4363 // render into a slightly restricted region so that the borders of the
4364 // shadowmap area fade away, rather than streaking across everything
4365 // outside the usable area
4366 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4368 for (i = 0;i < r_shadow_nummodelshadows;i++)
4370 ent = r_shadow_modelshadows[i];
4371 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4372 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4373 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4374 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4375 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4376 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4377 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4378 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4379 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4380 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4381 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4382 RSurf_ActiveModelEntity(ent, false, false, false);
4383 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4384 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4390 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4392 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4394 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4395 Cvar_SetValueQuick(&r_test, 0);
4400 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4401 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4402 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4403 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4404 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4405 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4408 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4411 vec3_t centerorigin;
4415 // if it's too close, skip it
4416 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4418 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4421 if (usequery && r_numqueries + 2 <= r_maxqueries)
4423 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4424 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4425 // 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
4426 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4428 switch(vid.renderpath)
4430 case RENDERPATH_GL32:
4431 case RENDERPATH_GLES2:
4434 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4435 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4436 GL_DepthFunc(GL_ALWAYS);
4437 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4438 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4439 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4440 qglEndQuery(GL_SAMPLES_PASSED);
4441 GL_DepthFunc(GL_LEQUAL);
4442 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4443 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4444 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4445 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4446 qglEndQuery(GL_SAMPLES_PASSED);
4452 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4455 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4457 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4460 unsigned int occlude = 0;
4462 // now we have to check the query result
4463 if (rtlight->corona_queryindex_visiblepixels)
4465 switch(vid.renderpath)
4467 case RENDERPATH_GL32:
4468 case RENDERPATH_GLES2:
4470 // store the pixel counts into a uniform buffer for the shader to
4471 // use - we'll never know the results on the cpu without
4472 // synchronizing and we don't want that
4473 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4474 if (!r_shadow_occlusion_buf) {
4475 qglGenBuffers(1, &r_shadow_occlusion_buf);
4476 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4477 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4479 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4481 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4482 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4483 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4484 occlude = MATERIALFLAG_OCCLUDE;
4485 cscale *= rtlight->corona_visibility;
4495 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4498 VectorScale(rtlight->currentcolor, cscale, color);
4499 if (VectorLength(color) > (1.0f / 256.0f))
4502 qboolean negated = (color[0] + color[1] + color[2] < 0);
4505 VectorNegate(color, color);
4506 GL_BlendEquationSubtract(true);
4508 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4509 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);
4510 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4512 GL_BlendEquationSubtract(false);
4516 void R_Shadow_DrawCoronas(void)
4519 qboolean usequery = false;
4524 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4526 if (r_fb.water.renderingscene)
4528 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4529 R_EntityMatrix(&identitymatrix);
4531 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4533 // check occlusion of coronas, using occlusion queries or raytraces
4535 switch (vid.renderpath)
4537 case RENDERPATH_GL32:
4538 case RENDERPATH_GLES2:
4539 usequery = r_coronas_occlusionquery.integer;
4543 GL_ColorMask(0,0,0,0);
4544 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4545 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4548 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4549 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4551 qglGenQueries(r_maxqueries - i, r_queries + i);
4554 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4555 GL_BlendFunc(GL_ONE, GL_ZERO);
4556 GL_CullFace(GL_NONE);
4557 GL_DepthMask(false);
4558 GL_DepthRange(0, 1);
4559 GL_PolygonOffset(0, 0);
4561 R_Mesh_ResetTextureState();
4562 R_SetupShader_Generic_NoTexture(false, false);
4567 for (lightindex = 0;lightindex < range;lightindex++)
4569 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4572 rtlight = &light->rtlight;
4573 rtlight->corona_visibility = 0;
4574 rtlight->corona_queryindex_visiblepixels = 0;
4575 rtlight->corona_queryindex_allpixels = 0;
4576 if (!(rtlight->flags & flag))
4578 if (rtlight->corona <= 0)
4580 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4582 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4584 for (i = 0;i < r_refdef.scene.numlights;i++)
4586 rtlight = r_refdef.scene.lights[i];
4587 rtlight->corona_visibility = 0;
4588 rtlight->corona_queryindex_visiblepixels = 0;
4589 rtlight->corona_queryindex_allpixels = 0;
4590 if (!(rtlight->flags & flag))
4592 if (rtlight->corona <= 0)
4594 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4597 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4599 // now draw the coronas using the query data for intensity info
4600 for (lightindex = 0;lightindex < range;lightindex++)
4602 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4605 rtlight = &light->rtlight;
4606 if (rtlight->corona_visibility <= 0)
4608 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4610 for (i = 0;i < r_refdef.scene.numlights;i++)
4612 rtlight = r_refdef.scene.lights[i];
4613 if (rtlight->corona_visibility <= 0)
4615 if (gl_flashblend.integer)
4616 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4618 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4624 static dlight_t *R_Shadow_NewWorldLight(void)
4626 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4629 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)
4633 // 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
4635 // validate parameters
4639 // copy to light properties
4640 VectorCopy(origin, light->origin);
4641 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4642 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4643 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4645 light->color[0] = max(color[0], 0);
4646 light->color[1] = max(color[1], 0);
4647 light->color[2] = max(color[2], 0);
4649 light->color[0] = color[0];
4650 light->color[1] = color[1];
4651 light->color[2] = color[2];
4652 light->radius = max(radius, 0);
4653 light->style = style;
4654 light->shadow = shadowenable;
4655 light->corona = corona;
4656 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4657 light->coronasizescale = coronasizescale;
4658 light->ambientscale = ambientscale;
4659 light->diffusescale = diffusescale;
4660 light->specularscale = specularscale;
4661 light->flags = flags;
4663 // update renderable light data
4664 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4665 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);
4668 static void R_Shadow_FreeWorldLight(dlight_t *light)
4670 if (r_shadow_selectedlight == light)
4671 r_shadow_selectedlight = NULL;
4672 R_RTLight_Uncompile(&light->rtlight);
4673 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4676 void R_Shadow_ClearWorldLights(void)
4680 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4681 for (lightindex = 0;lightindex < range;lightindex++)
4683 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4685 R_Shadow_FreeWorldLight(light);
4687 r_shadow_selectedlight = NULL;
4690 static void R_Shadow_SelectLight(dlight_t *light)
4692 if (r_shadow_selectedlight)
4693 r_shadow_selectedlight->selected = false;
4694 r_shadow_selectedlight = light;
4695 if (r_shadow_selectedlight)
4696 r_shadow_selectedlight->selected = true;
4699 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4701 // this is never batched (there can be only one)
4703 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4704 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4705 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4708 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4713 skinframe_t *skinframe;
4716 // this is never batched (due to the ent parameter changing every time)
4717 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4718 const dlight_t *light = (dlight_t *)ent;
4721 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4724 VectorScale(light->color, intensity, spritecolor);
4725 if (VectorLength(spritecolor) < 0.1732f)
4726 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4727 if (VectorLength(spritecolor) > 1.0f)
4728 VectorNormalize(spritecolor);
4730 // draw light sprite
4731 if (light->cubemapname[0] && !light->shadow)
4732 skinframe = r_editlights_sprcubemapnoshadowlight;
4733 else if (light->cubemapname[0])
4734 skinframe = r_editlights_sprcubemaplight;
4735 else if (!light->shadow)
4736 skinframe = r_editlights_sprnoshadowlight;
4738 skinframe = r_editlights_sprlight;
4740 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);
4741 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4743 // draw selection sprite if light is selected
4744 if (light->selected)
4746 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4747 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4748 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4752 void R_Shadow_DrawLightSprites(void)
4756 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4757 for (lightindex = 0;lightindex < range;lightindex++)
4759 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4761 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4763 if (!r_editlights_lockcursor)
4764 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4767 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4772 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4773 if (lightindex >= range)
4775 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4778 rtlight = &light->rtlight;
4779 //if (!(rtlight->flags & flag))
4781 VectorCopy(rtlight->shadoworigin, origin);
4782 *radius = rtlight->radius;
4783 VectorCopy(rtlight->color, color);
4787 static void R_Shadow_SelectLightInView(void)
4789 float bestrating, rating, temp[3];
4793 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4797 if (r_editlights_lockcursor)
4799 for (lightindex = 0;lightindex < range;lightindex++)
4801 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4804 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4805 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4808 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4809 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)
4811 bestrating = rating;
4816 R_Shadow_SelectLight(best);
4819 void R_Shadow_LoadWorldLights(void)
4821 int n, a, style, shadow, flags;
4822 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4823 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4824 if (cl.worldmodel == NULL)
4826 Con_Print("No map loaded.\n");
4829 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4830 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4840 for (;COM_Parse(t, true) && strcmp(
4841 if (COM_Parse(t, true))
4843 if (com_token[0] == '!')
4846 origin[0] = atof(com_token+1);
4849 origin[0] = atof(com_token);
4854 while (*s && *s != '\n' && *s != '\r')
4860 // check for modifier flags
4867 #if _MSC_VER >= 1400
4868 #define sscanf sscanf_s
4870 cubemapname[sizeof(cubemapname)-1] = 0;
4871 #if MAX_QPATH != 128
4872 #error update this code if MAX_QPATH changes
4874 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
4875 #if _MSC_VER >= 1400
4876 , (unsigned int)sizeof(cubemapname)
4878 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4881 flags = LIGHTFLAG_REALTIMEMODE;
4889 coronasizescale = 0.25f;
4891 VectorClear(angles);
4894 if (a < 9 || !strcmp(cubemapname, "\"\""))
4896 // remove quotes on cubemapname
4897 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4900 namelen = strlen(cubemapname) - 2;
4901 memmove(cubemapname, cubemapname + 1, namelen);
4902 cubemapname[namelen] = '\0';
4906 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);
4909 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4917 Con_Printf("invalid rtlights file \"%s\"\n", name);
4918 Mem_Free(lightsstring);
4922 void R_Shadow_SaveWorldLights(void)
4926 size_t bufchars, bufmaxchars;
4928 char name[MAX_QPATH];
4929 char line[MAX_INPUTLINE];
4930 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4931 // I hate lines which are 3 times my screen size :( --blub
4934 if (cl.worldmodel == NULL)
4936 Con_Print("No map loaded.\n");
4939 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4940 bufchars = bufmaxchars = 0;
4942 for (lightindex = 0;lightindex < range;lightindex++)
4944 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4947 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4948 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);
4949 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4950 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]);
4952 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);
4953 if (bufchars + strlen(line) > bufmaxchars)
4955 bufmaxchars = bufchars + strlen(line) + 2048;
4957 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4961 memcpy(buf, oldbuf, bufchars);
4967 memcpy(buf + bufchars, line, strlen(line));
4968 bufchars += strlen(line);
4972 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4977 void R_Shadow_LoadLightsFile(void)
4980 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4981 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4982 if (cl.worldmodel == NULL)
4984 Con_Print("No map loaded.\n");
4987 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
4988 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4996 while (*s && *s != '\n' && *s != '\r')
5002 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);
5006 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);
5009 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5010 radius = bound(15, radius, 4096);
5011 VectorScale(color, (2.0f / (8388608.0f)), color);
5012 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5020 Con_Printf("invalid lights file \"%s\"\n", name);
5021 Mem_Free(lightsstring);
5025 // tyrlite/hmap2 light types in the delay field
5026 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5028 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5040 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5041 char key[256], value[MAX_INPUTLINE];
5044 if (cl.worldmodel == NULL)
5046 Con_Print("No map loaded.\n");
5049 // try to load a .ent file first
5050 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5051 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5052 // and if that is not found, fall back to the bsp file entity string
5054 data = cl.worldmodel->brush.entities;
5057 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5059 type = LIGHTTYPE_MINUSX;
5060 origin[0] = origin[1] = origin[2] = 0;
5061 originhack[0] = originhack[1] = originhack[2] = 0;
5062 angles[0] = angles[1] = angles[2] = 0;
5063 color[0] = color[1] = color[2] = 1;
5064 light[0] = light[1] = light[2] = 1;light[3] = 300;
5065 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5075 if (!COM_ParseToken_Simple(&data, false, false, true))
5077 if (com_token[0] == '}')
5078 break; // end of entity
5079 if (com_token[0] == '_')
5080 strlcpy(key, com_token + 1, sizeof(key));
5082 strlcpy(key, com_token, sizeof(key));
5083 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5084 key[strlen(key)-1] = 0;
5085 if (!COM_ParseToken_Simple(&data, false, false, true))
5087 strlcpy(value, com_token, sizeof(value));
5089 // now that we have the key pair worked out...
5090 if (!strcmp("light", key))
5092 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5096 light[0] = vec[0] * (1.0f / 256.0f);
5097 light[1] = vec[0] * (1.0f / 256.0f);
5098 light[2] = vec[0] * (1.0f / 256.0f);
5104 light[0] = vec[0] * (1.0f / 255.0f);
5105 light[1] = vec[1] * (1.0f / 255.0f);
5106 light[2] = vec[2] * (1.0f / 255.0f);
5110 else if (!strcmp("delay", key))
5112 else if (!strcmp("origin", key))
5113 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5114 else if (!strcmp("angle", key))
5115 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5116 else if (!strcmp("angles", key))
5117 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5118 else if (!strcmp("color", key))
5119 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5120 else if (!strcmp("wait", key))
5121 fadescale = atof(value);
5122 else if (!strcmp("classname", key))
5124 if (!strncmp(value, "light", 5))
5127 if (!strcmp(value, "light_fluoro"))
5132 overridecolor[0] = 1;
5133 overridecolor[1] = 1;
5134 overridecolor[2] = 1;
5136 if (!strcmp(value, "light_fluorospark"))
5141 overridecolor[0] = 1;
5142 overridecolor[1] = 1;
5143 overridecolor[2] = 1;
5145 if (!strcmp(value, "light_globe"))
5150 overridecolor[0] = 1;
5151 overridecolor[1] = 0.8;
5152 overridecolor[2] = 0.4;
5154 if (!strcmp(value, "light_flame_large_yellow"))
5159 overridecolor[0] = 1;
5160 overridecolor[1] = 0.5;
5161 overridecolor[2] = 0.1;
5163 if (!strcmp(value, "light_flame_small_yellow"))
5168 overridecolor[0] = 1;
5169 overridecolor[1] = 0.5;
5170 overridecolor[2] = 0.1;
5172 if (!strcmp(value, "light_torch_small_white"))
5177 overridecolor[0] = 1;
5178 overridecolor[1] = 0.5;
5179 overridecolor[2] = 0.1;
5181 if (!strcmp(value, "light_torch_small_walltorch"))
5186 overridecolor[0] = 1;
5187 overridecolor[1] = 0.5;
5188 overridecolor[2] = 0.1;
5192 else if (!strcmp("style", key))
5193 style = atoi(value);
5194 else if (!strcmp("skin", key))
5195 skin = (int)atof(value);
5196 else if (!strcmp("pflags", key))
5197 pflags = (int)atof(value);
5198 //else if (!strcmp("effects", key))
5199 // effects = (int)atof(value);
5200 else if (cl.worldmodel->type == mod_brushq3)
5202 if (!strcmp("scale", key))
5203 lightscale = atof(value);
5204 if (!strcmp("fade", key))
5205 fadescale = atof(value);
5210 if (lightscale <= 0)
5214 if (color[0] == color[1] && color[0] == color[2])
5216 color[0] *= overridecolor[0];
5217 color[1] *= overridecolor[1];
5218 color[2] *= overridecolor[2];
5220 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5221 color[0] = color[0] * light[0];
5222 color[1] = color[1] * light[1];
5223 color[2] = color[2] * light[2];
5226 case LIGHTTYPE_MINUSX:
5228 case LIGHTTYPE_RECIPX:
5230 VectorScale(color, (1.0f / 16.0f), color);
5232 case LIGHTTYPE_RECIPXX:
5234 VectorScale(color, (1.0f / 16.0f), color);
5237 case LIGHTTYPE_NONE:
5241 case LIGHTTYPE_MINUSXX:
5244 VectorAdd(origin, originhack, origin);
5246 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);
5249 Mem_Free(entfiledata);
5253 static void R_Shadow_SetCursorLocationForView(void)
5256 vec3_t dest, endpos;
5258 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5259 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5260 if (trace.fraction < 1)
5262 dist = trace.fraction * r_editlights_cursordistance.value;
5263 push = r_editlights_cursorpushback.value;
5267 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5268 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5272 VectorClear( endpos );
5274 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5275 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5276 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5279 void R_Shadow_UpdateWorldLightSelection(void)
5281 if (r_editlights.integer)
5283 R_Shadow_SetCursorLocationForView();
5284 R_Shadow_SelectLightInView();
5287 R_Shadow_SelectLight(NULL);
5290 static void R_Shadow_EditLights_Clear_f(void)
5292 R_Shadow_ClearWorldLights();
5295 void R_Shadow_EditLights_Reload_f(void)
5299 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5300 R_Shadow_ClearWorldLights();
5301 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5303 R_Shadow_LoadWorldLights();
5304 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5305 R_Shadow_LoadLightsFile();
5307 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5309 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5310 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5314 static void R_Shadow_EditLights_Save_f(void)
5318 R_Shadow_SaveWorldLights();
5321 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5323 R_Shadow_ClearWorldLights();
5324 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5327 static void R_Shadow_EditLights_ImportLightsFile_f(void)
5329 R_Shadow_ClearWorldLights();
5330 R_Shadow_LoadLightsFile();
5333 static void R_Shadow_EditLights_Spawn_f(void)
5336 if (!r_editlights.integer)
5338 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5341 if (Cmd_Argc() != 1)
5343 Con_Print("r_editlights_spawn does not take parameters\n");
5346 color[0] = color[1] = color[2] = 1;
5347 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5350 static void R_Shadow_EditLights_Edit_f(void)
5352 vec3_t origin, angles, color;
5353 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5354 int style, shadows, flags, normalmode, realtimemode;
5355 char cubemapname[MAX_INPUTLINE];
5356 if (!r_editlights.integer)
5358 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5361 if (!r_shadow_selectedlight)
5363 Con_Print("No selected light.\n");
5366 VectorCopy(r_shadow_selectedlight->origin, origin);
5367 VectorCopy(r_shadow_selectedlight->angles, angles);
5368 VectorCopy(r_shadow_selectedlight->color, color);
5369 radius = r_shadow_selectedlight->radius;
5370 style = r_shadow_selectedlight->style;
5371 if (r_shadow_selectedlight->cubemapname)
5372 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5375 shadows = r_shadow_selectedlight->shadow;
5376 corona = r_shadow_selectedlight->corona;
5377 coronasizescale = r_shadow_selectedlight->coronasizescale;
5378 ambientscale = r_shadow_selectedlight->ambientscale;
5379 diffusescale = r_shadow_selectedlight->diffusescale;
5380 specularscale = r_shadow_selectedlight->specularscale;
5381 flags = r_shadow_selectedlight->flags;
5382 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5383 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5384 if (!strcmp(Cmd_Argv(1), "origin"))
5386 if (Cmd_Argc() != 5)
5388 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5391 origin[0] = atof(Cmd_Argv(2));
5392 origin[1] = atof(Cmd_Argv(3));
5393 origin[2] = atof(Cmd_Argv(4));
5395 else if (!strcmp(Cmd_Argv(1), "originscale"))
5397 if (Cmd_Argc() != 5)
5399 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5402 origin[0] *= atof(Cmd_Argv(2));
5403 origin[1] *= atof(Cmd_Argv(3));
5404 origin[2] *= atof(Cmd_Argv(4));
5406 else if (!strcmp(Cmd_Argv(1), "originx"))
5408 if (Cmd_Argc() != 3)
5410 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5413 origin[0] = atof(Cmd_Argv(2));
5415 else if (!strcmp(Cmd_Argv(1), "originy"))
5417 if (Cmd_Argc() != 3)
5419 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5422 origin[1] = atof(Cmd_Argv(2));
5424 else if (!strcmp(Cmd_Argv(1), "originz"))
5426 if (Cmd_Argc() != 3)
5428 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5431 origin[2] = atof(Cmd_Argv(2));
5433 else if (!strcmp(Cmd_Argv(1), "move"))
5435 if (Cmd_Argc() != 5)
5437 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5440 origin[0] += atof(Cmd_Argv(2));
5441 origin[1] += atof(Cmd_Argv(3));
5442 origin[2] += atof(Cmd_Argv(4));
5444 else if (!strcmp(Cmd_Argv(1), "movex"))
5446 if (Cmd_Argc() != 3)
5448 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5451 origin[0] += atof(Cmd_Argv(2));
5453 else if (!strcmp(Cmd_Argv(1), "movey"))
5455 if (Cmd_Argc() != 3)
5457 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5460 origin[1] += atof(Cmd_Argv(2));
5462 else if (!strcmp(Cmd_Argv(1), "movez"))
5464 if (Cmd_Argc() != 3)
5466 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5469 origin[2] += atof(Cmd_Argv(2));
5471 else if (!strcmp(Cmd_Argv(1), "angles"))
5473 if (Cmd_Argc() != 5)
5475 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5478 angles[0] = atof(Cmd_Argv(2));
5479 angles[1] = atof(Cmd_Argv(3));
5480 angles[2] = atof(Cmd_Argv(4));
5482 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5484 if (Cmd_Argc() != 3)
5486 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5489 angles[0] = atof(Cmd_Argv(2));
5491 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5493 if (Cmd_Argc() != 3)
5495 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5498 angles[1] = atof(Cmd_Argv(2));
5500 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5502 if (Cmd_Argc() != 3)
5504 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5507 angles[2] = atof(Cmd_Argv(2));
5509 else if (!strcmp(Cmd_Argv(1), "color"))
5511 if (Cmd_Argc() != 5)
5513 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5516 color[0] = atof(Cmd_Argv(2));
5517 color[1] = atof(Cmd_Argv(3));
5518 color[2] = atof(Cmd_Argv(4));
5520 else if (!strcmp(Cmd_Argv(1), "radius"))
5522 if (Cmd_Argc() != 3)
5524 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5527 radius = atof(Cmd_Argv(2));
5529 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5531 if (Cmd_Argc() == 3)
5533 double scale = atof(Cmd_Argv(2));
5540 if (Cmd_Argc() != 5)
5542 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5545 color[0] *= atof(Cmd_Argv(2));
5546 color[1] *= atof(Cmd_Argv(3));
5547 color[2] *= atof(Cmd_Argv(4));
5550 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5552 if (Cmd_Argc() != 3)
5554 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5557 radius *= atof(Cmd_Argv(2));
5559 else if (!strcmp(Cmd_Argv(1), "style"))
5561 if (Cmd_Argc() != 3)
5563 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5566 style = atoi(Cmd_Argv(2));
5568 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5572 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5575 if (Cmd_Argc() == 3)
5576 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5580 else if (!strcmp(Cmd_Argv(1), "shadows"))
5582 if (Cmd_Argc() != 3)
5584 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5587 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5589 else if (!strcmp(Cmd_Argv(1), "corona"))
5591 if (Cmd_Argc() != 3)
5593 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5596 corona = atof(Cmd_Argv(2));
5598 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5600 if (Cmd_Argc() != 3)
5602 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5605 coronasizescale = atof(Cmd_Argv(2));
5607 else if (!strcmp(Cmd_Argv(1), "ambient"))
5609 if (Cmd_Argc() != 3)
5611 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5614 ambientscale = atof(Cmd_Argv(2));
5616 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5618 if (Cmd_Argc() != 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5623 diffusescale = atof(Cmd_Argv(2));
5625 else if (!strcmp(Cmd_Argv(1), "specular"))
5627 if (Cmd_Argc() != 3)
5629 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5632 specularscale = atof(Cmd_Argv(2));
5634 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5636 if (Cmd_Argc() != 3)
5638 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5641 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5643 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5645 if (Cmd_Argc() != 3)
5647 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5650 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5654 Con_Print("usage: r_editlights_edit [property] [value]\n");
5655 Con_Print("Selected light's properties:\n");
5656 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5657 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5658 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5659 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5660 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5661 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5662 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5663 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5664 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5665 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5666 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5667 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5668 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5669 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5672 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5673 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5676 static void R_Shadow_EditLights_EditAll_f(void)
5679 dlight_t *light, *oldselected;
5682 if (!r_editlights.integer)
5684 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5688 oldselected = r_shadow_selectedlight;
5689 // EditLights doesn't seem to have a "remove" command or something so:
5690 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5691 for (lightindex = 0;lightindex < range;lightindex++)
5693 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5696 R_Shadow_SelectLight(light);
5697 R_Shadow_EditLights_Edit_f();
5699 // return to old selected (to not mess editing once selection is locked)
5700 R_Shadow_SelectLight(oldselected);
5703 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5705 int lightnumber, lightcount;
5706 size_t lightindex, range;
5711 if (!r_editlights.integer)
5714 // update cvars so QC can query them
5715 if (r_shadow_selectedlight)
5717 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5718 Cvar_SetQuick(&r_editlights_current_origin, temp);
5719 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5720 Cvar_SetQuick(&r_editlights_current_angles, temp);
5721 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5722 Cvar_SetQuick(&r_editlights_current_color, temp);
5723 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5724 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5725 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5726 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5727 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5728 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5729 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5730 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5731 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5732 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5733 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5736 // draw properties on screen
5737 if (!r_editlights_drawproperties.integer)
5739 x = vid_conwidth.value - 320;
5741 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5744 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5745 for (lightindex = 0;lightindex < range;lightindex++)
5747 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5750 if (light == r_shadow_selectedlight)
5751 lightnumber = (int)lightindex;
5754 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;
5755 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;
5757 if (r_shadow_selectedlight == NULL)
5759 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;
5760 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;
5761 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;
5762 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;
5763 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;
5764 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;
5765 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;
5766 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;
5767 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;
5768 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;
5769 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;
5770 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;
5771 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;
5772 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;
5773 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;
5775 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;
5776 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;
5777 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;
5778 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;
5779 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;
5780 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;
5781 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;
5782 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;
5783 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;
5784 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;
5787 static void R_Shadow_EditLights_ToggleShadow_f(void)
5789 if (!r_editlights.integer)
5791 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5794 if (!r_shadow_selectedlight)
5796 Con_Print("No selected light.\n");
5799 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);
5802 static void R_Shadow_EditLights_ToggleCorona_f(void)
5804 if (!r_editlights.integer)
5806 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5809 if (!r_shadow_selectedlight)
5811 Con_Print("No selected light.\n");
5814 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);
5817 static void R_Shadow_EditLights_Remove_f(void)
5819 if (!r_editlights.integer)
5821 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5824 if (!r_shadow_selectedlight)
5826 Con_Print("No selected light.\n");
5829 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5830 r_shadow_selectedlight = NULL;
5833 static void R_Shadow_EditLights_Help_f(void)
5836 "Documentation on r_editlights system:\n"
5838 "r_editlights : enable/disable editing mode\n"
5839 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5840 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5841 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5842 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5843 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5845 "r_editlights_help : this help\n"
5846 "r_editlights_clear : remove all lights\n"
5847 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5848 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5849 "r_editlights_save : save to .rtlights file\n"
5850 "r_editlights_spawn : create a light with default settings\n"
5851 "r_editlights_edit command : edit selected light - more documentation below\n"
5852 "r_editlights_remove : remove selected light\n"
5853 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5854 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5855 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5857 "origin x y z : set light location\n"
5858 "originx x: set x component of light location\n"
5859 "originy y: set y component of light location\n"
5860 "originz z: set z component of light location\n"
5861 "move x y z : adjust light location\n"
5862 "movex x: adjust x component of light location\n"
5863 "movey y: adjust y component of light location\n"
5864 "movez z: adjust z component of light location\n"
5865 "angles x y z : set light angles\n"
5866 "anglesx x: set x component of light angles\n"
5867 "anglesy y: set y component of light angles\n"
5868 "anglesz z: set z component of light angles\n"
5869 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5870 "radius radius : set radius (size) of light\n"
5871 "colorscale grey : multiply color of light (1 does nothing)\n"
5872 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5873 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5874 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5875 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5876 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5877 "cubemap basename : set filter cubemap of light\n"
5878 "shadows 1/0 : turn on/off shadows\n"
5879 "corona n : set corona intensity\n"
5880 "coronasize n : set corona size (0-1)\n"
5881 "ambient n : set ambient intensity (0-1)\n"
5882 "diffuse n : set diffuse intensity (0-1)\n"
5883 "specular n : set specular intensity (0-1)\n"
5884 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5885 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5886 "<nothing> : print light properties to console\n"
5890 static void R_Shadow_EditLights_CopyInfo_f(void)
5892 if (!r_editlights.integer)
5894 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5897 if (!r_shadow_selectedlight)
5899 Con_Print("No selected light.\n");
5902 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5903 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5904 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5905 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5906 if (r_shadow_selectedlight->cubemapname)
5907 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5909 r_shadow_bufferlight.cubemapname[0] = 0;
5910 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5911 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5912 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5913 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5914 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5915 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5916 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5919 static void R_Shadow_EditLights_PasteInfo_f(void)
5921 if (!r_editlights.integer)
5923 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5926 if (!r_shadow_selectedlight)
5928 Con_Print("No selected light.\n");
5931 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);
5934 static void R_Shadow_EditLights_Lock_f(void)
5936 if (!r_editlights.integer)
5938 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5941 if (r_editlights_lockcursor)
5943 r_editlights_lockcursor = false;
5946 if (!r_shadow_selectedlight)
5948 Con_Print("No selected light to lock on.\n");
5951 r_editlights_lockcursor = true;
5954 static void R_Shadow_EditLights_Init(void)
5956 Cvar_RegisterVariable(&r_editlights);
5957 Cvar_RegisterVariable(&r_editlights_cursordistance);
5958 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5959 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5960 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5961 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5962 Cvar_RegisterVariable(&r_editlights_drawproperties);
5963 Cvar_RegisterVariable(&r_editlights_current_origin);
5964 Cvar_RegisterVariable(&r_editlights_current_angles);
5965 Cvar_RegisterVariable(&r_editlights_current_color);
5966 Cvar_RegisterVariable(&r_editlights_current_radius);
5967 Cvar_RegisterVariable(&r_editlights_current_corona);
5968 Cvar_RegisterVariable(&r_editlights_current_coronasize);
5969 Cvar_RegisterVariable(&r_editlights_current_style);
5970 Cvar_RegisterVariable(&r_editlights_current_shadows);
5971 Cvar_RegisterVariable(&r_editlights_current_cubemap);
5972 Cvar_RegisterVariable(&r_editlights_current_ambient);
5973 Cvar_RegisterVariable(&r_editlights_current_diffuse);
5974 Cvar_RegisterVariable(&r_editlights_current_specular);
5975 Cvar_RegisterVariable(&r_editlights_current_normalmode);
5976 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
5977 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5978 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5979 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)");
5980 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5981 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5982 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5983 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)");
5984 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5985 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5986 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5987 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5988 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5989 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5990 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)");
5991 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
5997 =============================================================================
6001 =============================================================================
6004 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6006 int i, numlights, flag, q;
6009 float relativepoint[3];
6014 float sa[3], sx[3], sy[3], sz[3], sd[3];
6017 // use first order spherical harmonics to combine directional lights
6018 for (q = 0; q < 3; q++)
6019 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6021 if (flags & LP_LIGHTMAP)
6023 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6025 float tempambient[3];
6026 for (q = 0; q < 3; q++)
6027 tempambient[q] = color[q] = relativepoint[q] = 0;
6028 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6029 // calculate a weighted average light direction as well
6030 intensity = VectorLength(color);
6031 for (q = 0; q < 3; q++)
6033 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6034 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6035 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6036 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6037 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6042 // unlit map - fullbright but scaled by lightmapintensity
6043 for (q = 0; q < 3; q++)
6044 sa[q] += lightmapintensity;
6048 if (flags & LP_RTWORLD)
6050 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6051 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6052 for (i = 0; i < numlights; i++)
6054 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6057 light = &dlight->rtlight;
6058 if (!(light->flags & flag))
6061 lightradius2 = light->radius * light->radius;
6062 VectorSubtract(light->shadoworigin, p, relativepoint);
6063 dist2 = VectorLength2(relativepoint);
6064 if (dist2 >= lightradius2)
6066 dist = sqrt(dist2) / light->radius;
6067 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6068 if (intensity <= 0.0f)
6070 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)
6072 for (q = 0; q < 3; q++)
6073 color[q] = light->currentcolor[q] * intensity;
6074 intensity = VectorLength(color);
6075 VectorNormalize(relativepoint);
6076 for (q = 0; q < 3; q++)
6078 sa[q] += 0.5f * color[q];
6079 sx[q] += relativepoint[0] * color[q];
6080 sy[q] += relativepoint[1] * color[q];
6081 sz[q] += relativepoint[2] * color[q];
6082 sd[q] += intensity * relativepoint[q];
6085 // FIXME: sample bouncegrid too!
6088 if (flags & LP_DYNLIGHT)
6091 for (i = 0;i < r_refdef.scene.numlights;i++)
6093 light = r_refdef.scene.lights[i];
6095 lightradius2 = light->radius * light->radius;
6096 VectorSubtract(light->shadoworigin, p, relativepoint);
6097 dist2 = VectorLength2(relativepoint);
6098 if (dist2 >= lightradius2)
6100 dist = sqrt(dist2) / light->radius;
6101 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6102 if (intensity <= 0.0f)
6104 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)
6106 for (q = 0; q < 3; q++)
6107 color[q] = light->currentcolor[q] * intensity;
6108 intensity = VectorLength(color);
6109 VectorNormalize(relativepoint);
6110 for (q = 0; q < 3; q++)
6112 sa[q] += 0.5f * color[q];
6113 sx[q] += relativepoint[0] * color[q];
6114 sy[q] += relativepoint[1] * color[q];
6115 sz[q] += relativepoint[2] * color[q];
6116 sd[q] += intensity * relativepoint[q];
6121 // calculate the weighted-average light direction (bentnormal)
6122 for (q = 0; q < 3; q++)
6123 lightdir[q] = sd[q];
6124 VectorNormalize(lightdir);
6125 for (q = 0; q < 3; q++)
6127 // extract the diffuse color along the chosen direction and scale it
6128 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6129 // subtract some of diffuse from ambient
6130 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;