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_dynamic_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color" };
198 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)"};
199 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"};
200 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"};
201 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
202 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)"};
203 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)"};
204 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"};
205 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)"};
206 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
207 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"};
208 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
209 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
210 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
211 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"};
212 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)"};
213 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "1", "overall brightness of bouncegrid texture"};
214 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"};
215 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)" };
216 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"};
217 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
218 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" };
219 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)" };
220 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
221 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" };
222 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
223 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"};
224 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"};
225 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
226 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)" };
227 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
228 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
229 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"};
230 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"};
231 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
232 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
233 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
234 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
235 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
236 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
237 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
238 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
239 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
240 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
241 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
242 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
243 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
244 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
245 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
246 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
247 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
248 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
249 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
250 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
251 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
252 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
254 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
256 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
257 #define ATTENTABLESIZE 256
258 // 1D gradient, 2D circle and 3D sphere attenuation textures
259 #define ATTEN1DSIZE 32
260 #define ATTEN2DSIZE 64
261 #define ATTEN3DSIZE 32
263 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
264 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
265 static float r_shadow_attentable[ATTENTABLESIZE+1];
267 rtlight_t *r_shadow_compilingrtlight;
268 static memexpandablearray_t r_shadow_worldlightsarray;
269 dlight_t *r_shadow_selectedlight;
270 dlight_t r_shadow_bufferlight;
271 vec3_t r_editlights_cursorlocation;
272 qboolean r_editlights_lockcursor;
274 extern int con_vislines;
276 void R_Shadow_UncompileWorldLights(void);
277 void R_Shadow_ClearWorldLights(void);
278 void R_Shadow_SaveWorldLights(void);
279 void R_Shadow_LoadWorldLights(void);
280 void R_Shadow_LoadLightsFile(void);
281 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
282 void R_Shadow_EditLights_Reload_f(void);
283 static void R_Shadow_MakeTextures(void);
285 #define EDLIGHTSPRSIZE 8
286 skinframe_t *r_editlights_sprcursor;
287 skinframe_t *r_editlights_sprlight;
288 skinframe_t *r_editlights_sprnoshadowlight;
289 skinframe_t *r_editlights_sprcubemaplight;
290 skinframe_t *r_editlights_sprcubemapnoshadowlight;
291 skinframe_t *r_editlights_sprselection;
293 static void R_Shadow_DrawModelShadowMaps(void);
294 static void R_Shadow_MakeShadowMap(int texturesize);
295 static void R_Shadow_MakeVSDCT(void);
296 static void R_Shadow_SetShadowMode(void)
298 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
299 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
300 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
301 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
302 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
303 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
304 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
305 r_shadow_shadowmapsampler = false;
306 r_shadow_shadowmappcf = 0;
307 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
308 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
309 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
310 if (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)
312 switch(vid.renderpath)
314 case RENDERPATH_GL32:
315 if(r_shadow_shadowmapfilterquality < 0)
317 if (!r_fb.usedepthtextures)
318 r_shadow_shadowmappcf = 1;
319 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
321 r_shadow_shadowmapsampler = true;
322 r_shadow_shadowmappcf = 1;
324 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
325 r_shadow_shadowmappcf = 1;
326 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
327 r_shadow_shadowmappcf = 1;
329 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
333 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
334 switch (r_shadow_shadowmapfilterquality)
339 r_shadow_shadowmappcf = 1;
342 r_shadow_shadowmappcf = 1;
345 r_shadow_shadowmappcf = 2;
349 if (!r_fb.usedepthtextures)
350 r_shadow_shadowmapsampler = false;
351 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
353 case RENDERPATH_GLES2:
358 if(R_CompileShader_CheckStaticParms())
362 qboolean R_Shadow_ShadowMappingEnabled(void)
364 switch (r_shadow_shadowmode)
366 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
373 static void R_Shadow_FreeShadowMaps(void)
375 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
377 R_Shadow_SetShadowMode();
379 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
383 if (r_shadow_shadowmap2ddepthtexture)
384 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
385 r_shadow_shadowmap2ddepthtexture = NULL;
387 if (r_shadow_shadowmap2ddepthbuffer)
388 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
389 r_shadow_shadowmap2ddepthbuffer = NULL;
391 if (r_shadow_shadowmapvsdcttexture)
392 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
393 r_shadow_shadowmapvsdcttexture = NULL;
396 static void r_shadow_start(void)
398 // allocate vertex processing arrays
399 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
400 r_shadow_attenuationgradienttexture = NULL;
401 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
402 r_shadow_shadowmap2ddepthtexture = NULL;
403 r_shadow_shadowmap2ddepthbuffer = NULL;
404 r_shadow_shadowmapvsdcttexture = NULL;
405 r_shadow_shadowmapmaxsize = 0;
406 r_shadow_shadowmaptexturesize = 0;
407 r_shadow_shadowmapfilterquality = -1;
408 r_shadow_shadowmapdepthbits = 0;
409 r_shadow_shadowmapvsdct = false;
410 r_shadow_shadowmapsampler = false;
411 r_shadow_shadowmappcf = 0;
414 R_Shadow_FreeShadowMaps();
416 r_shadow_texturepool = NULL;
417 r_shadow_filters_texturepool = NULL;
418 R_Shadow_MakeTextures();
419 r_shadow_scenemaxlights = 0;
420 r_shadow_scenenumlights = 0;
421 r_shadow_scenelightlist = NULL;
422 maxshadowtriangles = 0;
423 shadowelements = NULL;
424 maxshadowvertices = 0;
425 shadowvertex3f = NULL;
433 shadowmarklist = NULL;
438 shadowsideslist = NULL;
439 r_shadow_buffer_numleafpvsbytes = 0;
440 r_shadow_buffer_visitingleafpvs = NULL;
441 r_shadow_buffer_leafpvs = NULL;
442 r_shadow_buffer_leaflist = NULL;
443 r_shadow_buffer_numsurfacepvsbytes = 0;
444 r_shadow_buffer_surfacepvs = NULL;
445 r_shadow_buffer_surfacelist = NULL;
446 r_shadow_buffer_surfacesides = NULL;
447 r_shadow_buffer_numshadowtrispvsbytes = 0;
448 r_shadow_buffer_shadowtrispvs = NULL;
449 r_shadow_buffer_numlighttrispvsbytes = 0;
450 r_shadow_buffer_lighttrispvs = NULL;
452 r_shadow_usingdeferredprepass = false;
453 r_shadow_prepass_width = r_shadow_prepass_height = 0;
455 // determine renderpath specific capabilities, we don't need to figure
456 // these out per frame...
457 switch(vid.renderpath)
459 case RENDERPATH_GL32:
460 r_shadow_bouncegrid_state.allowdirectionalshading = true;
461 r_shadow_bouncegrid_state.capable = true;
463 case RENDERPATH_GLES2:
464 // for performance reasons, do not use directional shading on GLES devices
465 r_shadow_bouncegrid_state.capable = true;
470 static void R_Shadow_FreeDeferred(void);
471 static void r_shadow_shutdown(void)
474 R_Shadow_UncompileWorldLights();
476 R_Shadow_FreeShadowMaps();
478 r_shadow_usingdeferredprepass = false;
479 if (r_shadow_prepass_width)
480 R_Shadow_FreeDeferred();
481 r_shadow_prepass_width = r_shadow_prepass_height = 0;
484 r_shadow_scenemaxlights = 0;
485 r_shadow_scenenumlights = 0;
486 if (r_shadow_scenelightlist)
487 Mem_Free(r_shadow_scenelightlist);
488 r_shadow_scenelightlist = NULL;
489 r_shadow_bouncegrid_state.highpixels = NULL;
490 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
491 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
492 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
493 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
494 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
495 r_shadow_bouncegrid_state.maxsplatpaths = 0;
496 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
497 r_shadow_attenuationgradienttexture = NULL;
498 R_FreeTexturePool(&r_shadow_texturepool);
499 R_FreeTexturePool(&r_shadow_filters_texturepool);
500 maxshadowtriangles = 0;
502 Mem_Free(shadowelements);
503 shadowelements = NULL;
505 Mem_Free(shadowvertex3f);
506 shadowvertex3f = NULL;
509 Mem_Free(vertexupdate);
512 Mem_Free(vertexremap);
518 Mem_Free(shadowmark);
521 Mem_Free(shadowmarklist);
522 shadowmarklist = NULL;
527 Mem_Free(shadowsides);
530 Mem_Free(shadowsideslist);
531 shadowsideslist = NULL;
532 r_shadow_buffer_numleafpvsbytes = 0;
533 if (r_shadow_buffer_visitingleafpvs)
534 Mem_Free(r_shadow_buffer_visitingleafpvs);
535 r_shadow_buffer_visitingleafpvs = NULL;
536 if (r_shadow_buffer_leafpvs)
537 Mem_Free(r_shadow_buffer_leafpvs);
538 r_shadow_buffer_leafpvs = NULL;
539 if (r_shadow_buffer_leaflist)
540 Mem_Free(r_shadow_buffer_leaflist);
541 r_shadow_buffer_leaflist = NULL;
542 r_shadow_buffer_numsurfacepvsbytes = 0;
543 if (r_shadow_buffer_surfacepvs)
544 Mem_Free(r_shadow_buffer_surfacepvs);
545 r_shadow_buffer_surfacepvs = NULL;
546 if (r_shadow_buffer_surfacelist)
547 Mem_Free(r_shadow_buffer_surfacelist);
548 r_shadow_buffer_surfacelist = NULL;
549 if (r_shadow_buffer_surfacesides)
550 Mem_Free(r_shadow_buffer_surfacesides);
551 r_shadow_buffer_surfacesides = NULL;
552 r_shadow_buffer_numshadowtrispvsbytes = 0;
553 if (r_shadow_buffer_shadowtrispvs)
554 Mem_Free(r_shadow_buffer_shadowtrispvs);
555 r_shadow_buffer_numlighttrispvsbytes = 0;
556 if (r_shadow_buffer_lighttrispvs)
557 Mem_Free(r_shadow_buffer_lighttrispvs);
560 static void r_shadow_newmap(void)
562 r_shadow_bouncegrid_state.highpixels = NULL;
563 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
564 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
565 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
566 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
567 if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
569 r_shadow_bouncegrid_state.maxsplatpaths = 0;
571 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
572 if (r_shadow_lightcorona) { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
573 if (r_editlights_sprcursor) { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
574 if (r_editlights_sprlight) { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
575 if (r_editlights_sprnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
576 if (r_editlights_sprcubemaplight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
577 if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
578 if (r_editlights_sprselection) { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
579 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
580 R_Shadow_EditLights_Reload_f();
583 void R_Shadow_Init(void)
585 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
586 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
587 Cvar_RegisterVariable(&r_shadow_usebihculling);
588 Cvar_RegisterVariable(&r_shadow_usenormalmap);
589 Cvar_RegisterVariable(&r_shadow_debuglight);
590 Cvar_RegisterVariable(&r_shadow_deferred);
591 Cvar_RegisterVariable(&r_shadow_gloss);
592 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
593 Cvar_RegisterVariable(&r_shadow_glossintensity);
594 Cvar_RegisterVariable(&r_shadow_glossexponent);
595 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
596 Cvar_RegisterVariable(&r_shadow_glossexact);
597 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
598 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
599 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
600 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
601 Cvar_RegisterVariable(&r_shadow_projectdistance);
602 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
603 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
604 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
605 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
606 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
607 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
608 Cvar_RegisterVariable(&r_shadow_realtime_world);
609 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
610 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
611 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
612 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
613 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
614 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
615 Cvar_RegisterVariable(&r_shadow_scissor);
616 Cvar_RegisterVariable(&r_shadow_shadowmapping);
617 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
618 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
619 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
620 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
621 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
622 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
623 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
624 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
625 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
626 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
627 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
628 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
629 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
630 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
631 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
632 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
633 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
634 Cvar_RegisterVariable(&r_shadow_culllights_trace);
635 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
636 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
637 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
638 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
639 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
640 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
641 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
642 Cvar_RegisterVariable(&r_shadow_bouncegrid);
643 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
644 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
645 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
646 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
647 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
648 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
649 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
650 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
651 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
652 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
653 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
654 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
655 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
656 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
657 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
658 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
659 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
660 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
661 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
662 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
663 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
664 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
665 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
666 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
667 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
668 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
669 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
670 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
671 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
672 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
673 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
674 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
675 Cvar_RegisterVariable(&r_coronas);
676 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
677 Cvar_RegisterVariable(&r_coronas_occlusionquery);
678 Cvar_RegisterVariable(&gl_flashblend);
679 R_Shadow_EditLights_Init();
680 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
681 r_shadow_scenemaxlights = 0;
682 r_shadow_scenenumlights = 0;
683 r_shadow_scenelightlist = NULL;
684 maxshadowtriangles = 0;
685 shadowelements = NULL;
686 maxshadowvertices = 0;
687 shadowvertex3f = NULL;
695 shadowmarklist = NULL;
700 shadowsideslist = NULL;
701 r_shadow_buffer_numleafpvsbytes = 0;
702 r_shadow_buffer_visitingleafpvs = NULL;
703 r_shadow_buffer_leafpvs = NULL;
704 r_shadow_buffer_leaflist = NULL;
705 r_shadow_buffer_numsurfacepvsbytes = 0;
706 r_shadow_buffer_surfacepvs = NULL;
707 r_shadow_buffer_surfacelist = NULL;
708 r_shadow_buffer_surfacesides = NULL;
709 r_shadow_buffer_shadowtrispvs = NULL;
710 r_shadow_buffer_lighttrispvs = NULL;
711 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
714 matrix4x4_t matrix_attenuationxyz =
717 {0.5, 0.0, 0.0, 0.5},
718 {0.0, 0.5, 0.0, 0.5},
719 {0.0, 0.0, 0.5, 0.5},
724 matrix4x4_t matrix_attenuationz =
727 {0.0, 0.0, 0.5, 0.5},
728 {0.0, 0.0, 0.0, 0.5},
729 {0.0, 0.0, 0.0, 0.5},
734 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
736 numvertices = ((numvertices + 255) & ~255) * vertscale;
737 numtriangles = ((numtriangles + 255) & ~255) * triscale;
738 // make sure shadowelements is big enough for this volume
739 if (maxshadowtriangles < numtriangles)
741 maxshadowtriangles = numtriangles;
743 Mem_Free(shadowelements);
744 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
746 // make sure shadowvertex3f is big enough for this volume
747 if (maxshadowvertices < numvertices)
749 maxshadowvertices = numvertices;
751 Mem_Free(shadowvertex3f);
752 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
756 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
758 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
759 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
760 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
761 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
762 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
764 if (r_shadow_buffer_visitingleafpvs)
765 Mem_Free(r_shadow_buffer_visitingleafpvs);
766 if (r_shadow_buffer_leafpvs)
767 Mem_Free(r_shadow_buffer_leafpvs);
768 if (r_shadow_buffer_leaflist)
769 Mem_Free(r_shadow_buffer_leaflist);
770 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
771 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
772 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
773 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
775 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
777 if (r_shadow_buffer_surfacepvs)
778 Mem_Free(r_shadow_buffer_surfacepvs);
779 if (r_shadow_buffer_surfacelist)
780 Mem_Free(r_shadow_buffer_surfacelist);
781 if (r_shadow_buffer_surfacesides)
782 Mem_Free(r_shadow_buffer_surfacesides);
783 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
784 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
785 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
786 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
788 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
790 if (r_shadow_buffer_shadowtrispvs)
791 Mem_Free(r_shadow_buffer_shadowtrispvs);
792 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
793 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
795 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
797 if (r_shadow_buffer_lighttrispvs)
798 Mem_Free(r_shadow_buffer_lighttrispvs);
799 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
800 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
804 void R_Shadow_PrepareShadowMark(int numtris)
806 // make sure shadowmark is big enough for this volume
807 if (maxshadowmark < numtris)
809 maxshadowmark = numtris;
811 Mem_Free(shadowmark);
813 Mem_Free(shadowmarklist);
814 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
815 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
819 // if shadowmarkcount wrapped we clear the array and adjust accordingly
820 if (shadowmarkcount == 0)
823 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
828 void R_Shadow_PrepareShadowSides(int numtris)
830 if (maxshadowsides < numtris)
832 maxshadowsides = numtris;
834 Mem_Free(shadowsides);
836 Mem_Free(shadowsideslist);
837 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
838 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
843 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
845 // p1, p2, p3 are in the cubemap's local coordinate system
846 // bias = border/(size - border)
849 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
850 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
851 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
852 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
854 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
855 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
856 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
857 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
859 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
860 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
861 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
863 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
864 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
865 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
866 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
868 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
869 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
870 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
871 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
873 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
874 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
875 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
877 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
878 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
879 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
880 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
882 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
883 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
884 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
885 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
887 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
888 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
889 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
894 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
896 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
897 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
900 VectorSubtract(maxs, mins, radius);
901 VectorScale(radius, 0.5f, radius);
902 VectorAdd(mins, radius, center);
903 Matrix4x4_Transform(worldtolight, center, lightcenter);
904 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
905 VectorSubtract(lightcenter, lightradius, pmin);
906 VectorAdd(lightcenter, lightradius, pmax);
908 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
909 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
910 if(ap1 > bias*an1 && ap2 > bias*an2)
912 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
913 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
914 if(an1 > bias*ap1 && an2 > bias*ap2)
916 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
917 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
919 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
920 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
921 if(ap1 > bias*an1 && ap2 > bias*an2)
923 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
924 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
925 if(an1 > bias*ap1 && an2 > bias*ap2)
927 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
928 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
930 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
931 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
932 if(ap1 > bias*an1 && ap2 > bias*an2)
934 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
935 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
936 if(an1 > bias*ap1 && an2 > bias*ap2)
938 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
939 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
944 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
946 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
948 // p is in the cubemap's local coordinate system
949 // bias = border/(size - border)
950 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
951 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
952 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
954 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
955 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
956 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
957 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
958 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
959 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
963 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
967 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
968 float scale = (size - 2*border)/size, len;
969 float bias = border / (float)(size - border), dp, dn, ap, an;
970 // check if cone enclosing side would cross frustum plane
971 scale = 2 / (scale*scale + 2);
972 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
973 for (i = 0;i < 5;i++)
975 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
977 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
978 len = scale*VectorLength2(n);
979 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
980 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
981 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
983 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
985 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
986 len = scale*VectorLength2(n);
987 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
988 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
989 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
991 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
992 // check if frustum corners/origin cross plane sides
994 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
995 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
996 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
997 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
998 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
999 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1000 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1001 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1002 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1003 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1004 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1005 for (i = 0;i < 4;i++)
1007 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1008 VectorSubtract(n, p, n);
1009 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1010 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1011 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1012 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1013 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1014 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1015 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1016 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1017 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1020 // finite version, assumes corners are a finite distance from origin dependent on far plane
1021 for (i = 0;i < 5;i++)
1023 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1024 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1025 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1026 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1027 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1028 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1029 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1030 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1031 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1032 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1035 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1038 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)
1046 int mask, surfacemask = 0;
1047 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1049 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1050 tend = firsttriangle + numtris;
1051 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1053 // surface box entirely inside light box, no box cull
1054 if (projectdirection)
1056 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1058 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1059 TriangleNormal(v[0], v[1], v[2], normal);
1060 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1062 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1063 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1064 surfacemask |= mask;
1067 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;
1068 shadowsides[numshadowsides] = mask;
1069 shadowsideslist[numshadowsides++] = t;
1076 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1078 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1079 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1081 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1082 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1083 surfacemask |= mask;
1086 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;
1087 shadowsides[numshadowsides] = mask;
1088 shadowsideslist[numshadowsides++] = t;
1096 // surface box not entirely inside light box, cull each triangle
1097 if (projectdirection)
1099 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1101 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1102 TriangleNormal(v[0], v[1], v[2], normal);
1103 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1104 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1106 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1107 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1108 surfacemask |= mask;
1111 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;
1112 shadowsides[numshadowsides] = mask;
1113 shadowsideslist[numshadowsides++] = t;
1120 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1122 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1123 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1124 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1126 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1127 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1128 surfacemask |= mask;
1131 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;
1132 shadowsides[numshadowsides] = mask;
1133 shadowsideslist[numshadowsides++] = t;
1142 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)
1144 int i, j, outtriangles = 0;
1145 int *outelement3i[6];
1146 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1148 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1149 // make sure shadowelements is big enough for this mesh
1150 if (maxshadowtriangles < outtriangles)
1151 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1153 // compute the offset and size of the separate index lists for each cubemap side
1155 for (i = 0;i < 6;i++)
1157 outelement3i[i] = shadowelements + outtriangles * 3;
1158 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1159 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1160 outtriangles += sidetotals[i];
1163 // gather up the (sparse) triangles into separate index lists for each cubemap side
1164 for (i = 0;i < numsidetris;i++)
1166 const int *element = elements + sidetris[i] * 3;
1167 for (j = 0;j < 6;j++)
1169 if (sides[i] & (1 << j))
1171 outelement3i[j][0] = element[0];
1172 outelement3i[j][1] = element[1];
1173 outelement3i[j][2] = element[2];
1174 outelement3i[j] += 3;
1179 Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1182 static void R_Shadow_MakeTextures_MakeCorona(void)
1186 unsigned char pixels[32][32][4];
1187 for (y = 0;y < 32;y++)
1189 dy = (y - 15.5f) * (1.0f / 16.0f);
1190 for (x = 0;x < 32;x++)
1192 dx = (x - 15.5f) * (1.0f / 16.0f);
1193 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1194 a = bound(0, a, 255);
1195 pixels[y][x][0] = a;
1196 pixels[y][x][1] = a;
1197 pixels[y][x][2] = a;
1198 pixels[y][x][3] = 255;
1201 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1204 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1206 float dist = sqrt(x*x+y*y+z*z);
1207 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1208 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1209 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1212 static void R_Shadow_MakeTextures(void)
1215 float intensity, dist;
1217 R_Shadow_FreeShadowMaps();
1218 R_FreeTexturePool(&r_shadow_texturepool);
1219 r_shadow_texturepool = R_AllocTexturePool();
1220 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1221 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1222 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1223 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1224 for (x = 0;x <= ATTENTABLESIZE;x++)
1226 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1227 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1228 r_shadow_attentable[x] = bound(0, intensity, 1);
1230 // 1D gradient texture
1231 for (x = 0;x < ATTEN1DSIZE;x++)
1232 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1233 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1236 R_Shadow_MakeTextures_MakeCorona();
1238 // Editor light sprites
1239 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1256 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1257 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1274 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1275 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1292 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1293 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1310 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1311 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1328 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1329 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1346 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1349 void R_Shadow_RenderMode_Begin(void)
1356 if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1357 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1358 R_Shadow_MakeTextures();
1361 R_Mesh_ResetTextureState();
1362 GL_BlendFunc(GL_ONE, GL_ZERO);
1363 GL_DepthRange(0, 1);
1364 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1366 GL_DepthMask(false);
1367 GL_Color(0, 0, 0, 1);
1368 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1370 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1371 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1375 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1376 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1377 r_shadow_drawbuffer = drawbuffer;
1378 r_shadow_readbuffer = readbuffer;
1380 r_shadow_cullface_front = r_refdef.view.cullface_front;
1381 r_shadow_cullface_back = r_refdef.view.cullface_back;
1384 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1386 rsurface.rtlight = rtlight;
1389 void R_Shadow_RenderMode_Reset(void)
1391 R_Mesh_ResetTextureState();
1392 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1393 R_SetViewport(&r_refdef.view.viewport);
1394 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1395 GL_DepthRange(0, 1);
1397 GL_DepthMask(false);
1398 GL_DepthFunc(GL_LEQUAL);
1399 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1400 r_refdef.view.cullface_front = r_shadow_cullface_front;
1401 r_refdef.view.cullface_back = r_shadow_cullface_back;
1402 GL_CullFace(r_refdef.view.cullface_back);
1403 GL_Color(1, 1, 1, 1);
1404 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1405 GL_BlendFunc(GL_ONE, GL_ZERO);
1406 R_SetupShader_Generic_NoTexture(false, false);
1407 r_shadow_usingshadowmap2d = false;
1410 void R_Shadow_ClearStencil(void)
1412 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1413 r_refdef.stats[r_stat_lights_clears]++;
1416 static void R_Shadow_MakeVSDCT(void)
1418 // maps to a 2x3 texture rectangle with normalized coordinates
1423 // stores abs(dir.xy), offset.xy/2.5
1424 unsigned char data[4*6] =
1426 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1427 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1428 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1429 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1430 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1431 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1433 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1436 static void R_Shadow_MakeShadowMap(int texturesize)
1438 switch (r_shadow_shadowmode)
1440 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1441 if (r_shadow_shadowmap2ddepthtexture) return;
1442 if (r_fb.usedepthtextures)
1444 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);
1445 r_shadow_shadowmap2ddepthbuffer = NULL;
1446 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1450 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1451 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1452 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1460 void R_Shadow_ClearShadowMapTexture(void)
1462 r_viewport_t viewport;
1463 float clearcolor[4];
1465 // if they don't exist, create our textures now
1466 if (!r_shadow_shadowmap2ddepthtexture)
1467 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1468 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1469 R_Shadow_MakeVSDCT();
1471 // we're setting up to render shadowmaps, so change rendermode
1472 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1474 R_Mesh_ResetTextureState();
1475 R_Shadow_RenderMode_Reset();
1476 if (r_shadow_shadowmap2ddepthbuffer)
1477 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1479 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1480 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1481 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1485 // we have to set a viewport to clear anything in some renderpaths (D3D)
1486 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1487 R_SetViewport(&viewport);
1488 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1489 if (r_shadow_shadowmap2ddepthbuffer)
1490 GL_ColorMask(1, 1, 1, 1);
1492 GL_ColorMask(0, 0, 0, 0);
1493 switch (vid.renderpath)
1495 case RENDERPATH_GL32:
1496 case RENDERPATH_GLES2:
1497 GL_CullFace(r_refdef.view.cullface_back);
1500 Vector4Set(clearcolor, 1, 1, 1, 1);
1501 if (r_shadow_shadowmap2ddepthbuffer)
1502 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1504 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1507 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1509 int size = rsurface.rtlight->shadowmapatlassidesize;
1510 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1511 float farclip = 1.0f;
1512 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1513 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1514 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1515 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1516 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1517 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1518 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1519 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1520 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1521 if (r_shadow_shadowmap2ddepthbuffer)
1523 // completely different meaning than in depthtexture approach
1524 r_shadow_lightshadowmap_parameters[1] = 0;
1525 r_shadow_lightshadowmap_parameters[3] = -bias;
1529 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1531 float nearclip, farclip, bias;
1532 r_viewport_t viewport;
1534 float clearcolor[4];
1536 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1538 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1540 R_Mesh_ResetTextureState();
1541 R_Shadow_RenderMode_Reset();
1542 if (r_shadow_shadowmap2ddepthbuffer)
1543 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1545 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1546 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1547 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1552 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1554 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1556 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1557 R_SetViewport(&viewport);
1558 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1559 flipped = (side & 1) ^ (side >> 2);
1560 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1561 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1563 Vector4Set(clearcolor, 1,1,1,1);
1564 if (r_shadow_shadowmap2ddepthbuffer)
1565 GL_ColorMask(1,1,1,1);
1567 GL_ColorMask(0,0,0,0);
1568 switch(vid.renderpath)
1570 case RENDERPATH_GL32:
1571 case RENDERPATH_GLES2:
1572 GL_CullFace(r_refdef.view.cullface_back);
1576 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1577 r_shadow_shadowmapside = side;
1580 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1582 R_Mesh_ResetTextureState();
1585 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1586 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1587 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1588 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1591 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1592 R_Shadow_RenderMode_Reset();
1593 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1595 GL_DepthFunc(GL_EQUAL);
1596 // do global setup needed for the chosen lighting mode
1597 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1598 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1599 r_shadow_usingshadowmap2d = shadowmapping;
1600 r_shadow_rendermode = r_shadow_lightingrendermode;
1603 static const unsigned short bboxelements[36] =
1613 static const float bboxpoints[8][3] =
1625 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1628 float vertex3f[8*3];
1629 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1630 // do global setup needed for the chosen lighting mode
1631 R_Shadow_RenderMode_Reset();
1632 r_shadow_rendermode = r_shadow_lightingrendermode;
1633 R_EntityMatrix(&identitymatrix);
1634 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1635 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1636 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1638 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1640 r_shadow_usingshadowmap2d = shadowmapping;
1642 // render the lighting
1643 R_SetupShader_DeferredLight(rsurface.rtlight);
1644 for (i = 0;i < 8;i++)
1645 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1646 GL_ColorMask(1,1,1,1);
1647 GL_DepthMask(false);
1648 GL_DepthRange(0, 1);
1649 GL_PolygonOffset(0, 0);
1651 GL_DepthFunc(GL_GREATER);
1652 GL_CullFace(r_refdef.view.cullface_back);
1653 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1654 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1657 #define MAXBOUNCEGRIDSPLATSIZE 7
1658 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
1660 // these are temporary data per-frame, to be cache friendly the texture is
1661 // generated in slices (on Z), rendering each slice one after another and each
1662 // row in the slice one after another to be more cache friendly than randomly
1663 // seeking around a large memory space. Each slice keeps track of a linked list
1664 // of splat paths that are relevant to it. Also these are canonically flipped
1665 // to ensure that start[2] <= end[2].
1666 typedef struct r_shadow_bouncegrid_splatpath_s
1668 int nextpathonslice;
1675 vec_t splatintensity;
1676 vec_t splatsize_current;
1677 vec_t splatsize_perstep;
1679 r_shadow_bouncegrid_splatpath_t;
1681 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
1686 r_shadow_bouncegrid_splatpath_t *path;
1688 // cull paths that fail R_CullBox in dynamic mode
1689 if (!r_shadow_bouncegrid_state.settings.staticmode
1690 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
1692 vec3_t cullmins, cullmaxs;
1693 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
1694 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
1695 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
1696 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
1697 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
1698 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
1699 if (R_CullBox(cullmins, cullmaxs))
1703 // if the light path is going upward, reverse it - we always draw down.
1704 if (originalend[2] < originalstart[2])
1706 VectorCopy(originalend, start);
1707 VectorCopy(originalstart, end);
1711 VectorCopy(originalstart, start);
1712 VectorCopy(originalend, end);
1715 // transform to texture pixels
1716 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]);
1717 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]);
1718 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]);
1719 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]);
1720 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]);
1721 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]);
1723 // check if we need to grow the splatpaths array
1724 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
1726 // double the limit, this will persist from frame to frame so we don't
1727 // make the same mistake each time
1728 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
1729 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
1730 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
1731 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);
1734 VectorSubtract(originalstart, originalend, originaldir);
1735 VectorNormalize(originaldir);
1737 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
1738 VectorCopy(start, path->start);
1739 VectorCopy(end, path->end);
1740 VectorCopy(color, path->splatcolor);
1741 VectorCopy(originaldir, path->splatdir);
1742 path->splatintensity = VectorLength(color);
1745 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1747 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1754 // see if there are really any lights to render...
1755 if (enable && r_shadow_bouncegrid_static.integer)
1758 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1759 for (lightindex = 0;lightindex < range;lightindex++)
1761 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1762 if (!light || !(light->flags & flag))
1764 rtlight = &light->rtlight;
1765 // when static, we skip styled lights because they tend to change...
1766 if (rtlight->style > 0)
1768 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1769 if (!VectorLength2(lightcolor))
1779 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1781 qboolean s = r_shadow_bouncegrid_static.integer != 0;
1782 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1783 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1784 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1786 // prevent any garbage in alignment padded areas as we'll be using memcmp
1787 memset(settings, 0, sizeof(*settings));
1789 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1790 settings->staticmode = s;
1791 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1792 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1793 settings->lightpathsize = bound(0.0f, r_shadow_bouncegrid_lightpathsize.value, 1024.0f);
1794 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1795 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1796 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1797 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1798 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1799 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1800 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1801 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) / 65536.0f;
1802 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1803 settings->energyperphoton = 4096.0f / quality;
1804 settings->spacing[0] = spacing;
1805 settings->spacing[1] = spacing;
1806 settings->spacing[2] = spacing;
1807 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1808 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1809 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1810 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1811 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1813 // bound the values for sanity
1814 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1815 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1816 settings->maxbounce = bound(0, settings->maxbounce, 16);
1817 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1818 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1819 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1822 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1833 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1835 // get the spacing values
1836 spacing[0] = settings->spacing[0];
1837 spacing[1] = settings->spacing[1];
1838 spacing[2] = settings->spacing[2];
1839 ispacing[0] = 1.0f / spacing[0];
1840 ispacing[1] = 1.0f / spacing[1];
1841 ispacing[2] = 1.0f / spacing[2];
1843 // calculate texture size enclosing entire world bounds at the spacing
1844 if (r_refdef.scene.worldmodel)
1848 qboolean bounds_set = false;
1852 // calculate bounds enclosing world lights as they should be noticably tighter
1853 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1854 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1855 for (lightindex = 0;lightindex < range;lightindex++)
1857 const vec_t *rtlmins, *rtlmaxs;
1859 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1863 rtlight = &light->rtlight;
1864 rtlmins = rtlight->cullmins;
1865 rtlmaxs = rtlight->cullmaxs;
1869 VectorCopy(rtlmins, mins);
1870 VectorCopy(rtlmaxs, maxs);
1875 mins[0] = min(mins[0], rtlmins[0]);
1876 mins[1] = min(mins[1], rtlmins[1]);
1877 mins[2] = min(mins[2], rtlmins[2]);
1878 maxs[0] = max(maxs[0], rtlmaxs[0]);
1879 maxs[1] = max(maxs[1], rtlmaxs[1]);
1880 maxs[2] = max(maxs[2], rtlmaxs[2]);
1884 // limit to no larger than the world bounds
1885 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1886 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1887 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1888 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1889 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1890 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1892 VectorMA(mins, -2.0f, spacing, mins);
1893 VectorMA(maxs, 2.0f, spacing, maxs);
1897 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1898 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1900 VectorSubtract(maxs, mins, size);
1901 // now we can calculate the resolution we want
1902 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1903 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1904 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1905 // figure out the exact texture size (honoring power of 2 if required)
1906 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1907 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1908 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1909 size[0] = spacing[0] * resolution[0];
1910 size[1] = spacing[1] * resolution[1];
1911 size[2] = spacing[2] * resolution[2];
1913 // if dynamic we may or may not want to use the world bounds
1914 // if the dynamic size is smaller than the world bounds, use it instead
1915 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]))
1917 // we know the resolution we want
1918 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1919 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1920 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1921 // now we can calculate the texture size
1922 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1923 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1924 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1925 size[0] = spacing[0] * resolution[0];
1926 size[1] = spacing[1] * resolution[1];
1927 size[2] = spacing[2] * resolution[2];
1928 // center the rendering on the view
1929 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1930 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1931 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1934 // recalculate the maxs in case the resolution was not satisfactory
1935 VectorAdd(mins, size, maxs);
1937 // check if this changed the texture size
1938 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);
1939 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1940 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1941 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1942 VectorCopy(size, r_shadow_bouncegrid_state.size);
1943 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1944 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1945 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1947 // reallocate pixels for this update if needed...
1948 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1949 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1950 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1951 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1952 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1954 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1956 r_shadow_bouncegrid_state.highpixels = NULL;
1958 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1959 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1960 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1961 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1962 if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
1964 r_shadow_bouncegrid_state.maxsplatpaths = 0;
1965 r_shadow_bouncegrid_state.numpixels = numpixels;
1968 // update the bouncegrid matrix to put it in the world properly
1969 memset(m, 0, sizeof(m));
1970 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1971 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1972 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1973 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1974 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1975 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1977 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1980 // enumerate world rtlights and sum the overall amount of light in the world,
1981 // from that we can calculate a scaling factor to fairly distribute photons
1982 // to all the lights
1984 // this modifies rtlight->photoncolor and rtlight->photons
1985 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
1987 float normalphotonscaling;
1988 float photonscaling;
1989 float photonintensity;
1990 float photoncount = 0.0f;
1991 float lightintensity;
1997 unsigned int lightindex;
2000 normalphotonscaling = 1.0f / max(0.0000001f, settings->energyperphoton);
2001 for (lightindex = 0;lightindex < range2;lightindex++)
2003 if (lightindex < range)
2005 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2008 rtlight = &light->rtlight;
2009 VectorClear(rtlight->bouncegrid_photoncolor);
2010 rtlight->bouncegrid_photons = 0;
2011 rtlight->bouncegrid_hits = 0;
2012 rtlight->bouncegrid_traces = 0;
2013 rtlight->bouncegrid_effectiveradius = 0;
2014 if (!(light->flags & flag))
2016 if (settings->staticmode)
2018 // when static, we skip styled lights because they tend to change...
2019 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2022 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2027 rtlight = r_refdef.scene.lights[lightindex - range];
2028 VectorClear(rtlight->bouncegrid_photoncolor);
2029 rtlight->bouncegrid_photons = 0;
2030 rtlight->bouncegrid_hits = 0;
2031 rtlight->bouncegrid_traces = 0;
2032 rtlight->bouncegrid_effectiveradius = 0;
2034 // draw only visible lights (major speedup)
2035 radius = rtlight->radius * settings->lightradiusscale;
2036 cullmins[0] = rtlight->shadoworigin[0] - radius;
2037 cullmins[1] = rtlight->shadoworigin[1] - radius;
2038 cullmins[2] = rtlight->shadoworigin[2] - radius;
2039 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2040 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2041 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2042 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2043 if (!settings->staticmode)
2045 // skip if the expanded light box does not touch any visible leafs
2046 if (r_refdef.scene.worldmodel
2047 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2048 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2050 // skip if the expanded light box is not visible to traceline
2051 // note that PrepareLight already did this check but for a smaller box, so we
2052 // end up casting more traces per frame per light when using bouncegrid, which
2053 // is probably fine (and they use the same timer)
2054 if (r_shadow_culllights_trace.integer)
2056 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))
2057 rtlight->trace_timer = realtime;
2058 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2061 // skip if expanded light box is offscreen
2062 if (R_CullBox(cullmins, cullmaxs))
2064 // skip if overall light intensity is zero
2065 if (w * VectorLength2(rtlight->color) == 0.0f)
2068 // a light that does not emit any light before style is applied, can be
2069 // skipped entirely (it may just be a corona)
2070 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2072 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2073 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2074 // skip lights that will emit no photons
2075 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2077 // shoot particles from this light
2078 // use a calculation for the number of particles that will not
2079 // vary with lightstyle, otherwise we get randomized particle
2080 // distribution, the seeded random is only consistent for a
2081 // consistent number of particles on this light...
2082 s = rtlight->radius;
2083 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2084 if (lightindex >= range)
2085 lightintensity *= settings->dlightparticlemultiplier;
2086 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2087 photoncount += rtlight->bouncegrid_photons;
2088 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2089 // if the lightstyle happens to be off right now, we can skip actually
2090 // firing the photons, but we did have to count them in the total.
2091 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2092 // rtlight->bouncegrid_photons = 0;
2094 // the user provided an energyperphoton value which we try to use
2095 // if that results in too many photons to shoot this frame, then we cap it
2096 // which causes photons to appear/disappear from frame to frame, so we don't
2097 // like doing that in the typical case
2098 photonscaling = 1.0f;
2099 photonintensity = 1.0f;
2100 if (photoncount > settings->maxphotons)
2102 photonscaling = settings->maxphotons / photoncount;
2103 photonintensity = 1.0f / photonscaling;
2106 // modify the lights to reflect our computed scaling
2107 for (lightindex = 0; lightindex < range2; lightindex++)
2109 if (lightindex < range)
2111 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2114 rtlight = &light->rtlight;
2117 rtlight = r_refdef.scene.lights[lightindex - range];
2118 rtlight->bouncegrid_photons *= photonscaling;
2119 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2123 static void R_Shadow_BounceGrid_ClearPixels(void)
2125 // clear the highpixels array we'll be accumulating into
2126 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2127 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2128 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2129 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2130 r_shadow_bouncegrid_state.highpixels_index = 0;
2131 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2132 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2135 static void R_Shadow_BounceGrid_PerformSplats(void)
2137 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2138 r_shadow_bouncegrid_splatpath_t *splatpath;
2139 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2140 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2142 int xi, yi, zi; // pixel increments
2143 float xf, yf, zf; // pixel centers
2144 float splatcolor[32] = { 0 };
2145 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2146 float iradius = 1.0f / radius;
2148 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2149 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2151 // we use these a lot, so get a local copy
2152 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2154 for (pathindex = 0, splatpath = splatpaths; pathindex < numsplatpaths; pathindex++, splatpath++)
2156 splatpath->slicerange[0] = (int)floor((min(splatpath->start[2], splatpath->end[2]) - radius) * r_shadow_bouncegrid_state.ispacing[2] - 0.5f);
2157 splatpath->slicerange[1] = (int)floor((max(splatpath->start[2], splatpath->end[2]) + radius) * r_shadow_bouncegrid_state.ispacing[2] - 0.5f + 1.0f);
2160 // 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)
2161 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])
2163 int slicefirstpathindex = -1;
2164 for (pathindex = 0, splatpath = splatpaths; pathindex < numsplatpaths; pathindex++, splatpath++)
2166 if (zi >= splatpath->slicerange[0] && zi < splatpath->slicerange[1])
2168 if (zf < splatpath->start[2])
2169 VectorCopy(splatpath->start, splatpath->slicecenter);
2170 else if (zf > splatpath->end[2])
2171 VectorCopy(splatpath->end, splatpath->slicecenter);
2174 float lerp = (zf - splatpath->start[2]) / (splatpath->end[2] - splatpath->start[2]);
2175 splatpath->slicecenter[2] = zf;
2176 splatpath->slicecenter[0] = splatpath->start[0] + lerp * (splatpath->end[0] - splatpath->start[0]);
2177 splatpath->slicecenter[1] = splatpath->start[1] + lerp * (splatpath->end[1] - splatpath->start[1]);
2179 float distz = (splatpath->slicecenter[2] - zf) * iradius;
2180 if (distz * distz < 1.0f)
2182 splatpath->nextpathonslice = slicefirstpathindex;
2183 slicefirstpathindex = pathindex;
2187 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])
2189 for (pathindex = slicefirstpathindex; pathindex >= 0; pathindex = splatpaths[pathindex].nextpathonslice)
2191 splatpath = splatpaths + pathindex;
2192 float disty = (splatpath->slicecenter[1] - yf) * iradius;
2193 float distz = (splatpath->slicecenter[2] - zf) * iradius;
2194 float distyz = disty * disty + distz * distz;
2197 int xstart = (int)floor((splatpath->slicecenter[0] - radius) * r_shadow_bouncegrid_state.ispacing[0] - 0.5f);
2198 int xend = (int)floor((splatpath->slicecenter[0] + radius) * r_shadow_bouncegrid_state.ispacing[0] - 0.5f + 1.0f);
2200 xstart = max(1, xstart);
2201 xend = min(resolution[0] - 2, xend);
2204 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2205 // accumulate average shotcolor
2206 VectorCopy(splatpath->splatdir, dir);
2207 splatcolor[0] = splatpath->splatcolor[0];
2208 splatcolor[1] = splatpath->splatcolor[1];
2209 splatcolor[2] = splatpath->splatcolor[2];
2210 splatcolor[3] = 0.0f;
2213 // store bentnormal in case the shader has a use for it,
2214 // bentnormal is an intensity-weighted average of the directions,
2215 // and will be normalized on conversion to texture pixels.
2216 splatcolor[4] = dir[0] * splatpath->splatintensity;
2217 splatcolor[5] = dir[1] * splatpath->splatintensity;
2218 splatcolor[6] = dir[2] * splatpath->splatintensity;
2219 splatcolor[7] = splatpath->splatintensity;
2220 // for each color component (R, G, B) calculate the amount that a
2221 // direction contributes
2222 splatcolor[8] = splatcolor[0] * max(0.0f, dir[0]);
2223 splatcolor[9] = splatcolor[0] * max(0.0f, dir[1]);
2224 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2225 splatcolor[11] = 0.0f;
2226 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2227 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2228 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2229 splatcolor[15] = 0.0f;
2230 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2231 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2232 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2233 splatcolor[19] = 0.0f;
2234 // and do the same for negative directions
2235 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2236 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2237 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2238 splatcolor[23] = 0.0f;
2239 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2240 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2241 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2242 splatcolor[27] = 0.0f;
2243 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2244 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2245 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2246 splatcolor[31] = 0.0f;
2248 for (xi = xstart, xf = (xi + 0.5f) * r_shadow_bouncegrid_state.spacing[0]; xi < xend; xi++, xf += r_shadow_bouncegrid_state.spacing[0])
2250 float distx = (splatpath->slicecenter[0] - xf) * iradius;
2251 float distxyz = (distx * distx + distyz);
2254 // contribute some color to this pixel, across all bands
2255 float w = 1.0f - 1.0f * sqrt(distxyz);
2257 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2261 // small optimization for alpha - only splatcolor[7] is non-zero, so skip the rest of the alpha elements.
2262 p[pixelsperband * 4 + 3] += splatcolor[7] * w;
2264 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
2266 // add to the pixel color (RGB only - see above)
2267 p[0] += splatcolor[band * 4 + 0] * w;
2268 p[1] += splatcolor[band * 4 + 1] * w;
2269 p[2] += splatcolor[band * 4 + 2] * w;
2279 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2281 const float *inpixel;
2283 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2286 unsigned int x, y, z;
2287 unsigned int resolution[3];
2288 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2289 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2291 for (z = 1;z < resolution[2]-1;z++)
2293 for (y = 1;y < resolution[1]-1;y++)
2296 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2297 inpixel = inpixels + 4*index;
2298 outpixel = outpixels + 4*index;
2299 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2301 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2302 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2303 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2304 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2311 static void R_Shadow_BounceGrid_BlurPixels(void)
2314 unsigned int resolution[3];
2316 if (!r_shadow_bouncegrid_state.settings.blur)
2319 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2321 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2322 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2323 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2324 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2327 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2329 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2331 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2333 // toggle the state, highpixels now points to pixels[3] result
2334 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2335 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2338 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2340 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2341 unsigned char *pixelsbgra8 = NULL;
2342 unsigned char *pixelbgra8;
2343 unsigned short *pixelsrgba16f = NULL;
2344 unsigned short *pixelrgba16f;
2345 float *pixelsrgba32f = NULL;
2346 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2349 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2350 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2351 unsigned int pixelband;
2352 unsigned int x, y, z;
2353 unsigned int index, bandindex;
2354 unsigned int resolution[3];
2356 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2358 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2360 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2361 r_shadow_bouncegrid_state.texture = NULL;
2364 // if bentnormals exist, we need to normalize and bias them for the shader
2368 for (z = 0;z < resolution[2]-1;z++)
2370 for (y = 0;y < resolution[1]-1;y++)
2373 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2374 highpixel = highpixels + 4*index;
2375 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2377 // only convert pixels that were hit by photons
2378 if (highpixel[3] != 0.0f)
2379 VectorNormalize(highpixel);
2380 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2381 highpixel[pixelsperband * 4 + 3] = 1.0f;
2387 // start by clearing the pixels array - we won't be writing to all of it
2389 // then process only the pixels that have at least some color, skipping
2390 // the higher bands for speed on pixels that are black
2391 switch (floatcolors)
2394 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2395 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2396 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2397 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2400 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2402 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2404 for (z = 1;z < resolution[2]-1;z++)
2406 for (y = 1;y < resolution[1]-1;y++)
2410 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2411 highpixel = highpixels + 4*index;
2412 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2414 // only convert pixels that were hit by photons
2415 if (VectorLength2(highpixel))
2417 // normalize the bentnormal now
2420 VectorNormalize(highpixel + pixelsperband * 4);
2421 highpixel[pixelsperband * 4 + 3] = 1.0f;
2423 // process all of the pixelbands for this pixel
2424 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2426 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2427 bandpixel = highpixels + 4*bandindex;
2428 c[0] = (int)(bandpixel[0]*256.0f);
2429 c[1] = (int)(bandpixel[1]*256.0f);
2430 c[2] = (int)(bandpixel[2]*256.0f);
2431 c[3] = (int)(bandpixel[3]*256.0f);
2432 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2433 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2434 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2435 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2442 if (!r_shadow_bouncegrid_state.createtexture)
2443 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2445 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);
2448 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2449 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2450 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2451 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2452 for (z = 1;z < resolution[2]-1;z++)
2454 for (y = 1;y < resolution[1]-1;y++)
2458 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2459 highpixel = highpixels + 4*index;
2460 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2462 // only convert pixels that were hit by photons
2463 if (VectorLength2(highpixel))
2465 // process all of the pixelbands for this pixel
2466 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2468 // time to have fun with IEEE 754 bit hacking...
2471 unsigned int raw[4];
2473 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2474 bandpixel = highpixels + 4*bandindex;
2475 VectorCopy4(bandpixel, u.f);
2476 VectorCopy4(u.raw, c);
2477 // this math supports negative numbers, snaps denormals to zero
2478 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2479 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2480 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2481 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2482 // this math does not support negative
2483 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2484 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2485 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2486 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2493 if (!r_shadow_bouncegrid_state.createtexture)
2494 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2496 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);
2499 // our native format happens to match, so this is easy.
2500 pixelsrgba32f = highpixels;
2502 if (!r_shadow_bouncegrid_state.createtexture)
2503 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2505 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);
2509 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2512 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2516 int hitsupercontentsmask;
2517 int skipsupercontentsmask;
2518 int skipmaterialflagsmask;
2522 float bounceminimumintensity2;
2524 //trace_t cliptrace2;
2525 //trace_t cliptrace3;
2526 unsigned int lightindex;
2528 randomseed_t randomseed;
2530 vec3_t baseshotcolor;
2536 vec_t distancetraveled;
2540 // compute a seed for the unstable random modes
2541 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2542 seed = realtime * 1000.0;
2544 r_shadow_bouncegrid_state.numsplatpaths = 0;
2546 // figure out what we want to interact with
2547 if (settings.hitmodels)
2548 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2550 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2551 skipsupercontentsmask = 0;
2552 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
2553 maxbounce = settings.maxbounce;
2555 for (lightindex = 0;lightindex < range2;lightindex++)
2557 if (lightindex < range)
2559 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2562 rtlight = &light->rtlight;
2565 rtlight = r_refdef.scene.lights[lightindex - range];
2566 // note that this code used to keep track of residual photons and
2567 // distribute them evenly to achieve exactly a desired photon count,
2568 // but that caused unwanted flickering in dynamic mode
2569 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2570 // skip if we won't be shooting any photons
2571 if (!shootparticles)
2573 radius = rtlight->radius * settings.lightradiusscale;
2574 //s = settings.particleintensity / shootparticles;
2575 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2576 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2577 if (VectorLength2(baseshotcolor) <= 0.0f)
2579 r_refdef.stats[r_stat_bouncegrid_lights]++;
2580 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2581 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2582 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
2584 // for seeded random we start the RNG with the position of the light
2585 if (settings.rng_seed >= 0)
2593 u.f[0] = rtlight->shadoworigin[0];
2594 u.f[1] = rtlight->shadoworigin[1];
2595 u.f[2] = rtlight->shadoworigin[2];
2597 switch (settings.rng_type)
2601 // we have to shift the seed provided by the user because the result must be odd
2602 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
2605 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
2610 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2612 VectorCopy(baseshotcolor, shotcolor);
2613 VectorCopy(rtlight->shadoworigin, clipstart);
2614 switch (settings.rng_type)
2618 VectorLehmerRandom(&randomseed, clipend);
2621 VectorCheeseRandom(seed, clipend);
2625 // we want a uniform distribution spherically, not merely within the sphere
2626 if (settings.normalizevectors)
2627 VectorNormalize(clipend);
2629 VectorMA(clipstart, radius, clipend, clipend);
2630 distancetraveled = 0.0f;
2631 for (bouncecount = 0;;bouncecount++)
2633 r_refdef.stats[r_stat_bouncegrid_traces]++;
2634 rtlight->bouncegrid_traces++;
2635 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2636 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2637 if (settings.staticmode || settings.rng_seed < 0)
2639 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2640 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2641 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);
2645 // dynamic mode fires many rays and most will match the cache from the previous frame
2646 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
2648 if (bouncecount > 0 || settings.includedirectlighting)
2651 VectorCopy(cliptrace.endpos, hitpos);
2652 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
2654 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
2655 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
2656 if (rtlight->bouncegrid_effectiveradius < s)
2657 rtlight->bouncegrid_effectiveradius = s;
2658 if (cliptrace.fraction >= 1.0f)
2660 r_refdef.stats[r_stat_bouncegrid_hits]++;
2661 rtlight->bouncegrid_hits++;
2662 if (bouncecount >= maxbounce)
2664 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2665 // also clamp the resulting color to never add energy, even if the user requests extreme values
2666 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2667 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2669 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2670 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2671 surfcolor[0] = min(surfcolor[0], 1.0f);
2672 surfcolor[1] = min(surfcolor[1], 1.0f);
2673 surfcolor[2] = min(surfcolor[2], 1.0f);
2674 VectorMultiply(shotcolor, surfcolor, shotcolor);
2675 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
2677 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2678 // reflect the remaining portion of the line across plane normal
2679 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2680 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2681 // calculate the new line start and end
2682 VectorCopy(cliptrace.endpos, clipstart);
2683 VectorAdd(clipstart, clipend, clipend);
2689 void R_Shadow_UpdateBounceGridTexture(void)
2691 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2692 r_shadow_bouncegrid_settings_t settings;
2693 qboolean enable = false;
2694 qboolean settingschanged;
2695 unsigned int range; // number of world lights
2696 unsigned int range1; // number of dynamic lights (or zero if disabled)
2697 unsigned int range2; // range+range1
2699 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2701 R_Shadow_BounceGrid_GenerateSettings(&settings);
2703 // changing intensity does not require an update
2704 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2706 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2708 // when settings change, we free everything as it is just simpler that way.
2709 if (settingschanged || !enable)
2711 // not enabled, make sure we free anything we don't need anymore.
2712 if (r_shadow_bouncegrid_state.texture)
2714 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2715 r_shadow_bouncegrid_state.texture = NULL;
2717 r_shadow_bouncegrid_state.highpixels = NULL;
2718 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2719 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2720 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2721 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2722 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2723 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2724 r_shadow_bouncegrid_state.numpixels = 0;
2725 r_shadow_bouncegrid_state.directional = false;
2731 // if all the settings seem identical to the previous update, return
2732 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2735 // store the new settings
2736 r_shadow_bouncegrid_state.settings = settings;
2738 R_Shadow_BounceGrid_UpdateSpacing();
2740 // get the range of light numbers we'll be looping over:
2741 // range = static lights
2742 // range1 = dynamic lights (optional)
2743 // range2 = range + range1
2744 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2745 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2746 range2 = range + range1;
2748 // calculate weighting factors for distributing photons among the lights
2749 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
2750 R_TimeReport("bg_assignphotons");
2752 // trace the photons from lights and accumulate illumination
2753 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
2754 R_TimeReport("bg_tracephotons");
2756 // clear the texture
2757 R_Shadow_BounceGrid_ClearPixels();
2758 R_TimeReport("bg_cleartex");
2760 // accumulate the light splatting into texture
2761 R_Shadow_BounceGrid_PerformSplats();
2762 R_TimeReport("bg_lighttex");
2764 // apply a mild blur filter to the texture
2765 R_Shadow_BounceGrid_BlurPixels();
2766 R_TimeReport("bg_blurtex");
2768 // convert the pixels to lower precision and upload the texture
2769 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2770 R_TimeReport("bg_uploadtex");
2772 // after we compute the static lighting we don't need to keep the highpixels array around
2773 if (settings.staticmode)
2775 r_shadow_bouncegrid_state.highpixels = NULL;
2776 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2777 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2778 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2779 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2780 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2781 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2785 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2787 R_Shadow_RenderMode_Reset();
2788 GL_BlendFunc(GL_ONE, GL_ONE);
2789 GL_DepthRange(0, 1);
2790 GL_DepthTest(r_showlighting.integer < 2);
2791 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2793 GL_DepthFunc(GL_EQUAL);
2794 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2797 void R_Shadow_RenderMode_End(void)
2799 R_Shadow_RenderMode_Reset();
2800 R_Shadow_RenderMode_ActiveLight(NULL);
2802 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2803 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2806 int bboxedges[12][2] =
2825 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2827 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2829 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2830 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2831 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2832 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2835 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2836 return true; // invisible
2837 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2838 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2839 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2840 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2841 r_refdef.stats[r_stat_lights_scissored]++;
2845 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2847 // used to display how many times a surface is lit for level design purposes
2848 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2849 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2853 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])
2855 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2856 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2860 extern cvar_t gl_lightmaps;
2861 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2864 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2865 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2866 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2867 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2868 if (!r_shadow_usenormalmap.integer)
2870 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2871 VectorClear(diffusecolor);
2872 VectorClear(specularcolor);
2874 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2875 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2876 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2877 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2879 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2882 VectorNegate(ambientcolor, ambientcolor);
2883 VectorNegate(diffusecolor, diffusecolor);
2884 VectorNegate(specularcolor, specularcolor);
2885 GL_BlendEquationSubtract(true);
2887 RSurf_SetupDepthAndCulling();
2888 switch (r_shadow_rendermode)
2890 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2891 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2892 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2894 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2895 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2898 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2902 GL_BlendEquationSubtract(false);
2905 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)
2907 matrix4x4_t tempmatrix = *matrix;
2908 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2910 // if this light has been compiled before, free the associated data
2911 R_RTLight_Uncompile(rtlight);
2913 // clear it completely to avoid any lingering data
2914 memset(rtlight, 0, sizeof(*rtlight));
2916 // copy the properties
2917 rtlight->matrix_lighttoworld = tempmatrix;
2918 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2919 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2920 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2921 VectorCopy(color, rtlight->color);
2922 rtlight->cubemapname[0] = 0;
2923 if (cubemapname && cubemapname[0])
2924 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2925 rtlight->shadow = shadow;
2926 rtlight->corona = corona;
2927 rtlight->style = style;
2928 rtlight->isstatic = isstatic;
2929 rtlight->coronasizescale = coronasizescale;
2930 rtlight->ambientscale = ambientscale;
2931 rtlight->diffusescale = diffusescale;
2932 rtlight->specularscale = specularscale;
2933 rtlight->flags = flags;
2935 // compute derived data
2936 //rtlight->cullradius = rtlight->radius;
2937 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2938 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2939 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2940 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2941 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2942 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2943 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2946 // compiles rtlight geometry
2947 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2948 void R_RTLight_Compile(rtlight_t *rtlight)
2951 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2952 int lighttris, shadowtris;
2953 entity_render_t *ent = r_refdef.scene.worldentity;
2954 dp_model_t *model = r_refdef.scene.worldmodel;
2955 unsigned char *data;
2957 // compile the light
2958 rtlight->compiled = true;
2959 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2960 rtlight->static_numleafs = 0;
2961 rtlight->static_numleafpvsbytes = 0;
2962 rtlight->static_leaflist = NULL;
2963 rtlight->static_leafpvs = NULL;
2964 rtlight->static_numsurfaces = 0;
2965 rtlight->static_surfacelist = NULL;
2966 rtlight->static_shadowmap_receivers = 0x3F;
2967 rtlight->static_shadowmap_casters = 0x3F;
2968 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2969 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2970 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2971 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2972 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2973 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2975 if (model && model->GetLightInfo)
2977 // this variable must be set for the CompileShadowMap code
2978 r_shadow_compilingrtlight = rtlight;
2979 R_FrameData_SetMark();
2980 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);
2981 R_FrameData_ReturnToMark();
2982 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2983 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2984 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2985 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2986 rtlight->static_numsurfaces = numsurfaces;
2987 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2988 rtlight->static_numleafs = numleafs;
2989 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2990 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2991 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2992 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2993 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2994 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2995 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2996 if (rtlight->static_numsurfaces)
2997 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2998 if (rtlight->static_numleafs)
2999 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3000 if (rtlight->static_numleafpvsbytes)
3001 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3002 if (rtlight->static_numshadowtrispvsbytes)
3003 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3004 if (rtlight->static_numlighttrispvsbytes)
3005 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3006 R_FrameData_SetMark();
3007 if (model->CompileShadowMap && rtlight->shadow)
3008 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3009 R_FrameData_ReturnToMark();
3010 // now we're done compiling the rtlight
3011 r_shadow_compilingrtlight = NULL;
3015 // use smallest available cullradius - box radius or light radius
3016 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3017 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3020 if (rtlight->static_numlighttrispvsbytes)
3021 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3022 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3026 if (rtlight->static_numshadowtrispvsbytes)
3027 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3028 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3031 if (developer_extra.integer)
3032 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);
3035 void R_RTLight_Uncompile(rtlight_t *rtlight)
3037 if (rtlight->compiled)
3039 if (rtlight->static_meshchain_shadow_shadowmap)
3040 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3041 rtlight->static_meshchain_shadow_shadowmap = NULL;
3042 // these allocations are grouped
3043 if (rtlight->static_surfacelist)
3044 Mem_Free(rtlight->static_surfacelist);
3045 rtlight->static_numleafs = 0;
3046 rtlight->static_numleafpvsbytes = 0;
3047 rtlight->static_leaflist = NULL;
3048 rtlight->static_leafpvs = NULL;
3049 rtlight->static_numsurfaces = 0;
3050 rtlight->static_surfacelist = NULL;
3051 rtlight->static_numshadowtrispvsbytes = 0;
3052 rtlight->static_shadowtrispvs = NULL;
3053 rtlight->static_numlighttrispvsbytes = 0;
3054 rtlight->static_lighttrispvs = NULL;
3055 rtlight->compiled = false;
3059 void R_Shadow_UncompileWorldLights(void)
3063 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3064 for (lightindex = 0;lightindex < range;lightindex++)
3066 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3069 R_RTLight_Uncompile(&light->rtlight);
3073 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3077 // reset the count of frustum planes
3078 // see rtlight->cached_frustumplanes definition for how much this array
3080 rtlight->cached_numfrustumplanes = 0;
3082 if (r_trippy.integer)
3085 // haven't implemented a culling path for ortho rendering
3086 if (!r_refdef.view.useperspective)
3088 // check if the light is on screen and copy the 4 planes if it is
3089 for (i = 0;i < 4;i++)
3090 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3093 for (i = 0;i < 4;i++)
3094 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3099 // generate a deformed frustum that includes the light origin, this is
3100 // used to cull shadow casting surfaces that can not possibly cast a
3101 // shadow onto the visible light-receiving surfaces, which can be a
3104 // if the light origin is onscreen the result will be 4 planes exactly
3105 // if the light origin is offscreen on only one axis the result will
3106 // be exactly 5 planes (split-side case)
3107 // if the light origin is offscreen on two axes the result will be
3108 // exactly 4 planes (stretched corner case)
3109 for (i = 0;i < 4;i++)
3111 // quickly reject standard frustum planes that put the light
3112 // origin outside the frustum
3113 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3116 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3118 // if all the standard frustum planes were accepted, the light is onscreen
3119 // otherwise we need to generate some more planes below...
3120 if (rtlight->cached_numfrustumplanes < 4)
3122 // at least one of the stock frustum planes failed, so we need to
3123 // create one or two custom planes to enclose the light origin
3124 for (i = 0;i < 4;i++)
3126 // create a plane using the view origin and light origin, and a
3127 // single point from the frustum corner set
3128 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3129 VectorNormalize(plane.normal);
3130 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3131 // see if this plane is backwards and flip it if so
3132 for (j = 0;j < 4;j++)
3133 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3137 VectorNegate(plane.normal, plane.normal);
3139 // flipped plane, test again to see if it is now valid
3140 for (j = 0;j < 4;j++)
3141 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3143 // if the plane is still not valid, then it is dividing the
3144 // frustum and has to be rejected
3148 // we have created a valid plane, compute extra info
3149 PlaneClassify(&plane);
3151 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3153 // if we've found 5 frustum planes then we have constructed a
3154 // proper split-side case and do not need to keep searching for
3155 // planes to enclose the light origin
3156 if (rtlight->cached_numfrustumplanes == 5)
3164 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3166 plane = rtlight->cached_frustumplanes[i];
3167 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));
3172 // now add the light-space box planes if the light box is rotated, as any
3173 // caster outside the oriented light box is irrelevant (even if it passed
3174 // the worldspace light box, which is axial)
3175 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3177 for (i = 0;i < 6;i++)
3181 v[i >> 1] = (i & 1) ? -1 : 1;
3182 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3183 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3184 plane.dist = VectorNormalizeLength(plane.normal);
3185 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3186 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3192 // add the world-space reduced box planes
3193 for (i = 0;i < 6;i++)
3195 VectorClear(plane.normal);
3196 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3197 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3198 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3207 // reduce all plane distances to tightly fit the rtlight cull box, which
3209 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3210 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3211 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3212 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3213 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3214 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3215 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3216 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3217 oldnum = rtlight->cached_numfrustumplanes;
3218 rtlight->cached_numfrustumplanes = 0;
3219 for (j = 0;j < oldnum;j++)
3221 // find the nearest point on the box to this plane
3222 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3223 for (i = 1;i < 8;i++)
3225 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3226 if (bestdist > dist)
3229 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);
3230 // if the nearest point is near or behind the plane, we want this
3231 // plane, otherwise the plane is useless as it won't cull anything
3232 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3234 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3235 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3242 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3244 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3246 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3248 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3249 if (mesh->sidetotals[r_shadow_shadowmapside])
3252 GL_CullFace(GL_NONE);
3253 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3254 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3255 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);
3259 else if (r_refdef.scene.worldentity->model)
3260 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);
3262 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3265 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3267 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3268 vec_t relativeshadowradius;
3269 RSurf_ActiveModelEntity(ent, false, false, false);
3270 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3271 // we need to re-init the shader for each entity because the matrix changed
3272 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3273 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3274 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3275 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3276 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3277 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3278 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3279 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3280 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3283 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3285 // set up properties for rendering light onto this entity
3286 RSurf_ActiveModelEntity(ent, true, true, false);
3287 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3288 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3289 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3290 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3293 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3295 if (!r_refdef.scene.worldmodel->DrawLight)
3298 // set up properties for rendering light onto this entity
3299 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3300 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3301 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3302 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3303 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3305 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3307 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3310 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3312 dp_model_t *model = ent->model;
3313 if (!model->DrawLight)
3316 R_Shadow_SetupEntityLight(ent);
3318 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3320 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3323 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3327 int numleafs, numsurfaces;
3328 int *leaflist, *surfacelist;
3329 unsigned char *leafpvs;
3330 unsigned char *shadowtrispvs;
3331 unsigned char *lighttrispvs;
3332 //unsigned char *surfacesides;
3333 int numlightentities;
3334 int numlightentities_noselfshadow;
3335 int numshadowentities;
3336 int numshadowentities_noselfshadow;
3337 // FIXME: bounds check lightentities and shadowentities, etc.
3338 static entity_render_t *lightentities[MAX_EDICTS];
3339 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3340 static entity_render_t *shadowentities[MAX_EDICTS];
3341 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3343 qboolean castshadows;
3345 rtlight->draw = false;
3346 rtlight->cached_numlightentities = 0;
3347 rtlight->cached_numlightentities_noselfshadow = 0;
3348 rtlight->cached_numshadowentities = 0;
3349 rtlight->cached_numshadowentities_noselfshadow = 0;
3350 rtlight->cached_numsurfaces = 0;
3351 rtlight->cached_lightentities = NULL;
3352 rtlight->cached_lightentities_noselfshadow = NULL;
3353 rtlight->cached_shadowentities = NULL;
3354 rtlight->cached_shadowentities_noselfshadow = NULL;
3355 rtlight->cached_shadowtrispvs = NULL;
3356 rtlight->cached_lighttrispvs = NULL;
3357 rtlight->cached_surfacelist = NULL;
3358 rtlight->shadowmapsidesize = 0;
3360 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3361 // skip lights that are basically invisible (color 0 0 0)
3362 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3364 // loading is done before visibility checks because loading should happen
3365 // all at once at the start of a level, not when it stalls gameplay.
3366 // (especially important to benchmarks)
3368 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3370 if (rtlight->compiled)
3371 R_RTLight_Uncompile(rtlight);
3372 R_RTLight_Compile(rtlight);
3376 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3378 // look up the light style value at this time
3379 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3380 VectorScale(rtlight->color, f, rtlight->currentcolor);
3382 if (rtlight->selected)
3384 f = 2 + sin(realtime * M_PI * 4.0);
3385 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3389 // skip if lightstyle is currently off
3390 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3393 // skip processing on corona-only lights
3397 // skip if the light box is not touching any visible leafs
3398 if (r_shadow_culllights_pvs.integer
3399 && r_refdef.scene.worldmodel
3400 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3401 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3404 // skip if the light box is not visible to traceline
3405 if (r_shadow_culllights_trace.integer)
3407 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))
3408 rtlight->trace_timer = realtime;
3409 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3413 // skip if the light box is off screen
3414 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3417 // in the typical case this will be quickly replaced by GetLightInfo
3418 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3419 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3421 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3423 // 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
3424 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3427 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3429 // compiled light, world available and can receive realtime lighting
3430 // retrieve leaf information
3431 numleafs = rtlight->static_numleafs;
3432 leaflist = rtlight->static_leaflist;
3433 leafpvs = rtlight->static_leafpvs;
3434 numsurfaces = rtlight->static_numsurfaces;
3435 surfacelist = rtlight->static_surfacelist;
3436 //surfacesides = NULL;
3437 shadowtrispvs = rtlight->static_shadowtrispvs;
3438 lighttrispvs = rtlight->static_lighttrispvs;
3440 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3442 // dynamic light, world available and can receive realtime lighting
3443 // calculate lit surfaces and leafs
3444 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);
3445 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3446 leaflist = r_shadow_buffer_leaflist;
3447 leafpvs = r_shadow_buffer_leafpvs;
3448 surfacelist = r_shadow_buffer_surfacelist;
3449 //surfacesides = r_shadow_buffer_surfacesides;
3450 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3451 lighttrispvs = r_shadow_buffer_lighttrispvs;
3452 // if the reduced leaf bounds are offscreen, skip it
3453 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3464 //surfacesides = NULL;
3465 shadowtrispvs = NULL;
3466 lighttrispvs = NULL;
3468 // check if light is illuminating any visible leafs
3471 for (i = 0; i < numleafs; i++)
3472 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3478 // make a list of lit entities and shadow casting entities
3479 numlightentities = 0;
3480 numlightentities_noselfshadow = 0;
3481 numshadowentities = 0;
3482 numshadowentities_noselfshadow = 0;
3484 // add dynamic entities that are lit by the light
3485 for (i = 0; i < r_refdef.scene.numentities; i++)
3488 entity_render_t *ent = r_refdef.scene.entities[i];
3490 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3492 // skip the object entirely if it is not within the valid
3493 // shadow-casting region (which includes the lit region)
3494 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3496 if (!(model = ent->model))
3498 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3500 // this entity wants to receive light, is visible, and is
3501 // inside the light box
3502 // TODO: check if the surfaces in the model can receive light
3503 // so now check if it's in a leaf seen by the light
3504 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))
3506 if (ent->flags & RENDER_NOSELFSHADOW)
3507 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3509 lightentities[numlightentities++] = ent;
3510 // since it is lit, it probably also casts a shadow...
3511 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3512 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3513 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3515 // note: exterior models without the RENDER_NOSELFSHADOW
3516 // flag still create a RENDER_NOSELFSHADOW shadow but
3517 // are lit normally, this means that they are
3518 // self-shadowing but do not shadow other
3519 // RENDER_NOSELFSHADOW entities such as the gun
3520 // (very weird, but keeps the player shadow off the gun)
3521 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3522 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3524 shadowentities[numshadowentities++] = ent;
3527 else if (ent->flags & RENDER_SHADOW)
3529 // this entity is not receiving light, but may still need to
3531 // TODO: check if the surfaces in the model can cast shadow
3532 // now check if it is in a leaf seen by the light
3533 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))
3535 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3536 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3537 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3539 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3540 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3542 shadowentities[numshadowentities++] = ent;
3547 // return if there's nothing at all to light
3548 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3551 // count this light in the r_speeds
3552 r_refdef.stats[r_stat_lights]++;
3554 // flag it as worth drawing later
3555 rtlight->draw = true;
3557 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3558 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3560 numshadowentities = numshadowentities_noselfshadow = 0;
3561 rtlight->castshadows = castshadows;
3563 // cache all the animated entities that cast a shadow but are not visible
3564 for (i = 0; i < numshadowentities; i++)
3565 R_AnimCache_GetEntity(shadowentities[i], false, false);
3566 for (i = 0; i < numshadowentities_noselfshadow; i++)
3567 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3569 // 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)
3570 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3572 for (i = 0; i < numshadowentities_noselfshadow; i++)
3573 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3574 numshadowentities_noselfshadow = 0;
3577 // we can convert noselfshadow to regular if there are no casters of that type
3578 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3580 for (i = 0; i < numlightentities_noselfshadow; i++)
3581 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3582 numlightentities_noselfshadow = 0;
3585 // allocate some temporary memory for rendering this light later in the frame
3586 // reusable buffers need to be copied, static data can be used as-is
3587 rtlight->cached_numlightentities = numlightentities;
3588 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3589 rtlight->cached_numshadowentities = numshadowentities;
3590 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3591 rtlight->cached_numsurfaces = numsurfaces;
3592 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3593 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3594 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3595 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3596 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3598 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3599 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3600 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3601 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3602 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3606 // compiled light data
3607 rtlight->cached_shadowtrispvs = shadowtrispvs;
3608 rtlight->cached_lighttrispvs = lighttrispvs;
3609 rtlight->cached_surfacelist = surfacelist;
3612 if (R_Shadow_ShadowMappingEnabled())
3614 // figure out the shadowmapping parameters for this light
3615 vec3_t nearestpoint;
3618 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3619 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3620 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3621 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3622 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3623 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3624 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3625 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3626 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3630 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3634 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3635 int numlightentities;
3636 int numlightentities_noselfshadow;
3637 int numshadowentities;
3638 int numshadowentities_noselfshadow;
3639 entity_render_t **lightentities;
3640 entity_render_t **lightentities_noselfshadow;
3641 entity_render_t **shadowentities;
3642 entity_render_t **shadowentities_noselfshadow;
3644 static unsigned char entitysides[MAX_EDICTS];
3645 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3651 matrix4x4_t radiustolight;
3653 // check if we cached this light this frame (meaning it is worth drawing)
3654 if (!rtlight->draw || !rtlight->castshadows)
3657 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3658 if (rtlight->shadowmapatlassidesize == 0)
3660 rtlight->castshadows = false;
3664 // set up a scissor rectangle for this light
3665 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3668 // don't let sound skip if going slow
3669 if (r_refdef.scene.extraupdate)
3672 numlightentities = rtlight->cached_numlightentities;
3673 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3674 numshadowentities = rtlight->cached_numshadowentities;
3675 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3676 numsurfaces = rtlight->cached_numsurfaces;
3677 lightentities = rtlight->cached_lightentities;
3678 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3679 shadowentities = rtlight->cached_shadowentities;
3680 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3681 shadowtrispvs = rtlight->cached_shadowtrispvs;
3682 lighttrispvs = rtlight->cached_lighttrispvs;
3683 surfacelist = rtlight->cached_surfacelist;
3685 // make this the active rtlight for rendering purposes
3686 R_Shadow_RenderMode_ActiveLight(rtlight);
3688 radiustolight = rtlight->matrix_worldtolight;
3689 Matrix4x4_Abs(&radiustolight);
3691 size = rtlight->shadowmapatlassidesize;
3692 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3694 surfacesides = NULL;
3699 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3701 castermask = rtlight->static_shadowmap_casters;
3702 receivermask = rtlight->static_shadowmap_receivers;
3706 surfacesides = r_shadow_buffer_surfacesides;
3707 for (i = 0; i < numsurfaces; i++)
3709 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3710 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3711 castermask |= surfacesides[i];
3712 receivermask |= surfacesides[i];
3717 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3718 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3719 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3720 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3722 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3726 for (i = 0; i < numshadowentities; i++)
3727 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3728 for (i = 0; i < numshadowentities_noselfshadow; i++)
3729 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3732 // there is no need to render shadows for sides that have no receivers...
3733 castermask &= receivermask;
3735 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3737 // render shadow casters into shadowmaps for this light
3738 for (side = 0; side < 6; side++)
3740 int bit = 1 << side;
3741 if (castermask & bit)
3743 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3745 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3746 for (i = 0; i < numshadowentities; i++)
3747 if (entitysides[i] & bit)
3748 R_Shadow_DrawEntityShadow(shadowentities[i]);
3749 for (i = 0; i < numshadowentities_noselfshadow; i++)
3750 if (entitysides_noselfshadow[i] & bit)
3751 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3754 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3755 if (numshadowentities_noselfshadow)
3757 for (side = 0; side < 6; side++)
3759 int bit = 1 << side;
3760 if (castermask & bit)
3762 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3764 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3765 for (i = 0; i < numshadowentities; i++)
3766 if (entitysides[i] & bit)
3767 R_Shadow_DrawEntityShadow(shadowentities[i]);
3773 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3777 unsigned char *shadowtrispvs, *lighttrispvs;
3778 int numlightentities;
3779 int numlightentities_noselfshadow;
3780 int numshadowentities;
3781 int numshadowentities_noselfshadow;
3782 entity_render_t **lightentities;
3783 entity_render_t **lightentities_noselfshadow;
3784 entity_render_t **shadowentities;
3785 entity_render_t **shadowentities_noselfshadow;
3787 qboolean castshadows;
3789 // check if we cached this light this frame (meaning it is worth drawing)
3793 // set up a scissor rectangle for this light
3794 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3797 // don't let sound skip if going slow
3798 if (r_refdef.scene.extraupdate)
3801 numlightentities = rtlight->cached_numlightentities;
3802 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3803 numshadowentities = rtlight->cached_numshadowentities;
3804 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3805 numsurfaces = rtlight->cached_numsurfaces;
3806 lightentities = rtlight->cached_lightentities;
3807 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3808 shadowentities = rtlight->cached_shadowentities;
3809 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3810 shadowtrispvs = rtlight->cached_shadowtrispvs;
3811 lighttrispvs = rtlight->cached_lighttrispvs;
3812 surfacelist = rtlight->cached_surfacelist;
3813 castshadows = rtlight->castshadows;
3815 // make this the active rtlight for rendering purposes
3816 R_Shadow_RenderMode_ActiveLight(rtlight);
3818 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3820 // optionally draw the illuminated areas
3821 // for performance analysis by level designers
3822 R_Shadow_RenderMode_VisibleLighting(false);
3824 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3825 for (i = 0;i < numlightentities;i++)
3826 R_Shadow_DrawEntityLight(lightentities[i]);
3827 for (i = 0;i < numlightentities_noselfshadow;i++)
3828 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3831 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3835 float shadowmapoffsetnoselfshadow = 0;
3836 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3837 Matrix4x4_Abs(&radiustolight);
3839 size = rtlight->shadowmapatlassidesize;
3840 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3842 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3844 if (rtlight->cached_numshadowentities_noselfshadow)
3845 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3847 // render lighting using the depth texture as shadowmap
3848 // draw lighting in the unmasked areas
3849 if (numsurfaces + numlightentities)
3851 R_Shadow_RenderMode_Lighting(false, true, false);
3852 // draw lighting in the unmasked areas
3854 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3855 for (i = 0; i < numlightentities; i++)
3856 R_Shadow_DrawEntityLight(lightentities[i]);
3858 // offset to the noselfshadow part of the atlas and draw those too
3859 if (numlightentities_noselfshadow)
3861 R_Shadow_RenderMode_Lighting(false, true, true);
3862 for (i = 0; i < numlightentities_noselfshadow; i++)
3863 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3866 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3867 if (r_shadow_usingdeferredprepass)
3868 R_Shadow_RenderMode_DrawDeferredLight(true);
3872 // draw lighting in the unmasked areas
3873 R_Shadow_RenderMode_Lighting(false, false, false);
3875 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3876 for (i = 0;i < numlightentities;i++)
3877 R_Shadow_DrawEntityLight(lightentities[i]);
3878 for (i = 0;i < numlightentities_noselfshadow;i++)
3879 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3881 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3882 if (r_shadow_usingdeferredprepass)
3883 R_Shadow_RenderMode_DrawDeferredLight(false);
3887 static void R_Shadow_FreeDeferred(void)
3889 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3890 r_shadow_prepassgeometryfbo = 0;
3892 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3893 r_shadow_prepasslightingdiffusespecularfbo = 0;
3895 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3896 r_shadow_prepasslightingdiffusefbo = 0;
3898 if (r_shadow_prepassgeometrydepthbuffer)
3899 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3900 r_shadow_prepassgeometrydepthbuffer = NULL;
3902 if (r_shadow_prepassgeometrynormalmaptexture)
3903 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3904 r_shadow_prepassgeometrynormalmaptexture = NULL;
3906 if (r_shadow_prepasslightingdiffusetexture)
3907 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3908 r_shadow_prepasslightingdiffusetexture = NULL;
3910 if (r_shadow_prepasslightingspeculartexture)
3911 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3912 r_shadow_prepasslightingspeculartexture = NULL;
3915 void R_Shadow_DrawPrepass(void)
3919 entity_render_t *ent;
3920 float clearcolor[4];
3922 R_Mesh_ResetTextureState();
3924 GL_ColorMask(1,1,1,1);
3925 GL_BlendFunc(GL_ONE, GL_ZERO);
3928 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3929 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3930 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3931 if (r_timereport_active)
3932 R_TimeReport("prepasscleargeom");
3934 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3935 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3936 if (r_timereport_active)
3937 R_TimeReport("prepassworld");
3939 for (i = 0;i < r_refdef.scene.numentities;i++)
3941 if (!r_refdef.viewcache.entityvisible[i])
3943 ent = r_refdef.scene.entities[i];
3944 if (ent->model && ent->model->DrawPrepass != NULL)
3945 ent->model->DrawPrepass(ent);
3948 if (r_timereport_active)
3949 R_TimeReport("prepassmodels");
3951 GL_DepthMask(false);
3952 GL_ColorMask(1,1,1,1);
3955 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3956 Vector4Set(clearcolor, 0, 0, 0, 0);
3957 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3958 if (r_timereport_active)
3959 R_TimeReport("prepassclearlit");
3961 R_Shadow_RenderMode_Begin();
3963 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
3964 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
3966 R_Shadow_RenderMode_End();
3968 if (r_timereport_active)
3969 R_TimeReport("prepasslights");
3972 #define MAX_SCENELIGHTS 65536
3973 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
3975 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
3977 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
3979 r_shadow_scenemaxlights *= 2;
3980 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
3981 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
3983 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
3987 void R_Shadow_DrawLightSprites(void);
3988 void R_Shadow_PrepareLights(void)
3997 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
3998 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
3999 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4001 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4002 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4003 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4004 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4005 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4006 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4007 r_shadow_shadowmapborder != shadowmapborder ||
4008 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4009 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4010 R_Shadow_FreeShadowMaps();
4012 r_shadow_usingshadowmaportho = false;
4014 switch (vid.renderpath)
4016 case RENDERPATH_GL32:
4018 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4020 r_shadow_usingdeferredprepass = false;
4021 if (r_shadow_prepass_width)
4022 R_Shadow_FreeDeferred();
4023 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4027 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4029 R_Shadow_FreeDeferred();
4031 r_shadow_usingdeferredprepass = true;
4032 r_shadow_prepass_width = vid.width;
4033 r_shadow_prepass_height = vid.height;
4034 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4035 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);
4036 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);
4037 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);
4039 // set up the geometry pass fbo (depth + normalmap)
4040 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4041 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4042 // render depth into a renderbuffer and other important properties into the normalmap texture
4044 // set up the lighting pass fbo (diffuse + specular)
4045 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4046 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4047 // render diffuse into one texture and specular into another,
4048 // with depth and normalmap bound as textures,
4049 // with depth bound as attachment as well
4051 // set up the lighting pass fbo (diffuse)
4052 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4053 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4054 // render diffuse into one texture,
4055 // with depth and normalmap bound as textures,
4056 // with depth bound as attachment as well
4060 case RENDERPATH_GLES2:
4061 r_shadow_usingdeferredprepass = false;
4065 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);
4067 r_shadow_scenenumlights = 0;
4068 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4069 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4070 for (lightindex = 0; lightindex < range; lightindex++)
4072 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4073 if (light && (light->flags & flag))
4075 R_Shadow_PrepareLight(&light->rtlight);
4076 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4079 if (r_refdef.scene.rtdlight)
4081 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4083 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4084 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4087 else if (gl_flashblend.integer)
4089 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4091 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4092 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4093 VectorScale(rtlight->color, f, rtlight->currentcolor);
4097 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4098 if (r_shadow_debuglight.integer >= 0)
4100 r_shadow_scenenumlights = 0;
4101 lightindex = r_shadow_debuglight.integer;
4102 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4105 R_Shadow_PrepareLight(&light->rtlight);
4106 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4110 // if we're doing shadowmaps we need to prepare the atlas layout now
4111 if (R_Shadow_ShadowMappingEnabled())
4115 // allocate shadowmaps in the atlas now
4116 // 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...
4117 for (lod = 0; lod < 16; lod++)
4119 int packing_success = 0;
4120 int packing_failure = 0;
4121 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4122 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4123 if (r_shadow_shadowmapatlas_modelshadows_size)
4124 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);
4125 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4127 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4128 int size = rtlight->shadowmapsidesize >> lod;
4130 if (!rtlight->castshadows)
4132 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4135 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4136 if (rtlight->cached_numshadowentities_noselfshadow)
4138 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4140 rtlight->shadowmapatlassidesize = size;
4145 // note down that we failed to pack this one, it will have to disable shadows
4146 rtlight->shadowmapatlassidesize = 0;
4150 // generally everything fits and we stop here on the first iteration
4151 if (packing_failure == 0)
4156 if (r_editlights.integer)
4157 R_Shadow_DrawLightSprites();
4160 void R_Shadow_DrawShadowMaps(void)
4162 R_Shadow_RenderMode_Begin();
4163 R_Shadow_RenderMode_ActiveLight(NULL);
4165 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4166 R_Shadow_ClearShadowMapTexture();
4168 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4169 if (r_shadow_shadowmapatlas_modelshadows_size)
4171 R_Shadow_DrawModelShadowMaps();
4172 // don't let sound skip if going slow
4173 if (r_refdef.scene.extraupdate)
4177 if (R_Shadow_ShadowMappingEnabled())
4180 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4181 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4184 R_Shadow_RenderMode_End();
4187 void R_Shadow_DrawLights(void)
4191 R_Shadow_RenderMode_Begin();
4193 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4194 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4196 R_Shadow_RenderMode_End();
4199 #define MAX_MODELSHADOWS 1024
4200 static int r_shadow_nummodelshadows;
4201 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4203 void R_Shadow_PrepareModelShadows(void)
4206 float scale, size, radius, dot1, dot2;
4207 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4208 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4209 entity_render_t *ent;
4211 r_shadow_nummodelshadows = 0;
4212 r_shadow_shadowmapatlas_modelshadows_size = 0;
4214 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4217 size = r_shadow_shadowmaptexturesize / 4;
4218 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4219 radius = 0.5f * size / scale;
4221 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4222 VectorCopy(prvmshadowdir, shadowdir);
4223 VectorNormalize(shadowdir);
4224 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4225 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4226 if (fabs(dot1) <= fabs(dot2))
4227 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4229 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4230 VectorNormalize(shadowforward);
4231 CrossProduct(shadowdir, shadowforward, shadowright);
4232 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4233 VectorCopy(prvmshadowfocus, shadowfocus);
4234 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4235 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4236 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4237 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4238 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4240 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4242 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4243 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4244 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4245 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4246 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4247 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4249 for (i = 0; i < r_refdef.scene.numentities; i++)
4251 ent = r_refdef.scene.entities[i];
4252 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4254 // cast shadows from anything of the map (submodels are optional)
4255 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4257 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4259 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4260 R_AnimCache_GetEntity(ent, false, false);
4264 if (r_shadow_nummodelshadows)
4266 r_shadow_shadowmapatlas_modelshadows_x = 0;
4267 r_shadow_shadowmapatlas_modelshadows_y = 0;
4268 r_shadow_shadowmapatlas_modelshadows_size = size;
4272 static void R_Shadow_DrawModelShadowMaps(void)
4275 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4276 entity_render_t *ent;
4277 vec3_t relativelightorigin;
4278 vec3_t relativelightdirection, relativeforward, relativeright;
4279 vec3_t relativeshadowmins, relativeshadowmaxs;
4280 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4281 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4283 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4284 r_viewport_t viewport;
4286 size = r_shadow_shadowmapatlas_modelshadows_size;
4287 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4288 radius = 0.5f / scale;
4289 nearclip = -r_shadows_throwdistance.value;
4290 farclip = r_shadows_throwdistance.value;
4291 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);
4293 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4294 r_shadow_modelshadowmap_parameters[0] = size;
4295 r_shadow_modelshadowmap_parameters[1] = size;
4296 r_shadow_modelshadowmap_parameters[2] = 1.0;
4297 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4298 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4299 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4300 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4301 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4302 r_shadow_usingshadowmaportho = true;
4304 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4305 VectorCopy(prvmshadowdir, shadowdir);
4306 VectorNormalize(shadowdir);
4307 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4308 VectorCopy(prvmshadowfocus, shadowfocus);
4309 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4310 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4311 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4312 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4313 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4314 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4315 if (fabs(dot1) <= fabs(dot2))
4316 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4318 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4319 VectorNormalize(shadowforward);
4320 VectorM(scale, shadowforward, &m[0]);
4321 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4323 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4324 CrossProduct(shadowdir, shadowforward, shadowright);
4325 VectorM(scale, shadowright, &m[4]);
4326 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4327 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4328 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4329 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4330 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4331 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);
4332 R_SetViewport(&viewport);
4334 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4336 // render into a slightly restricted region so that the borders of the
4337 // shadowmap area fade away, rather than streaking across everything
4338 // outside the usable area
4339 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4341 for (i = 0;i < r_shadow_nummodelshadows;i++)
4343 ent = r_shadow_modelshadows[i];
4344 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4345 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4346 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4347 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4348 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4349 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4350 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4351 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4352 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4353 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4354 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4355 RSurf_ActiveModelEntity(ent, false, false, false);
4356 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4357 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4363 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4365 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4367 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4368 Cvar_SetValueQuick(&r_test, 0);
4373 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4374 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4375 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4376 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4377 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4378 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4381 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4384 vec3_t centerorigin;
4388 // if it's too close, skip it
4389 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4391 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4394 if (usequery && r_numqueries + 2 <= r_maxqueries)
4396 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4397 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4398 // 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
4399 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4401 switch(vid.renderpath)
4403 case RENDERPATH_GL32:
4404 case RENDERPATH_GLES2:
4407 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4408 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4409 GL_DepthFunc(GL_ALWAYS);
4410 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4411 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4412 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4413 qglEndQuery(GL_SAMPLES_PASSED);
4414 GL_DepthFunc(GL_LEQUAL);
4415 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4416 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4417 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4418 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4419 qglEndQuery(GL_SAMPLES_PASSED);
4425 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4428 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4430 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4433 unsigned int occlude = 0;
4435 // now we have to check the query result
4436 if (rtlight->corona_queryindex_visiblepixels)
4438 switch(vid.renderpath)
4440 case RENDERPATH_GL32:
4441 case RENDERPATH_GLES2:
4443 // store the pixel counts into a uniform buffer for the shader to
4444 // use - we'll never know the results on the cpu without
4445 // synchronizing and we don't want that
4446 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4447 if (!r_shadow_occlusion_buf) {
4448 qglGenBuffers(1, &r_shadow_occlusion_buf);
4449 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4450 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4452 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4454 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4455 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4456 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4457 occlude = MATERIALFLAG_OCCLUDE;
4458 cscale *= rtlight->corona_visibility;
4468 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4471 VectorScale(rtlight->currentcolor, cscale, color);
4472 if (VectorLength(color) > (1.0f / 256.0f))
4475 qboolean negated = (color[0] + color[1] + color[2] < 0);
4478 VectorNegate(color, color);
4479 GL_BlendEquationSubtract(true);
4481 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4482 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);
4483 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4485 GL_BlendEquationSubtract(false);
4489 void R_Shadow_DrawCoronas(void)
4492 qboolean usequery = false;
4497 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4499 if (r_fb.water.renderingscene)
4501 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4502 R_EntityMatrix(&identitymatrix);
4504 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4506 // check occlusion of coronas, using occlusion queries or raytraces
4508 switch (vid.renderpath)
4510 case RENDERPATH_GL32:
4511 case RENDERPATH_GLES2:
4512 usequery = r_coronas_occlusionquery.integer;
4516 GL_ColorMask(0,0,0,0);
4517 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4518 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4521 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4522 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4524 qglGenQueries(r_maxqueries - i, r_queries + i);
4527 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4528 GL_BlendFunc(GL_ONE, GL_ZERO);
4529 GL_CullFace(GL_NONE);
4530 GL_DepthMask(false);
4531 GL_DepthRange(0, 1);
4532 GL_PolygonOffset(0, 0);
4534 R_Mesh_ResetTextureState();
4535 R_SetupShader_Generic_NoTexture(false, false);
4540 for (lightindex = 0;lightindex < range;lightindex++)
4542 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4545 rtlight = &light->rtlight;
4546 rtlight->corona_visibility = 0;
4547 rtlight->corona_queryindex_visiblepixels = 0;
4548 rtlight->corona_queryindex_allpixels = 0;
4549 if (!(rtlight->flags & flag))
4551 if (rtlight->corona <= 0)
4553 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4555 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4557 for (i = 0;i < r_refdef.scene.numlights;i++)
4559 rtlight = r_refdef.scene.lights[i];
4560 rtlight->corona_visibility = 0;
4561 rtlight->corona_queryindex_visiblepixels = 0;
4562 rtlight->corona_queryindex_allpixels = 0;
4563 if (!(rtlight->flags & flag))
4565 if (rtlight->corona <= 0)
4567 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4570 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4572 // now draw the coronas using the query data for intensity info
4573 for (lightindex = 0;lightindex < range;lightindex++)
4575 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4578 rtlight = &light->rtlight;
4579 if (rtlight->corona_visibility <= 0)
4581 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4583 for (i = 0;i < r_refdef.scene.numlights;i++)
4585 rtlight = r_refdef.scene.lights[i];
4586 if (rtlight->corona_visibility <= 0)
4588 if (gl_flashblend.integer)
4589 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4591 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4597 static dlight_t *R_Shadow_NewWorldLight(void)
4599 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4602 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)
4606 // 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
4608 // validate parameters
4612 // copy to light properties
4613 VectorCopy(origin, light->origin);
4614 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4615 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4616 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4618 light->color[0] = max(color[0], 0);
4619 light->color[1] = max(color[1], 0);
4620 light->color[2] = max(color[2], 0);
4622 light->color[0] = color[0];
4623 light->color[1] = color[1];
4624 light->color[2] = color[2];
4625 light->radius = max(radius, 0);
4626 light->style = style;
4627 light->shadow = shadowenable;
4628 light->corona = corona;
4629 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4630 light->coronasizescale = coronasizescale;
4631 light->ambientscale = ambientscale;
4632 light->diffusescale = diffusescale;
4633 light->specularscale = specularscale;
4634 light->flags = flags;
4636 // update renderable light data
4637 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4638 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);
4641 static void R_Shadow_FreeWorldLight(dlight_t *light)
4643 if (r_shadow_selectedlight == light)
4644 r_shadow_selectedlight = NULL;
4645 R_RTLight_Uncompile(&light->rtlight);
4646 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4649 void R_Shadow_ClearWorldLights(void)
4653 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4654 for (lightindex = 0;lightindex < range;lightindex++)
4656 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4658 R_Shadow_FreeWorldLight(light);
4660 r_shadow_selectedlight = NULL;
4663 static void R_Shadow_SelectLight(dlight_t *light)
4665 if (r_shadow_selectedlight)
4666 r_shadow_selectedlight->selected = false;
4667 r_shadow_selectedlight = light;
4668 if (r_shadow_selectedlight)
4669 r_shadow_selectedlight->selected = true;
4672 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4674 // this is never batched (there can be only one)
4676 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4677 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4678 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4681 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4686 skinframe_t *skinframe;
4689 // this is never batched (due to the ent parameter changing every time)
4690 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4691 const dlight_t *light = (dlight_t *)ent;
4694 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4697 VectorScale(light->color, intensity, spritecolor);
4698 if (VectorLength(spritecolor) < 0.1732f)
4699 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4700 if (VectorLength(spritecolor) > 1.0f)
4701 VectorNormalize(spritecolor);
4703 // draw light sprite
4704 if (light->cubemapname[0] && !light->shadow)
4705 skinframe = r_editlights_sprcubemapnoshadowlight;
4706 else if (light->cubemapname[0])
4707 skinframe = r_editlights_sprcubemaplight;
4708 else if (!light->shadow)
4709 skinframe = r_editlights_sprnoshadowlight;
4711 skinframe = r_editlights_sprlight;
4713 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);
4714 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4716 // draw selection sprite if light is selected
4717 if (light->selected)
4719 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4720 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4721 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4725 void R_Shadow_DrawLightSprites(void)
4729 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4730 for (lightindex = 0;lightindex < range;lightindex++)
4732 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4734 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4736 if (!r_editlights_lockcursor)
4737 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4740 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4745 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4746 if (lightindex >= range)
4748 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4751 rtlight = &light->rtlight;
4752 //if (!(rtlight->flags & flag))
4754 VectorCopy(rtlight->shadoworigin, origin);
4755 *radius = rtlight->radius;
4756 VectorCopy(rtlight->color, color);
4760 static void R_Shadow_SelectLightInView(void)
4762 float bestrating, rating, temp[3];
4766 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4770 if (r_editlights_lockcursor)
4772 for (lightindex = 0;lightindex < range;lightindex++)
4774 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4777 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4778 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4781 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4782 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)
4784 bestrating = rating;
4789 R_Shadow_SelectLight(best);
4792 void R_Shadow_LoadWorldLights(void)
4794 int n, a, style, shadow, flags;
4795 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4796 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4797 if (cl.worldmodel == NULL)
4799 Con_Print("No map loaded.\n");
4802 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4803 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4813 for (;COM_Parse(t, true) && strcmp(
4814 if (COM_Parse(t, true))
4816 if (com_token[0] == '!')
4819 origin[0] = atof(com_token+1);
4822 origin[0] = atof(com_token);
4827 while (*s && *s != '\n' && *s != '\r')
4833 // check for modifier flags
4840 #if _MSC_VER >= 1400
4841 #define sscanf sscanf_s
4843 cubemapname[sizeof(cubemapname)-1] = 0;
4844 #if MAX_QPATH != 128
4845 #error update this code if MAX_QPATH changes
4847 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
4848 #if _MSC_VER >= 1400
4849 , (unsigned int)sizeof(cubemapname)
4851 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4854 flags = LIGHTFLAG_REALTIMEMODE;
4862 coronasizescale = 0.25f;
4864 VectorClear(angles);
4867 if (a < 9 || !strcmp(cubemapname, "\"\""))
4869 // remove quotes on cubemapname
4870 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4873 namelen = strlen(cubemapname) - 2;
4874 memmove(cubemapname, cubemapname + 1, namelen);
4875 cubemapname[namelen] = '\0';
4879 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);
4882 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4890 Con_Printf("invalid rtlights file \"%s\"\n", name);
4891 Mem_Free(lightsstring);
4895 void R_Shadow_SaveWorldLights(void)
4899 size_t bufchars, bufmaxchars;
4901 char name[MAX_QPATH];
4902 char line[MAX_INPUTLINE];
4903 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4904 // I hate lines which are 3 times my screen size :( --blub
4907 if (cl.worldmodel == NULL)
4909 Con_Print("No map loaded.\n");
4912 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4913 bufchars = bufmaxchars = 0;
4915 for (lightindex = 0;lightindex < range;lightindex++)
4917 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4920 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4921 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);
4922 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4923 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]);
4925 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);
4926 if (bufchars + strlen(line) > bufmaxchars)
4928 bufmaxchars = bufchars + strlen(line) + 2048;
4930 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4934 memcpy(buf, oldbuf, bufchars);
4940 memcpy(buf + bufchars, line, strlen(line));
4941 bufchars += strlen(line);
4945 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4950 void R_Shadow_LoadLightsFile(void)
4953 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4954 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4955 if (cl.worldmodel == NULL)
4957 Con_Print("No map loaded.\n");
4960 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
4961 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4969 while (*s && *s != '\n' && *s != '\r')
4975 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);
4979 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);
4982 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4983 radius = bound(15, radius, 4096);
4984 VectorScale(color, (2.0f / (8388608.0f)), color);
4985 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4993 Con_Printf("invalid lights file \"%s\"\n", name);
4994 Mem_Free(lightsstring);
4998 // tyrlite/hmap2 light types in the delay field
4999 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5001 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5013 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5014 char key[256], value[MAX_INPUTLINE];
5017 if (cl.worldmodel == NULL)
5019 Con_Print("No map loaded.\n");
5022 // try to load a .ent file first
5023 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5024 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5025 // and if that is not found, fall back to the bsp file entity string
5027 data = cl.worldmodel->brush.entities;
5030 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5032 type = LIGHTTYPE_MINUSX;
5033 origin[0] = origin[1] = origin[2] = 0;
5034 originhack[0] = originhack[1] = originhack[2] = 0;
5035 angles[0] = angles[1] = angles[2] = 0;
5036 color[0] = color[1] = color[2] = 1;
5037 light[0] = light[1] = light[2] = 1;light[3] = 300;
5038 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5048 if (!COM_ParseToken_Simple(&data, false, false, true))
5050 if (com_token[0] == '}')
5051 break; // end of entity
5052 if (com_token[0] == '_')
5053 strlcpy(key, com_token + 1, sizeof(key));
5055 strlcpy(key, com_token, sizeof(key));
5056 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5057 key[strlen(key)-1] = 0;
5058 if (!COM_ParseToken_Simple(&data, false, false, true))
5060 strlcpy(value, com_token, sizeof(value));
5062 // now that we have the key pair worked out...
5063 if (!strcmp("light", key))
5065 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5069 light[0] = vec[0] * (1.0f / 256.0f);
5070 light[1] = vec[0] * (1.0f / 256.0f);
5071 light[2] = vec[0] * (1.0f / 256.0f);
5077 light[0] = vec[0] * (1.0f / 255.0f);
5078 light[1] = vec[1] * (1.0f / 255.0f);
5079 light[2] = vec[2] * (1.0f / 255.0f);
5083 else if (!strcmp("delay", key))
5085 else if (!strcmp("origin", key))
5086 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5087 else if (!strcmp("angle", key))
5088 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5089 else if (!strcmp("angles", key))
5090 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5091 else if (!strcmp("color", key))
5092 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5093 else if (!strcmp("wait", key))
5094 fadescale = atof(value);
5095 else if (!strcmp("classname", key))
5097 if (!strncmp(value, "light", 5))
5100 if (!strcmp(value, "light_fluoro"))
5105 overridecolor[0] = 1;
5106 overridecolor[1] = 1;
5107 overridecolor[2] = 1;
5109 if (!strcmp(value, "light_fluorospark"))
5114 overridecolor[0] = 1;
5115 overridecolor[1] = 1;
5116 overridecolor[2] = 1;
5118 if (!strcmp(value, "light_globe"))
5123 overridecolor[0] = 1;
5124 overridecolor[1] = 0.8;
5125 overridecolor[2] = 0.4;
5127 if (!strcmp(value, "light_flame_large_yellow"))
5132 overridecolor[0] = 1;
5133 overridecolor[1] = 0.5;
5134 overridecolor[2] = 0.1;
5136 if (!strcmp(value, "light_flame_small_yellow"))
5141 overridecolor[0] = 1;
5142 overridecolor[1] = 0.5;
5143 overridecolor[2] = 0.1;
5145 if (!strcmp(value, "light_torch_small_white"))
5150 overridecolor[0] = 1;
5151 overridecolor[1] = 0.5;
5152 overridecolor[2] = 0.1;
5154 if (!strcmp(value, "light_torch_small_walltorch"))
5159 overridecolor[0] = 1;
5160 overridecolor[1] = 0.5;
5161 overridecolor[2] = 0.1;
5165 else if (!strcmp("style", key))
5166 style = atoi(value);
5167 else if (!strcmp("skin", key))
5168 skin = (int)atof(value);
5169 else if (!strcmp("pflags", key))
5170 pflags = (int)atof(value);
5171 //else if (!strcmp("effects", key))
5172 // effects = (int)atof(value);
5173 else if (cl.worldmodel->type == mod_brushq3)
5175 if (!strcmp("scale", key))
5176 lightscale = atof(value);
5177 if (!strcmp("fade", key))
5178 fadescale = atof(value);
5183 if (lightscale <= 0)
5187 if (color[0] == color[1] && color[0] == color[2])
5189 color[0] *= overridecolor[0];
5190 color[1] *= overridecolor[1];
5191 color[2] *= overridecolor[2];
5193 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5194 color[0] = color[0] * light[0];
5195 color[1] = color[1] * light[1];
5196 color[2] = color[2] * light[2];
5199 case LIGHTTYPE_MINUSX:
5201 case LIGHTTYPE_RECIPX:
5203 VectorScale(color, (1.0f / 16.0f), color);
5205 case LIGHTTYPE_RECIPXX:
5207 VectorScale(color, (1.0f / 16.0f), color);
5210 case LIGHTTYPE_NONE:
5214 case LIGHTTYPE_MINUSXX:
5217 VectorAdd(origin, originhack, origin);
5219 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);
5222 Mem_Free(entfiledata);
5226 static void R_Shadow_SetCursorLocationForView(void)
5229 vec3_t dest, endpos;
5231 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5232 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5233 if (trace.fraction < 1)
5235 dist = trace.fraction * r_editlights_cursordistance.value;
5236 push = r_editlights_cursorpushback.value;
5240 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5241 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5245 VectorClear( endpos );
5247 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5248 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5249 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5252 void R_Shadow_UpdateWorldLightSelection(void)
5254 if (r_editlights.integer)
5256 R_Shadow_SetCursorLocationForView();
5257 R_Shadow_SelectLightInView();
5260 R_Shadow_SelectLight(NULL);
5263 static void R_Shadow_EditLights_Clear_f(void)
5265 R_Shadow_ClearWorldLights();
5268 void R_Shadow_EditLights_Reload_f(void)
5272 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5273 R_Shadow_ClearWorldLights();
5274 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5276 R_Shadow_LoadWorldLights();
5277 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5278 R_Shadow_LoadLightsFile();
5280 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5282 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5283 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5287 static void R_Shadow_EditLights_Save_f(void)
5291 R_Shadow_SaveWorldLights();
5294 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5296 R_Shadow_ClearWorldLights();
5297 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5300 static void R_Shadow_EditLights_ImportLightsFile_f(void)
5302 R_Shadow_ClearWorldLights();
5303 R_Shadow_LoadLightsFile();
5306 static void R_Shadow_EditLights_Spawn_f(void)
5309 if (!r_editlights.integer)
5311 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5314 if (Cmd_Argc() != 1)
5316 Con_Print("r_editlights_spawn does not take parameters\n");
5319 color[0] = color[1] = color[2] = 1;
5320 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5323 static void R_Shadow_EditLights_Edit_f(void)
5325 vec3_t origin, angles, color;
5326 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5327 int style, shadows, flags, normalmode, realtimemode;
5328 char cubemapname[MAX_INPUTLINE];
5329 if (!r_editlights.integer)
5331 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5334 if (!r_shadow_selectedlight)
5336 Con_Print("No selected light.\n");
5339 VectorCopy(r_shadow_selectedlight->origin, origin);
5340 VectorCopy(r_shadow_selectedlight->angles, angles);
5341 VectorCopy(r_shadow_selectedlight->color, color);
5342 radius = r_shadow_selectedlight->radius;
5343 style = r_shadow_selectedlight->style;
5344 if (r_shadow_selectedlight->cubemapname)
5345 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5348 shadows = r_shadow_selectedlight->shadow;
5349 corona = r_shadow_selectedlight->corona;
5350 coronasizescale = r_shadow_selectedlight->coronasizescale;
5351 ambientscale = r_shadow_selectedlight->ambientscale;
5352 diffusescale = r_shadow_selectedlight->diffusescale;
5353 specularscale = r_shadow_selectedlight->specularscale;
5354 flags = r_shadow_selectedlight->flags;
5355 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5356 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5357 if (!strcmp(Cmd_Argv(1), "origin"))
5359 if (Cmd_Argc() != 5)
5361 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5364 origin[0] = atof(Cmd_Argv(2));
5365 origin[1] = atof(Cmd_Argv(3));
5366 origin[2] = atof(Cmd_Argv(4));
5368 else if (!strcmp(Cmd_Argv(1), "originscale"))
5370 if (Cmd_Argc() != 5)
5372 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5375 origin[0] *= atof(Cmd_Argv(2));
5376 origin[1] *= atof(Cmd_Argv(3));
5377 origin[2] *= atof(Cmd_Argv(4));
5379 else if (!strcmp(Cmd_Argv(1), "originx"))
5381 if (Cmd_Argc() != 3)
5383 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5386 origin[0] = atof(Cmd_Argv(2));
5388 else if (!strcmp(Cmd_Argv(1), "originy"))
5390 if (Cmd_Argc() != 3)
5392 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5395 origin[1] = atof(Cmd_Argv(2));
5397 else if (!strcmp(Cmd_Argv(1), "originz"))
5399 if (Cmd_Argc() != 3)
5401 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5404 origin[2] = atof(Cmd_Argv(2));
5406 else if (!strcmp(Cmd_Argv(1), "move"))
5408 if (Cmd_Argc() != 5)
5410 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5413 origin[0] += atof(Cmd_Argv(2));
5414 origin[1] += atof(Cmd_Argv(3));
5415 origin[2] += atof(Cmd_Argv(4));
5417 else if (!strcmp(Cmd_Argv(1), "movex"))
5419 if (Cmd_Argc() != 3)
5421 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5424 origin[0] += atof(Cmd_Argv(2));
5426 else if (!strcmp(Cmd_Argv(1), "movey"))
5428 if (Cmd_Argc() != 3)
5430 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5433 origin[1] += atof(Cmd_Argv(2));
5435 else if (!strcmp(Cmd_Argv(1), "movez"))
5437 if (Cmd_Argc() != 3)
5439 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5442 origin[2] += atof(Cmd_Argv(2));
5444 else if (!strcmp(Cmd_Argv(1), "angles"))
5446 if (Cmd_Argc() != 5)
5448 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5451 angles[0] = atof(Cmd_Argv(2));
5452 angles[1] = atof(Cmd_Argv(3));
5453 angles[2] = atof(Cmd_Argv(4));
5455 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5457 if (Cmd_Argc() != 3)
5459 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5462 angles[0] = atof(Cmd_Argv(2));
5464 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5466 if (Cmd_Argc() != 3)
5468 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5471 angles[1] = atof(Cmd_Argv(2));
5473 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5475 if (Cmd_Argc() != 3)
5477 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5480 angles[2] = atof(Cmd_Argv(2));
5482 else if (!strcmp(Cmd_Argv(1), "color"))
5484 if (Cmd_Argc() != 5)
5486 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5489 color[0] = atof(Cmd_Argv(2));
5490 color[1] = atof(Cmd_Argv(3));
5491 color[2] = atof(Cmd_Argv(4));
5493 else if (!strcmp(Cmd_Argv(1), "radius"))
5495 if (Cmd_Argc() != 3)
5497 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5500 radius = atof(Cmd_Argv(2));
5502 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5504 if (Cmd_Argc() == 3)
5506 double scale = atof(Cmd_Argv(2));
5513 if (Cmd_Argc() != 5)
5515 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5518 color[0] *= atof(Cmd_Argv(2));
5519 color[1] *= atof(Cmd_Argv(3));
5520 color[2] *= atof(Cmd_Argv(4));
5523 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5525 if (Cmd_Argc() != 3)
5527 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5530 radius *= atof(Cmd_Argv(2));
5532 else if (!strcmp(Cmd_Argv(1), "style"))
5534 if (Cmd_Argc() != 3)
5536 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5539 style = atoi(Cmd_Argv(2));
5541 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5545 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5548 if (Cmd_Argc() == 3)
5549 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5553 else if (!strcmp(Cmd_Argv(1), "shadows"))
5555 if (Cmd_Argc() != 3)
5557 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5560 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5562 else if (!strcmp(Cmd_Argv(1), "corona"))
5564 if (Cmd_Argc() != 3)
5566 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5569 corona = atof(Cmd_Argv(2));
5571 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5573 if (Cmd_Argc() != 3)
5575 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5578 coronasizescale = atof(Cmd_Argv(2));
5580 else if (!strcmp(Cmd_Argv(1), "ambient"))
5582 if (Cmd_Argc() != 3)
5584 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5587 ambientscale = atof(Cmd_Argv(2));
5589 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5591 if (Cmd_Argc() != 3)
5593 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5596 diffusescale = atof(Cmd_Argv(2));
5598 else if (!strcmp(Cmd_Argv(1), "specular"))
5600 if (Cmd_Argc() != 3)
5602 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5605 specularscale = atof(Cmd_Argv(2));
5607 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5609 if (Cmd_Argc() != 3)
5611 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5614 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5616 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5618 if (Cmd_Argc() != 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5623 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5627 Con_Print("usage: r_editlights_edit [property] [value]\n");
5628 Con_Print("Selected light's properties:\n");
5629 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5630 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5631 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5632 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5633 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5634 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5635 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5636 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5637 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5638 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5639 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5640 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5641 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5642 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5645 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5646 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5649 static void R_Shadow_EditLights_EditAll_f(void)
5652 dlight_t *light, *oldselected;
5655 if (!r_editlights.integer)
5657 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5661 oldselected = r_shadow_selectedlight;
5662 // EditLights doesn't seem to have a "remove" command or something so:
5663 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5664 for (lightindex = 0;lightindex < range;lightindex++)
5666 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5669 R_Shadow_SelectLight(light);
5670 R_Shadow_EditLights_Edit_f();
5672 // return to old selected (to not mess editing once selection is locked)
5673 R_Shadow_SelectLight(oldselected);
5676 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5678 int lightnumber, lightcount;
5679 size_t lightindex, range;
5684 if (!r_editlights.integer)
5687 // update cvars so QC can query them
5688 if (r_shadow_selectedlight)
5690 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5691 Cvar_SetQuick(&r_editlights_current_origin, temp);
5692 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5693 Cvar_SetQuick(&r_editlights_current_angles, temp);
5694 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5695 Cvar_SetQuick(&r_editlights_current_color, temp);
5696 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5697 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5698 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5699 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5700 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5701 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5702 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5703 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5704 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5705 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5706 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5709 // draw properties on screen
5710 if (!r_editlights_drawproperties.integer)
5712 x = vid_conwidth.value - 320;
5714 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5717 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5718 for (lightindex = 0;lightindex < range;lightindex++)
5720 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5723 if (light == r_shadow_selectedlight)
5724 lightnumber = (int)lightindex;
5727 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;
5728 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;
5730 if (r_shadow_selectedlight == NULL)
5732 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;
5733 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;
5734 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;
5735 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;
5736 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;
5737 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;
5738 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;
5739 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;
5740 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;
5741 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;
5742 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;
5743 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;
5744 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;
5745 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;
5746 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;
5748 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;
5749 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;
5750 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;
5751 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;
5752 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;
5753 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;
5754 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;
5755 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;
5756 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;
5757 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;
5760 static void R_Shadow_EditLights_ToggleShadow_f(void)
5762 if (!r_editlights.integer)
5764 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5767 if (!r_shadow_selectedlight)
5769 Con_Print("No selected light.\n");
5772 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);
5775 static void R_Shadow_EditLights_ToggleCorona_f(void)
5777 if (!r_editlights.integer)
5779 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5782 if (!r_shadow_selectedlight)
5784 Con_Print("No selected light.\n");
5787 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);
5790 static void R_Shadow_EditLights_Remove_f(void)
5792 if (!r_editlights.integer)
5794 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5797 if (!r_shadow_selectedlight)
5799 Con_Print("No selected light.\n");
5802 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5803 r_shadow_selectedlight = NULL;
5806 static void R_Shadow_EditLights_Help_f(void)
5809 "Documentation on r_editlights system:\n"
5811 "r_editlights : enable/disable editing mode\n"
5812 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5813 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5814 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5815 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5816 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5818 "r_editlights_help : this help\n"
5819 "r_editlights_clear : remove all lights\n"
5820 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5821 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5822 "r_editlights_save : save to .rtlights file\n"
5823 "r_editlights_spawn : create a light with default settings\n"
5824 "r_editlights_edit command : edit selected light - more documentation below\n"
5825 "r_editlights_remove : remove selected light\n"
5826 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5827 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5828 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5830 "origin x y z : set light location\n"
5831 "originx x: set x component of light location\n"
5832 "originy y: set y component of light location\n"
5833 "originz z: set z component of light location\n"
5834 "move x y z : adjust light location\n"
5835 "movex x: adjust x component of light location\n"
5836 "movey y: adjust y component of light location\n"
5837 "movez z: adjust z component of light location\n"
5838 "angles x y z : set light angles\n"
5839 "anglesx x: set x component of light angles\n"
5840 "anglesy y: set y component of light angles\n"
5841 "anglesz z: set z component of light angles\n"
5842 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5843 "radius radius : set radius (size) of light\n"
5844 "colorscale grey : multiply color of light (1 does nothing)\n"
5845 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5846 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5847 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5848 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5849 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5850 "cubemap basename : set filter cubemap of light\n"
5851 "shadows 1/0 : turn on/off shadows\n"
5852 "corona n : set corona intensity\n"
5853 "coronasize n : set corona size (0-1)\n"
5854 "ambient n : set ambient intensity (0-1)\n"
5855 "diffuse n : set diffuse intensity (0-1)\n"
5856 "specular n : set specular intensity (0-1)\n"
5857 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5858 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5859 "<nothing> : print light properties to console\n"
5863 static void R_Shadow_EditLights_CopyInfo_f(void)
5865 if (!r_editlights.integer)
5867 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5870 if (!r_shadow_selectedlight)
5872 Con_Print("No selected light.\n");
5875 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5876 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5877 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5878 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5879 if (r_shadow_selectedlight->cubemapname)
5880 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5882 r_shadow_bufferlight.cubemapname[0] = 0;
5883 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5884 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5885 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5886 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5887 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5888 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5889 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5892 static void R_Shadow_EditLights_PasteInfo_f(void)
5894 if (!r_editlights.integer)
5896 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5899 if (!r_shadow_selectedlight)
5901 Con_Print("No selected light.\n");
5904 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);
5907 static void R_Shadow_EditLights_Lock_f(void)
5909 if (!r_editlights.integer)
5911 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5914 if (r_editlights_lockcursor)
5916 r_editlights_lockcursor = false;
5919 if (!r_shadow_selectedlight)
5921 Con_Print("No selected light to lock on.\n");
5924 r_editlights_lockcursor = true;
5927 static void R_Shadow_EditLights_Init(void)
5929 Cvar_RegisterVariable(&r_editlights);
5930 Cvar_RegisterVariable(&r_editlights_cursordistance);
5931 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5932 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5933 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5934 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5935 Cvar_RegisterVariable(&r_editlights_drawproperties);
5936 Cvar_RegisterVariable(&r_editlights_current_origin);
5937 Cvar_RegisterVariable(&r_editlights_current_angles);
5938 Cvar_RegisterVariable(&r_editlights_current_color);
5939 Cvar_RegisterVariable(&r_editlights_current_radius);
5940 Cvar_RegisterVariable(&r_editlights_current_corona);
5941 Cvar_RegisterVariable(&r_editlights_current_coronasize);
5942 Cvar_RegisterVariable(&r_editlights_current_style);
5943 Cvar_RegisterVariable(&r_editlights_current_shadows);
5944 Cvar_RegisterVariable(&r_editlights_current_cubemap);
5945 Cvar_RegisterVariable(&r_editlights_current_ambient);
5946 Cvar_RegisterVariable(&r_editlights_current_diffuse);
5947 Cvar_RegisterVariable(&r_editlights_current_specular);
5948 Cvar_RegisterVariable(&r_editlights_current_normalmode);
5949 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
5950 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5951 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5952 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)");
5953 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5954 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5955 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5956 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)");
5957 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5958 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5959 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5960 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5961 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5962 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5963 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)");
5964 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
5970 =============================================================================
5974 =============================================================================
5977 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
5979 int i, numlights, flag, q;
5982 float relativepoint[3];
5987 float sa[3], sx[3], sy[3], sz[3], sd[3];
5990 // use first order spherical harmonics to combine directional lights
5991 for (q = 0; q < 3; q++)
5992 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
5994 if (flags & LP_LIGHTMAP)
5996 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
5998 float tempambient[3];
5999 for (q = 0; q < 3; q++)
6000 tempambient[q] = color[q] = relativepoint[q] = 0;
6001 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6002 // calculate a weighted average light direction as well
6003 intensity = VectorLength(color);
6004 for (q = 0; q < 3; q++)
6006 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6007 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6008 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6009 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6010 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6015 // unlit map - fullbright but scaled by lightmapintensity
6016 for (q = 0; q < 3; q++)
6017 sa[q] += lightmapintensity;
6021 if (flags & LP_RTWORLD)
6023 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6024 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6025 for (i = 0; i < numlights; i++)
6027 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6030 light = &dlight->rtlight;
6031 if (!(light->flags & flag))
6034 lightradius2 = light->radius * light->radius;
6035 VectorSubtract(light->shadoworigin, p, relativepoint);
6036 dist2 = VectorLength2(relativepoint);
6037 if (dist2 >= lightradius2)
6039 dist = sqrt(dist2) / light->radius;
6040 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6041 if (intensity <= 0.0f)
6043 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)
6045 for (q = 0; q < 3; q++)
6046 color[q] = light->currentcolor[q] * intensity;
6047 intensity = VectorLength(color);
6048 VectorNormalize(relativepoint);
6049 for (q = 0; q < 3; q++)
6051 sa[q] += 0.5f * color[q];
6052 sx[q] += relativepoint[0] * color[q];
6053 sy[q] += relativepoint[1] * color[q];
6054 sz[q] += relativepoint[2] * color[q];
6055 sd[q] += intensity * relativepoint[q];
6058 // FIXME: sample bouncegrid too!
6061 if (flags & LP_DYNLIGHT)
6064 for (i = 0;i < r_refdef.scene.numlights;i++)
6066 light = r_refdef.scene.lights[i];
6068 lightradius2 = light->radius * light->radius;
6069 VectorSubtract(light->shadoworigin, p, relativepoint);
6070 dist2 = VectorLength2(relativepoint);
6071 if (dist2 >= lightradius2)
6073 dist = sqrt(dist2) / light->radius;
6074 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6075 if (intensity <= 0.0f)
6077 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)
6079 for (q = 0; q < 3; q++)
6080 color[q] = light->currentcolor[q] * intensity;
6081 intensity = VectorLength(color);
6082 VectorNormalize(relativepoint);
6083 for (q = 0; q < 3; q++)
6085 sa[q] += 0.5f * color[q];
6086 sx[q] += relativepoint[0] * color[q];
6087 sy[q] += relativepoint[1] * color[q];
6088 sz[q] += relativepoint[2] * color[q];
6089 sd[q] += intensity * relativepoint[q];
6094 // calculate the weighted-average light direction (bentnormal)
6095 for (q = 0; q < 3; q++)
6096 lightdir[q] = sd[q];
6097 VectorNormalize(lightdir);
6098 for (q = 0; q < 3; q++)
6100 // extract the diffuse color along the chosen direction and scale it
6101 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6102 // subtract some of diffuse from ambient
6103 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;