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_DISABLED,
28 R_SHADOW_SHADOWMODE_SHADOWMAP2D
30 r_shadow_shadowmode_t;
32 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
33 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
34 int r_shadow_scenemaxlights;
35 int r_shadow_scenenumlights;
36 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
37 qbool r_shadow_usingshadowmap2d;
38 qbool r_shadow_usingshadowmaportho;
39 int r_shadow_shadowmapside;
40 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
41 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
42 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
43 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
45 int r_shadow_drawbuffer;
46 int r_shadow_readbuffer;
48 int r_shadow_cullface_front, r_shadow_cullface_back;
49 GLuint r_shadow_fbo2d;
50 int r_shadow_shadowmode_shadowmapping; // cached value of r_shadow_shadowmapping cvar
51 int r_shadow_shadowmode_deferred; // cached value of r_shadow_deferred cvar
52 r_shadow_shadowmode_t r_shadow_shadowmode;
53 int r_shadow_shadowmapfilterquality;
54 int r_shadow_shadowmapdepthbits;
55 int r_shadow_shadowmapmaxsize;
56 int r_shadow_shadowmaptexturesize;
57 qbool r_shadow_shadowmapvsdct;
58 qbool r_shadow_shadowmapsampler;
59 qbool r_shadow_shadowmapshadowsampler;
60 int r_shadow_shadowmappcf;
61 int r_shadow_shadowmapborder;
62 matrix4x4_t r_shadow_shadowmapmatrix;
63 int r_shadow_lightscissor[4];
64 qbool r_shadow_usingdeferredprepass;
65 qbool r_shadow_shadowmapdepthtexture;
66 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
67 int r_shadow_shadowmapatlas_modelshadows_x;
68 int r_shadow_shadowmapatlas_modelshadows_y;
69 int r_shadow_shadowmapatlas_modelshadows_size;
70 int maxshadowtriangles;
73 int maxshadowvertices;
74 float *shadowvertex3f;
84 unsigned char *shadowsides;
92 int r_shadow_buffer_numleafpvsbytes;
93 unsigned char *r_shadow_buffer_visitingleafpvs;
94 unsigned char *r_shadow_buffer_leafpvs;
95 int *r_shadow_buffer_leaflist;
97 int r_shadow_buffer_numsurfacepvsbytes;
98 unsigned char *r_shadow_buffer_surfacepvs;
99 int *r_shadow_buffer_surfacelist;
100 unsigned char *r_shadow_buffer_surfacesides;
102 int r_shadow_buffer_numshadowtrispvsbytes;
103 unsigned char *r_shadow_buffer_shadowtrispvs;
104 int r_shadow_buffer_numlighttrispvsbytes;
105 unsigned char *r_shadow_buffer_lighttrispvs;
107 rtexturepool_t *r_shadow_texturepool;
108 rtexture_t *r_shadow_attenuationgradienttexture;
109 skinframe_t *r_shadow_lightcorona;
110 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
111 rtexture_t *r_shadow_shadowmap2ddepthtexture;
112 rtexture_t *r_shadow_shadowmapvsdcttexture;
114 GLuint r_shadow_prepassgeometryfbo;
115 GLuint r_shadow_prepasslightingdiffusespecularfbo;
116 GLuint r_shadow_prepasslightingdiffusefbo;
117 int r_shadow_prepass_width;
118 int r_shadow_prepass_height;
119 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
120 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
121 rtexture_t *r_shadow_prepasslightingdiffusetexture;
122 rtexture_t *r_shadow_prepasslightingspeculartexture;
124 int r_shadow_viewfbo;
125 rtexture_t *r_shadow_viewdepthtexture;
126 rtexture_t *r_shadow_viewcolortexture;
129 int r_shadow_viewwidth;
130 int r_shadow_viewheight;
132 // lights are reloaded when this changes
133 char r_shadow_mapname[MAX_QPATH];
135 // buffer for doing corona fading
136 unsigned int r_shadow_occlusion_buf = 0;
138 // used only for light filters (cubemaps)
139 rtexturepool_t *r_shadow_filters_texturepool;
141 cvar_t r_shadow_bumpscale_basetexture = {CF_CLIENT, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
142 cvar_t r_shadow_bumpscale_bumpmap = {CF_CLIENT, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
143 cvar_t r_shadow_debuglight = {CF_CLIENT, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
144 cvar_t r_shadow_deferred = {CF_CLIENT | CF_ARCHIVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
145 cvar_t r_shadow_usebihculling = {CF_CLIENT, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
146 cvar_t r_shadow_usenormalmap = {CF_CLIENT | CF_ARCHIVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
147 cvar_t r_shadow_gloss = {CF_CLIENT | CF_ARCHIVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
148 cvar_t r_shadow_gloss2intensity = {CF_CLIENT, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
149 cvar_t r_shadow_glossintensity = {CF_CLIENT, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
150 cvar_t r_shadow_glossexponent = {CF_CLIENT, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
151 cvar_t r_shadow_gloss2exponent = {CF_CLIENT, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
152 cvar_t r_shadow_glossexact = {CF_CLIENT, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
153 cvar_t r_shadow_lightattenuationdividebias = {CF_CLIENT, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
154 cvar_t r_shadow_lightattenuationlinearscale = {CF_CLIENT, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
155 cvar_t r_shadow_lightintensityscale = {CF_CLIENT, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
156 cvar_t r_shadow_lightradiusscale = {CF_CLIENT, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
157 cvar_t r_shadow_projectdistance = {CF_CLIENT, "r_shadow_projectdistance", "0", "how far to cast shadows"};
158 cvar_t r_shadow_frontsidecasting = {CF_CLIENT, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
159 cvar_t r_shadow_realtime_dlight = {CF_CLIENT | CF_ARCHIVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
160 cvar_t r_shadow_realtime_dlight_shadows = {CF_CLIENT | CF_ARCHIVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
161 cvar_t r_shadow_realtime_dlight_svbspculling = {CF_CLIENT, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
162 cvar_t r_shadow_realtime_dlight_portalculling = {CF_CLIENT, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
163 cvar_t r_shadow_realtime_world = {CF_CLIENT | CF_ARCHIVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
164 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {CF_CLIENT, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
165 cvar_t r_shadow_realtime_world_lightmaps = {CF_CLIENT | CF_ARCHIVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
166 cvar_t r_shadow_realtime_world_shadows = {CF_CLIENT | CF_ARCHIVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
167 cvar_t r_shadow_realtime_world_compile = {CF_CLIENT, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
168 cvar_t r_shadow_realtime_world_compileshadow = {CF_CLIENT, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
169 cvar_t r_shadow_realtime_world_compilesvbsp = {CF_CLIENT, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
170 cvar_t r_shadow_realtime_world_compileportalculling = {CF_CLIENT, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
171 cvar_t r_shadow_scissor = {CF_CLIENT, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
172 cvar_t r_shadow_shadowmapping = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
173 cvar_t r_shadow_shadowmapping_filterquality = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
174 cvar_t r_shadow_shadowmapping_useshadowsampler = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
175 cvar_t r_shadow_shadowmapping_depthbits = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
176 cvar_t r_shadow_shadowmapping_vsdct = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
177 cvar_t r_shadow_shadowmapping_minsize = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
178 cvar_t r_shadow_shadowmapping_maxsize = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
179 cvar_t r_shadow_shadowmapping_texturesize = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
180 cvar_t r_shadow_shadowmapping_precision = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
181 //cvar_t r_shadow_shadowmapping_lod_bias = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
182 //cvar_t r_shadow_shadowmapping_lod_scale = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
183 cvar_t r_shadow_shadowmapping_bordersize = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
184 cvar_t r_shadow_shadowmapping_nearclip = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
185 cvar_t r_shadow_shadowmapping_bias = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
186 cvar_t r_shadow_shadowmapping_polygonfactor = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
187 cvar_t r_shadow_shadowmapping_polygonoffset = {CF_CLIENT | CF_ARCHIVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
188 cvar_t r_shadow_sortsurfaces = {CF_CLIENT, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
189 cvar_t r_shadow_culllights_pvs = {CF_CLIENT | CF_ARCHIVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
190 cvar_t r_shadow_culllights_trace = {CF_CLIENT | CF_ARCHIVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
191 cvar_t r_shadow_culllights_trace_eyejitter = {CF_CLIENT | CF_ARCHIVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
192 cvar_t r_shadow_culllights_trace_enlarge = {CF_CLIENT | CF_ARCHIVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
193 cvar_t r_shadow_culllights_trace_expand = {CF_CLIENT | CF_ARCHIVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
194 cvar_t r_shadow_culllights_trace_pad = {CF_CLIENT | CF_ARCHIVE, "r_shadow_culllights_trace_pad", "8", "accept traces that hit within this many units of the light bounds"};
195 cvar_t r_shadow_culllights_trace_samples = {CF_CLIENT | CF_ARCHIVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
196 cvar_t r_shadow_culllights_trace_tempsamples = {CF_CLIENT | CF_ARCHIVE, "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)"};
197 cvar_t r_shadow_culllights_trace_delay = {CF_CLIENT | CF_ARCHIVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
198 cvar_t r_shadow_bouncegrid = {CF_CLIENT | CF_ARCHIVE, "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)"};
199 cvar_t r_shadow_bouncegrid_blur = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
200 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color"};
201 cvar_t r_shadow_bouncegrid_dynamic_culllightpaths = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_culllightpaths", "0", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
202 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_directionalshading", "1", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
203 cvar_t r_shadow_bouncegrid_dynamic_dlightparticlemultiplier = {CF_CLIENT | CF_ARCHIVE, "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"};
204 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
205 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1)"};
206 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0)"};
207 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {CF_CLIENT | CF_ARCHIVE, "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"};
208 cvar_t r_shadow_bouncegrid_dynamic_quality = {CF_CLIENT | CF_ARCHIVE, "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)"};
209 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
210 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
211 cvar_t r_shadow_bouncegrid_dynamic_x = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
212 cvar_t r_shadow_bouncegrid_dynamic_y = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
213 cvar_t r_shadow_bouncegrid_dynamic_z = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
214 cvar_t r_shadow_bouncegrid_floatcolors = {CF_CLIENT | CF_ARCHIVE, "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"};
215 cvar_t r_shadow_bouncegrid_includedirectlighting = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
216 cvar_t r_shadow_bouncegrid_intensity = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
217 cvar_t r_shadow_bouncegrid_lightpathsize = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_lightpathsize", "64", "radius (in game units) of the light path for accumulation of light in the bouncegrid texture"};
218 cvar_t r_shadow_bouncegrid_normalizevectors = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)"};
219 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_particlebounceintensity", "4", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
220 cvar_t r_shadow_bouncegrid_particleintensity = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
221 cvar_t r_shadow_bouncegrid_rng_seed = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_rng_seed", "0", "0+ = use this number as RNG seed, -1 = use time instead for disco-like craziness in dynamic mode"};
222 cvar_t r_shadow_bouncegrid_rng_type = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)"};
223 cvar_t r_shadow_bouncegrid_static = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
224 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color"};
225 cvar_t r_shadow_bouncegrid_static_directionalshading = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
226 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_static_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
227 cvar_t r_shadow_bouncegrid_static_maxbounce = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
228 cvar_t r_shadow_bouncegrid_static_maxphotons = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
229 cvar_t r_shadow_bouncegrid_static_quality = {CF_CLIENT | CF_ARCHIVE, "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)"};
230 cvar_t r_shadow_bouncegrid_static_spacing = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
231 cvar_t r_shadow_bouncegrid_subsamples = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_subsamples", "1", "when generating the texture, sample this many points along each dimension (multisampling uses more compute but not more memory bandwidth)"};
232 cvar_t r_shadow_bouncegrid_threaded = {CF_CLIENT | CF_ARCHIVE, "r_shadow_bouncegrid_threaded", "1", "enables use of taskqueue_maxthreads to perform the traces and slice rendering of bouncegrid"};
233 cvar_t r_coronas = {CF_CLIENT | CF_ARCHIVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
234 cvar_t r_coronas_occlusionsizescale = {CF_CLIENT | CF_ARCHIVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
235 cvar_t r_coronas_occlusionquery = {CF_CLIENT | CF_ARCHIVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility, requires OpenGL 4.4"};
236 cvar_t gl_flashblend = {CF_CLIENT | CF_ARCHIVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
237 cvar_t r_editlights = {CF_CLIENT, "r_editlights", "0", "enables .rtlights file editing mode"};
238 cvar_t r_editlights_cursordistance = {CF_CLIENT, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
239 cvar_t r_editlights_cursorpushback = {CF_CLIENT, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
240 cvar_t r_editlights_cursorpushoff = {CF_CLIENT, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
241 cvar_t r_editlights_cursorgrid = {CF_CLIENT, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
242 cvar_t r_editlights_quakelightsizescale = {CF_CLIENT | CF_ARCHIVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
243 cvar_t r_editlights_drawproperties = {CF_CLIENT, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
244 cvar_t r_editlights_current_origin = {CF_CLIENT, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
245 cvar_t r_editlights_current_angles = {CF_CLIENT, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
246 cvar_t r_editlights_current_color = {CF_CLIENT, "r_editlights_current_color", "1 1 1", "color of selected light"};
247 cvar_t r_editlights_current_radius = {CF_CLIENT, "r_editlights_current_radius", "0", "radius of selected light"};
248 cvar_t r_editlights_current_corona = {CF_CLIENT, "r_editlights_current_corona", "0", "corona intensity of selected light"};
249 cvar_t r_editlights_current_coronasize = {CF_CLIENT, "r_editlights_current_coronasize", "0", "corona size of selected light"};
250 cvar_t r_editlights_current_style = {CF_CLIENT, "r_editlights_current_style", "0", "style of selected light"};
251 cvar_t r_editlights_current_shadows = {CF_CLIENT, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
252 cvar_t r_editlights_current_cubemap = {CF_CLIENT, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
253 cvar_t r_editlights_current_ambient = {CF_CLIENT, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
254 cvar_t r_editlights_current_diffuse = {CF_CLIENT, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
255 cvar_t r_editlights_current_specular = {CF_CLIENT, "r_editlights_current_specular", "1", "specular intensity of selected light"};
256 cvar_t r_editlights_current_normalmode = {CF_CLIENT, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
257 cvar_t r_editlights_current_realtimemode = {CF_CLIENT, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
259 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
261 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
262 #define ATTENTABLESIZE 256
263 // 1D gradient, 2D circle and 3D sphere attenuation textures
264 #define ATTEN1DSIZE 32
265 #define ATTEN2DSIZE 64
266 #define ATTEN3DSIZE 32
268 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
269 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
270 static float r_shadow_attentable[ATTENTABLESIZE+1];
272 rtlight_t *r_shadow_compilingrtlight;
273 static memexpandablearray_t r_shadow_worldlightsarray;
274 dlight_t *r_shadow_selectedlight;
275 dlight_t r_shadow_bufferlight;
276 vec3_t r_editlights_cursorlocation;
277 qbool r_editlights_lockcursor;
279 extern int con_vislines;
281 void R_Shadow_UncompileWorldLights(void);
282 void R_Shadow_ClearWorldLights(void);
283 void R_Shadow_SaveWorldLights(void);
284 void R_Shadow_LoadWorldLights(void);
285 void R_Shadow_LoadLightsFile(void);
286 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
287 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd);
288 static void R_Shadow_MakeTextures(void);
290 #define EDLIGHTSPRSIZE 8
291 skinframe_t *r_editlights_sprcursor;
292 skinframe_t *r_editlights_sprlight;
293 skinframe_t *r_editlights_sprnoshadowlight;
294 skinframe_t *r_editlights_sprcubemaplight;
295 skinframe_t *r_editlights_sprcubemapnoshadowlight;
296 skinframe_t *r_editlights_sprselection;
298 static void R_Shadow_DrawModelShadowMaps(void);
299 static void R_Shadow_MakeShadowMap(int texturesize);
300 static void R_Shadow_MakeVSDCT(void);
301 static void R_Shadow_SetShadowMode(void)
303 r_shadow_shadowmode_shadowmapping = r_shadow_shadowmapping.integer;
304 r_shadow_shadowmode_deferred = r_shadow_deferred.integer;
305 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
306 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
307 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
308 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
309 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
310 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
311 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
312 r_shadow_shadowmapsampler = false;
313 r_shadow_shadowmappcf = 0;
314 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
315 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_DISABLED;
316 if (r_shadow_shadowmode_shadowmapping || r_shadow_shadowmode_deferred)
318 switch (vid.renderpath)
320 case RENDERPATH_GL32:
321 if (r_shadow_shadowmapfilterquality < 0)
323 if (!r_fb.usedepthtextures)
324 r_shadow_shadowmappcf = 1;
325 else if ((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
327 r_shadow_shadowmapsampler = true;
328 r_shadow_shadowmappcf = 1;
330 else if (vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
331 r_shadow_shadowmappcf = 1;
332 else if ((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
333 r_shadow_shadowmappcf = 1;
335 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
339 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
340 switch (r_shadow_shadowmapfilterquality)
345 r_shadow_shadowmappcf = 1;
348 r_shadow_shadowmappcf = 1;
351 r_shadow_shadowmappcf = 2;
355 if (!r_fb.usedepthtextures)
356 r_shadow_shadowmapsampler = false;
357 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
359 case RENDERPATH_GLES2:
360 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
365 switch (r_shadow_shadowmode)
367 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
368 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
370 case R_SHADOW_SHADOWMODE_DISABLED:
374 if(R_CompileShader_CheckStaticParms())
375 R_GLSL_Restart_f(cmd_local);
378 qbool R_Shadow_ShadowMappingEnabled(void)
380 switch (r_shadow_shadowmode)
382 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
384 case R_SHADOW_SHADOWMODE_DISABLED:
390 static void R_Shadow_FreeShadowMaps(void)
392 R_Shadow_UncompileWorldLights();
394 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
396 R_Shadow_SetShadowMode();
398 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
402 if (r_shadow_shadowmap2ddepthtexture)
403 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
404 r_shadow_shadowmap2ddepthtexture = NULL;
406 if (r_shadow_shadowmap2ddepthbuffer)
407 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
408 r_shadow_shadowmap2ddepthbuffer = NULL;
410 if (r_shadow_shadowmapvsdcttexture)
411 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
412 r_shadow_shadowmapvsdcttexture = NULL;
416 static void r_shadow_start(void)
418 // allocate vertex processing arrays
419 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
420 r_shadow_attenuationgradienttexture = NULL;
421 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_DISABLED;
422 r_shadow_shadowmap2ddepthtexture = NULL;
423 r_shadow_shadowmap2ddepthbuffer = NULL;
424 r_shadow_shadowmapvsdcttexture = NULL;
425 r_shadow_shadowmapmaxsize = 0;
426 r_shadow_shadowmaptexturesize = 0;
427 r_shadow_shadowmapfilterquality = -1;
428 r_shadow_shadowmapdepthbits = 0;
429 r_shadow_shadowmapvsdct = false;
430 r_shadow_shadowmapsampler = false;
431 r_shadow_shadowmappcf = 0;
434 R_Shadow_FreeShadowMaps();
436 r_shadow_texturepool = NULL;
437 r_shadow_filters_texturepool = NULL;
438 R_Shadow_MakeTextures();
439 r_shadow_scenemaxlights = 0;
440 r_shadow_scenenumlights = 0;
441 r_shadow_scenelightlist = NULL;
442 maxshadowtriangles = 0;
443 shadowelements = NULL;
444 maxshadowvertices = 0;
445 shadowvertex3f = NULL;
453 shadowmarklist = NULL;
458 shadowsideslist = NULL;
459 r_shadow_buffer_numleafpvsbytes = 0;
460 r_shadow_buffer_visitingleafpvs = NULL;
461 r_shadow_buffer_leafpvs = NULL;
462 r_shadow_buffer_leaflist = NULL;
463 r_shadow_buffer_numsurfacepvsbytes = 0;
464 r_shadow_buffer_surfacepvs = NULL;
465 r_shadow_buffer_surfacelist = NULL;
466 r_shadow_buffer_surfacesides = NULL;
467 r_shadow_buffer_numshadowtrispvsbytes = 0;
468 r_shadow_buffer_shadowtrispvs = NULL;
469 r_shadow_buffer_numlighttrispvsbytes = 0;
470 r_shadow_buffer_lighttrispvs = NULL;
472 r_shadow_usingdeferredprepass = false;
473 r_shadow_prepass_width = r_shadow_prepass_height = 0;
475 // determine renderpath specific capabilities, we don't need to figure
476 // these out per frame...
477 switch(vid.renderpath)
479 case RENDERPATH_GL32:
480 r_shadow_bouncegrid_state.allowdirectionalshading = true;
481 r_shadow_bouncegrid_state.capable = true;
483 case RENDERPATH_GLES2:
484 // for performance reasons, do not use directional shading on GLES devices
485 r_shadow_bouncegrid_state.capable = true;
490 static void R_Shadow_BounceGrid_FreeHighPixels(void)
492 r_shadow_bouncegrid_state.highpixels = NULL;
493 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
494 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
495 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
496 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
497 if (r_shadow_bouncegrid_state.photons) { Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL; }
498 if (r_shadow_bouncegrid_state.photons_tasks) { Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL; }
499 if (r_shadow_bouncegrid_state.slices_tasks) { Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL; }
502 static void R_Shadow_FreeDeferred(void);
503 static void r_shadow_shutdown(void)
507 R_Shadow_FreeShadowMaps();
509 r_shadow_usingdeferredprepass = false;
510 if (r_shadow_prepass_width)
511 R_Shadow_FreeDeferred();
512 r_shadow_prepass_width = r_shadow_prepass_height = 0;
515 r_shadow_scenemaxlights = 0;
516 r_shadow_scenenumlights = 0;
517 if (r_shadow_scenelightlist)
518 Mem_Free(r_shadow_scenelightlist);
519 r_shadow_scenelightlist = NULL;
520 R_Shadow_BounceGrid_FreeHighPixels();
521 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
522 r_shadow_attenuationgradienttexture = NULL;
523 R_FreeTexturePool(&r_shadow_texturepool);
524 R_FreeTexturePool(&r_shadow_filters_texturepool);
525 maxshadowtriangles = 0;
527 Mem_Free(shadowelements);
528 shadowelements = NULL;
530 Mem_Free(shadowvertex3f);
531 shadowvertex3f = NULL;
534 Mem_Free(vertexupdate);
537 Mem_Free(vertexremap);
543 Mem_Free(shadowmark);
546 Mem_Free(shadowmarklist);
547 shadowmarklist = NULL;
552 Mem_Free(shadowsides);
555 Mem_Free(shadowsideslist);
556 shadowsideslist = NULL;
557 r_shadow_buffer_numleafpvsbytes = 0;
558 if (r_shadow_buffer_visitingleafpvs)
559 Mem_Free(r_shadow_buffer_visitingleafpvs);
560 r_shadow_buffer_visitingleafpvs = NULL;
561 if (r_shadow_buffer_leafpvs)
562 Mem_Free(r_shadow_buffer_leafpvs);
563 r_shadow_buffer_leafpvs = NULL;
564 if (r_shadow_buffer_leaflist)
565 Mem_Free(r_shadow_buffer_leaflist);
566 r_shadow_buffer_leaflist = NULL;
567 r_shadow_buffer_numsurfacepvsbytes = 0;
568 if (r_shadow_buffer_surfacepvs)
569 Mem_Free(r_shadow_buffer_surfacepvs);
570 r_shadow_buffer_surfacepvs = NULL;
571 if (r_shadow_buffer_surfacelist)
572 Mem_Free(r_shadow_buffer_surfacelist);
573 r_shadow_buffer_surfacelist = NULL;
574 if (r_shadow_buffer_surfacesides)
575 Mem_Free(r_shadow_buffer_surfacesides);
576 r_shadow_buffer_surfacesides = NULL;
577 r_shadow_buffer_numshadowtrispvsbytes = 0;
578 if (r_shadow_buffer_shadowtrispvs)
579 Mem_Free(r_shadow_buffer_shadowtrispvs);
580 r_shadow_buffer_numlighttrispvsbytes = 0;
581 if (r_shadow_buffer_lighttrispvs)
582 Mem_Free(r_shadow_buffer_lighttrispvs);
585 static void r_shadow_newmap(void)
587 R_Shadow_BounceGrid_FreeHighPixels();
589 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
590 if (r_shadow_lightcorona) { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
591 if (r_editlights_sprcursor) { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
592 if (r_editlights_sprlight) { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
593 if (r_editlights_sprnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
594 if (r_editlights_sprcubemaplight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
595 if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
596 if (r_editlights_sprselection) { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
597 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
598 R_Shadow_EditLights_Reload_f(cmd_local);
601 void R_Shadow_Init(void)
603 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
604 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
605 Cvar_RegisterVariable(&r_shadow_usebihculling);
606 Cvar_RegisterVariable(&r_shadow_usenormalmap);
607 Cvar_RegisterVariable(&r_shadow_debuglight);
608 Cvar_RegisterVariable(&r_shadow_deferred);
609 Cvar_RegisterVariable(&r_shadow_gloss);
610 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
611 Cvar_RegisterVariable(&r_shadow_glossintensity);
612 Cvar_RegisterVariable(&r_shadow_glossexponent);
613 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
614 Cvar_RegisterVariable(&r_shadow_glossexact);
615 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
616 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
617 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
618 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
619 Cvar_RegisterVariable(&r_shadow_projectdistance);
620 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
621 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
622 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
623 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
624 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
625 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
626 Cvar_RegisterVariable(&r_shadow_realtime_world);
627 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
628 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
629 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
630 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
631 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
632 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
633 Cvar_RegisterVariable(&r_shadow_scissor);
634 Cvar_RegisterVariable(&r_shadow_shadowmapping);
635 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
636 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
637 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
638 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
639 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
640 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
641 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
642 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
643 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
644 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
645 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
646 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
647 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
648 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
649 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
650 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
651 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
652 Cvar_RegisterVariable(&r_shadow_culllights_trace);
653 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
654 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
655 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
656 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
657 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
658 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
659 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
660 Cvar_RegisterVariable(&r_shadow_bouncegrid);
661 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
662 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
663 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
664 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
665 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
666 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
667 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
668 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
669 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
670 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
671 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
672 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
673 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
674 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
675 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
676 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
677 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
678 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
679 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
680 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
681 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
682 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
683 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
684 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
685 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
686 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
687 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
688 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
689 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
690 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
691 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
692 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
693 Cvar_RegisterVariable(&r_shadow_bouncegrid_subsamples);
694 Cvar_RegisterVariable(&r_shadow_bouncegrid_threaded);
695 Cvar_RegisterVariable(&r_coronas);
696 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
697 Cvar_RegisterVariable(&r_coronas_occlusionquery);
698 Cvar_RegisterVariable(&gl_flashblend);
699 R_Shadow_EditLights_Init();
700 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
701 r_shadow_scenemaxlights = 0;
702 r_shadow_scenenumlights = 0;
703 r_shadow_scenelightlist = NULL;
704 maxshadowtriangles = 0;
705 shadowelements = NULL;
706 maxshadowvertices = 0;
707 shadowvertex3f = NULL;
715 shadowmarklist = NULL;
720 shadowsideslist = NULL;
721 r_shadow_buffer_numleafpvsbytes = 0;
722 r_shadow_buffer_visitingleafpvs = NULL;
723 r_shadow_buffer_leafpvs = NULL;
724 r_shadow_buffer_leaflist = NULL;
725 r_shadow_buffer_numsurfacepvsbytes = 0;
726 r_shadow_buffer_surfacepvs = NULL;
727 r_shadow_buffer_surfacelist = NULL;
728 r_shadow_buffer_surfacesides = NULL;
729 r_shadow_buffer_shadowtrispvs = NULL;
730 r_shadow_buffer_lighttrispvs = NULL;
731 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
734 matrix4x4_t matrix_attenuationxyz =
737 {0.5, 0.0, 0.0, 0.5},
738 {0.0, 0.5, 0.0, 0.5},
739 {0.0, 0.0, 0.5, 0.5},
744 matrix4x4_t matrix_attenuationz =
747 {0.0, 0.0, 0.5, 0.5},
748 {0.0, 0.0, 0.0, 0.5},
749 {0.0, 0.0, 0.0, 0.5},
754 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
756 numvertices = ((numvertices + 255) & ~255) * vertscale;
757 numtriangles = ((numtriangles + 255) & ~255) * triscale;
758 // make sure shadowelements is big enough for this volume
759 if (maxshadowtriangles < numtriangles)
761 maxshadowtriangles = numtriangles;
763 Mem_Free(shadowelements);
764 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
766 // make sure shadowvertex3f is big enough for this volume
767 if (maxshadowvertices < numvertices)
769 maxshadowvertices = numvertices;
771 Mem_Free(shadowvertex3f);
772 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
776 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
778 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
779 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
780 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
781 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
782 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
784 if (r_shadow_buffer_visitingleafpvs)
785 Mem_Free(r_shadow_buffer_visitingleafpvs);
786 if (r_shadow_buffer_leafpvs)
787 Mem_Free(r_shadow_buffer_leafpvs);
788 if (r_shadow_buffer_leaflist)
789 Mem_Free(r_shadow_buffer_leaflist);
790 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
791 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
792 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
793 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
795 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
797 if (r_shadow_buffer_surfacepvs)
798 Mem_Free(r_shadow_buffer_surfacepvs);
799 if (r_shadow_buffer_surfacelist)
800 Mem_Free(r_shadow_buffer_surfacelist);
801 if (r_shadow_buffer_surfacesides)
802 Mem_Free(r_shadow_buffer_surfacesides);
803 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
804 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
805 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
806 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
808 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
810 if (r_shadow_buffer_shadowtrispvs)
811 Mem_Free(r_shadow_buffer_shadowtrispvs);
812 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
813 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
815 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
817 if (r_shadow_buffer_lighttrispvs)
818 Mem_Free(r_shadow_buffer_lighttrispvs);
819 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
820 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
824 void R_Shadow_PrepareShadowMark(int numtris)
826 // make sure shadowmark is big enough for this volume
827 if (maxshadowmark < numtris)
829 maxshadowmark = numtris;
831 Mem_Free(shadowmark);
833 Mem_Free(shadowmarklist);
834 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
835 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
839 // if shadowmarkcount wrapped we clear the array and adjust accordingly
840 if (shadowmarkcount == 0)
843 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
848 void R_Shadow_PrepareShadowSides(int numtris)
850 if (maxshadowsides < numtris)
852 maxshadowsides = numtris;
854 Mem_Free(shadowsides);
856 Mem_Free(shadowsideslist);
857 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
858 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
863 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
865 // p1, p2, p3 are in the cubemap's local coordinate system
866 // bias = border/(size - border)
869 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
870 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
871 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
872 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
874 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
875 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
876 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
877 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
879 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
880 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
881 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
883 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
884 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
885 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
886 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
888 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
889 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
890 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
891 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
893 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
894 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
895 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
897 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
898 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
899 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
900 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
902 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
903 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
904 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
905 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
907 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
908 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
909 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
914 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
916 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
917 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
920 VectorSubtract(maxs, mins, radius);
921 VectorScale(radius, 0.5f, radius);
922 VectorAdd(mins, radius, center);
923 Matrix4x4_Transform(worldtolight, center, lightcenter);
924 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
925 VectorSubtract(lightcenter, lightradius, pmin);
926 VectorAdd(lightcenter, lightradius, pmax);
928 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
929 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
930 if(ap1 > bias*an1 && ap2 > bias*an2)
932 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
933 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
934 if(an1 > bias*ap1 && an2 > bias*ap2)
936 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
937 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
939 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
940 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
941 if(ap1 > bias*an1 && ap2 > bias*an2)
943 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
944 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
945 if(an1 > bias*ap1 && an2 > bias*ap2)
947 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
948 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
950 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
951 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
952 if(ap1 > bias*an1 && ap2 > bias*an2)
954 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
955 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
956 if(an1 > bias*ap1 && an2 > bias*ap2)
958 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
959 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
964 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
966 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
968 // p is in the cubemap's local coordinate system
969 // bias = border/(size - border)
970 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
971 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
972 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
974 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
975 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
976 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
977 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
978 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
979 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
983 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
987 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
988 float scale = (size - 2*border)/size, len;
989 float bias = border / (float)(size - border), dp, dn, ap, an;
990 // check if cone enclosing side would cross frustum plane
991 scale = 2 / (scale*scale + 2);
992 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
993 for (i = 0;i < 5;i++)
995 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
997 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
998 len = scale*VectorLength2(n);
999 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1000 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1001 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1003 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1005 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1006 len = scale*VectorLength2(n);
1007 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1008 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1009 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1011 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1012 // check if frustum corners/origin cross plane sides
1014 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1015 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1016 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1017 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1018 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1019 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1020 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1021 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1022 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1023 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1024 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1025 for (i = 0;i < 4;i++)
1027 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1028 VectorSubtract(n, p, n);
1029 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1030 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1031 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1032 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1033 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1034 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1035 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1036 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1037 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1040 // finite version, assumes corners are a finite distance from origin dependent on far plane
1041 for (i = 0;i < 5;i++)
1043 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1044 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1045 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1046 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1047 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1048 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1049 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1050 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1051 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1052 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1055 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1058 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)
1066 int mask, surfacemask = 0;
1067 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1069 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1070 tend = firsttriangle + numtris;
1071 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1073 // surface box entirely inside light box, no box cull
1074 if (projectdirection)
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 TriangleNormal(v[0], v[1], v[2], normal);
1080 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1082 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1083 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1084 surfacemask |= mask;
1087 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;
1088 shadowsides[numshadowsides] = mask;
1089 shadowsideslist[numshadowsides++] = t;
1096 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1098 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1099 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1101 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1102 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1103 surfacemask |= mask;
1106 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;
1107 shadowsides[numshadowsides] = mask;
1108 shadowsideslist[numshadowsides++] = t;
1116 // surface box not entirely inside light box, cull each triangle
1117 if (projectdirection)
1119 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1121 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1122 TriangleNormal(v[0], v[1], v[2], normal);
1123 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
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;
1140 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1142 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1143 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1144 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1146 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1147 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1148 surfacemask |= mask;
1151 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;
1152 shadowsides[numshadowsides] = mask;
1153 shadowsideslist[numshadowsides++] = t;
1162 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)
1164 int i, j, outtriangles = 0;
1165 int *outelement3i[6];
1166 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1168 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1169 // make sure shadowelements is big enough for this mesh
1170 if (maxshadowtriangles < outtriangles)
1171 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1173 // compute the offset and size of the separate index lists for each cubemap side
1175 for (i = 0;i < 6;i++)
1177 outelement3i[i] = shadowelements + outtriangles * 3;
1178 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1179 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1180 outtriangles += sidetotals[i];
1183 // gather up the (sparse) triangles into separate index lists for each cubemap side
1184 for (i = 0;i < numsidetris;i++)
1186 const int *element = elements + sidetris[i] * 3;
1187 for (j = 0;j < 6;j++)
1189 if (sides[i] & (1 << j))
1191 outelement3i[j][0] = element[0];
1192 outelement3i[j][1] = element[1];
1193 outelement3i[j][2] = element[2];
1194 outelement3i[j] += 3;
1199 Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1202 static void R_Shadow_MakeTextures_MakeCorona(void)
1206 unsigned char pixels[32][32][4];
1207 for (y = 0;y < 32;y++)
1209 dy = (y - 15.5f) * (1.0f / 16.0f);
1210 for (x = 0;x < 32;x++)
1212 dx = (x - 15.5f) * (1.0f / 16.0f);
1213 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1214 a = bound(0, a, 255);
1215 pixels[y][x][0] = a;
1216 pixels[y][x][1] = a;
1217 pixels[y][x][2] = a;
1218 pixels[y][x][3] = 255;
1221 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1224 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1226 float dist = sqrt(x*x+y*y+z*z);
1227 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1228 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1229 return bound(0, (unsigned int)(intensity * 256.0f), 255) * 0x01010101U;
1232 static void R_Shadow_MakeTextures(void)
1235 float intensity, dist;
1237 R_Shadow_FreeShadowMaps();
1238 R_FreeTexturePool(&r_shadow_texturepool);
1239 r_shadow_texturepool = R_AllocTexturePool();
1240 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1241 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1242 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1243 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1244 for (x = 0;x <= ATTENTABLESIZE;x++)
1246 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1247 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1248 r_shadow_attentable[x] = bound(0, intensity, 1);
1250 // 1D gradient texture
1251 for (x = 0;x < ATTEN1DSIZE;x++)
1252 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1253 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1256 R_Shadow_MakeTextures_MakeCorona();
1258 // Editor light sprites
1259 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1276 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1277 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1294 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1295 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1312 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1313 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1330 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1331 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1348 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1349 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1366 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1369 void R_Shadow_RenderMode_Begin(void)
1376 if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1377 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1378 R_Shadow_MakeTextures();
1381 R_Mesh_ResetTextureState();
1382 GL_BlendFunc(GL_ONE, GL_ZERO);
1383 GL_DepthRange(0, 1);
1384 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1386 GL_DepthMask(false);
1387 GL_Color(0, 0, 0, 1);
1388 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1390 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1391 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1395 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1396 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1397 r_shadow_drawbuffer = drawbuffer;
1398 r_shadow_readbuffer = readbuffer;
1400 r_shadow_cullface_front = r_refdef.view.cullface_front;
1401 r_shadow_cullface_back = r_refdef.view.cullface_back;
1404 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1406 rsurface.rtlight = rtlight;
1409 void R_Shadow_RenderMode_Reset(void)
1411 R_Mesh_ResetTextureState();
1412 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1413 R_SetViewport(&r_refdef.view.viewport);
1414 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1415 GL_DepthRange(0, 1);
1417 GL_DepthMask(false);
1418 GL_DepthFunc(GL_LEQUAL);
1419 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1420 r_refdef.view.cullface_front = r_shadow_cullface_front;
1421 r_refdef.view.cullface_back = r_shadow_cullface_back;
1422 GL_CullFace(r_refdef.view.cullface_back);
1423 GL_Color(1, 1, 1, 1);
1424 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1425 GL_BlendFunc(GL_ONE, GL_ZERO);
1426 R_SetupShader_Generic_NoTexture(false, false);
1427 r_shadow_usingshadowmap2d = false;
1430 void R_Shadow_ClearStencil(void)
1432 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1433 r_refdef.stats[r_stat_lights_clears]++;
1436 static void R_Shadow_MakeVSDCT(void)
1438 // maps to a 2x3 texture rectangle with normalized coordinates
1443 // stores abs(dir.xy), offset.xy/2.5
1444 unsigned char data[4*6] =
1446 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1447 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1448 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1449 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1450 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1451 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1453 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1456 static void R_Shadow_MakeShadowMap(int texturesize)
1458 switch (r_shadow_shadowmode)
1460 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1461 if (r_shadow_shadowmap2ddepthtexture) return;
1462 if (r_fb.usedepthtextures)
1464 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);
1465 r_shadow_shadowmap2ddepthbuffer = NULL;
1466 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1470 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1471 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1472 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1475 case R_SHADOW_SHADOWMODE_DISABLED:
1480 void R_Shadow_ClearShadowMapTexture(void)
1482 r_viewport_t viewport;
1483 float clearcolor[4];
1485 // if they don't exist, create our textures now
1486 if (!r_shadow_shadowmap2ddepthtexture)
1487 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1488 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1489 R_Shadow_MakeVSDCT();
1491 // we're setting up to render shadowmaps, so change rendermode
1492 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1494 R_Mesh_ResetTextureState();
1495 R_Shadow_RenderMode_Reset();
1496 if (r_shadow_shadowmap2ddepthbuffer)
1497 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1499 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1500 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1501 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1505 // we have to set a viewport to clear anything in some renderpaths (D3D)
1506 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1507 R_SetViewport(&viewport);
1508 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1509 if (r_shadow_shadowmap2ddepthbuffer)
1510 GL_ColorMask(1, 1, 1, 1);
1512 GL_ColorMask(0, 0, 0, 0);
1513 switch (vid.renderpath)
1515 case RENDERPATH_GL32:
1516 case RENDERPATH_GLES2:
1517 GL_CullFace(r_refdef.view.cullface_back);
1520 Vector4Set(clearcolor, 1, 1, 1, 1);
1521 if (r_shadow_shadowmap2ddepthbuffer)
1522 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1524 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1527 static void R_Shadow_SetShadowmapParametersForLight(qbool noselfshadowpass)
1529 int size = rsurface.rtlight->shadowmapatlassidesize;
1530 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1531 float farclip = 1.0f;
1532 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1533 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1534 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1535 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1536 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1537 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1538 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1539 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1540 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1541 if (r_shadow_shadowmap2ddepthbuffer)
1543 // completely different meaning than in depthtexture approach
1544 r_shadow_lightshadowmap_parameters[1] = 0;
1545 r_shadow_lightshadowmap_parameters[3] = -bias;
1549 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1551 float nearclip, farclip;
1552 r_viewport_t viewport;
1555 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1557 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1559 R_Mesh_ResetTextureState();
1560 R_Shadow_RenderMode_Reset();
1561 if (r_shadow_shadowmap2ddepthbuffer)
1562 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1564 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1565 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1566 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1571 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1574 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1575 R_SetViewport(&viewport);
1576 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1577 flipped = (side & 1) ^ (side >> 2);
1578 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1579 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1581 if (r_shadow_shadowmap2ddepthbuffer)
1582 GL_ColorMask(1,1,1,1);
1584 GL_ColorMask(0,0,0,0);
1585 switch(vid.renderpath)
1587 case RENDERPATH_GL32:
1588 case RENDERPATH_GLES2:
1589 GL_CullFace(r_refdef.view.cullface_back);
1593 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1594 r_shadow_shadowmapside = side;
1597 void R_Shadow_RenderMode_Lighting(qbool transparent, qbool shadowmapping, qbool noselfshadowpass)
1599 R_Mesh_ResetTextureState();
1602 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1603 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1604 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1605 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1608 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1609 R_Shadow_RenderMode_Reset();
1610 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1612 GL_DepthFunc(GL_EQUAL);
1613 // do global setup needed for the chosen lighting mode
1614 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1615 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1616 r_shadow_usingshadowmap2d = shadowmapping;
1617 r_shadow_rendermode = r_shadow_lightingrendermode;
1620 static const unsigned short bboxelements[36] =
1630 static const float bboxpoints[8][3] =
1642 void R_Shadow_RenderMode_DrawDeferredLight(qbool shadowmapping)
1645 float vertex3f[8*3];
1646 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1647 // do global setup needed for the chosen lighting mode
1648 R_Shadow_RenderMode_Reset();
1649 r_shadow_rendermode = r_shadow_lightingrendermode;
1650 R_EntityMatrix(&identitymatrix);
1651 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1652 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1653 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1655 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1657 r_shadow_usingshadowmap2d = shadowmapping;
1659 // render the lighting
1660 R_SetupShader_DeferredLight(rsurface.rtlight);
1661 for (i = 0;i < 8;i++)
1662 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1663 GL_ColorMask(1,1,1,1);
1664 GL_DepthMask(false);
1665 GL_DepthRange(0, 1);
1666 GL_PolygonOffset(0, 0);
1668 GL_DepthFunc(GL_GREATER);
1669 GL_CullFace(r_refdef.view.cullface_back);
1670 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1671 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1674 static qbool R_Shadow_BounceGrid_CheckEnable(int flag)
1676 qbool enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1683 // see if there are really any lights to render...
1684 if (enable && r_shadow_bouncegrid_static.integer)
1687 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1688 for (lightindex = 0;lightindex < range;lightindex++)
1690 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1691 if (!light || !(light->flags & flag))
1693 rtlight = &light->rtlight;
1694 // when static, we skip styled lights because they tend to change...
1695 if (rtlight->style > 0)
1697 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1698 if (!VectorLength2(lightcolor))
1708 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1710 qbool s = r_shadow_bouncegrid_static.integer != 0;
1711 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1712 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1713 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1715 // prevent any garbage in alignment padded areas as we'll be using memcmp
1716 memset(settings, 0, sizeof(*settings));
1718 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1719 settings->staticmode = s;
1720 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
1721 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1722 settings->lightpathsize = bound(0.0f, r_shadow_bouncegrid_lightpathsize.value, 1024.0f);
1723 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1724 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1725 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1726 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1727 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1728 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1729 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
1730 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) / 65536.0f;
1731 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1732 settings->energyperphoton = 4096.0f / quality;
1733 settings->spacing[0] = spacing;
1734 settings->spacing[1] = spacing;
1735 settings->spacing[2] = spacing;
1736 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
1737 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
1738 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
1739 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
1740 settings->subsamples = bound(1, r_shadow_bouncegrid_subsamples.integer, 4);
1742 // bound the values for sanity
1743 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1744 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1745 settings->maxbounce = bound(0, settings->maxbounce, 16);
1746 settings->spacing[0] = bound(1, settings->spacing[0], 512);
1747 settings->spacing[1] = bound(1, settings->spacing[1], 512);
1748 settings->spacing[2] = bound(1, settings->spacing[2], 512);
1751 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1758 vec3_t maxs = {0,0,0};
1759 vec3_t mins = {0,0,0};
1762 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1764 // get the spacing values
1765 spacing[0] = settings->spacing[0];
1766 spacing[1] = settings->spacing[1];
1767 spacing[2] = settings->spacing[2];
1768 ispacing[0] = 1.0f / spacing[0];
1769 ispacing[1] = 1.0f / spacing[1];
1770 ispacing[2] = 1.0f / spacing[2];
1772 // calculate texture size enclosing entire world bounds at the spacing
1773 if (r_refdef.scene.worldmodel)
1777 qbool bounds_set = false;
1781 // calculate bounds enclosing world lights as they should be noticably tighter
1782 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1783 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1784 for (lightindex = 0;lightindex < range;lightindex++)
1786 const vec_t *rtlmins, *rtlmaxs;
1788 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1792 rtlight = &light->rtlight;
1793 rtlmins = rtlight->cullmins;
1794 rtlmaxs = rtlight->cullmaxs;
1798 VectorCopy(rtlmins, mins);
1799 VectorCopy(rtlmaxs, maxs);
1804 mins[0] = min(mins[0], rtlmins[0]);
1805 mins[1] = min(mins[1], rtlmins[1]);
1806 mins[2] = min(mins[2], rtlmins[2]);
1807 maxs[0] = max(maxs[0], rtlmaxs[0]);
1808 maxs[1] = max(maxs[1], rtlmaxs[1]);
1809 maxs[2] = max(maxs[2], rtlmaxs[2]);
1813 // limit to no larger than the world bounds
1814 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1815 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1816 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1817 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1818 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1819 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1821 VectorMA(mins, -2.0f, spacing, mins);
1822 VectorMA(maxs, 2.0f, spacing, maxs);
1826 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1827 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
1829 VectorSubtract(maxs, mins, size);
1830 // now we can calculate the resolution we want
1831 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1832 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1833 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1834 // figure out the exact texture size (honoring power of 2 if required)
1835 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1836 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1837 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1838 size[0] = spacing[0] * resolution[0];
1839 size[1] = spacing[1] * resolution[1];
1840 size[2] = spacing[2] * resolution[2];
1842 // if dynamic we may or may not want to use the world bounds
1843 // if the dynamic size is smaller than the world bounds, use it instead
1844 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]))
1846 // we know the resolution we want
1847 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1848 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1849 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1850 // now we can calculate the texture size
1851 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1852 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1853 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1854 size[0] = spacing[0] * resolution[0];
1855 size[1] = spacing[1] * resolution[1];
1856 size[2] = spacing[2] * resolution[2];
1857 // center the rendering on the view
1858 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1859 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1860 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1863 // recalculate the maxs in case the resolution was not satisfactory
1864 VectorAdd(mins, size, maxs);
1866 // check if this changed the texture size
1867 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);
1868 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1869 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1870 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1871 VectorCopy(size, r_shadow_bouncegrid_state.size);
1872 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1873 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1874 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1876 // reallocate pixels for this update if needed...
1877 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1878 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1879 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1880 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1881 if (r_shadow_bouncegrid_state.numpixels != numpixels)
1883 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1885 R_Shadow_BounceGrid_FreeHighPixels();
1887 r_shadow_bouncegrid_state.numpixels = numpixels;
1890 // update the bouncegrid matrix to put it in the world properly
1891 memset(m, 0, sizeof(m));
1892 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1893 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1894 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1895 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1896 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1897 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1899 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1902 static float R_Shadow_BounceGrid_RefractiveIndexAtPoint(vec3_t point)
1904 // check material at shadoworigin to see what the initial refractive index should be
1905 int hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
1906 int skipsupercontentsmask = 0;
1907 int skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
1908 trace_t trace = CL_TracePoint(point, r_shadow_bouncegrid_state.settings.staticmode ? MOVE_WORLDONLY : (r_shadow_bouncegrid_state.settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, true, false, NULL, true);
1909 if (trace.starttexture && (trace.starttexture->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)))
1910 return trace.starttexture->refractive_index;
1911 else if (trace.startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
1912 return 1.333f; // water
1914 return 1.0003f; // air
1917 // enumerate world rtlights and sum the overall amount of light in the world,
1918 // from that we can calculate a scaling factor to fairly distribute photons
1919 // to all the lights
1921 // this modifies rtlight->photoncolor and rtlight->photons
1922 static void R_Shadow_BounceGrid_AssignPhotons_Task(taskqueue_task_t *t)
1924 // get the range of light numbers we'll be looping over:
1925 // range = static lights
1926 // range1 = dynamic lights (optional)
1927 // range2 = range + range1
1928 unsigned int range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1929 unsigned int range1 = r_shadow_bouncegrid_state.settings.staticmode ? 0 : r_refdef.scene.numlights;
1930 unsigned int range2 = range + range1;
1931 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
1933 float normalphotonscaling;
1934 float photonscaling;
1935 float photonintensity;
1936 float photoncount = 0.0f;
1937 float lightintensity;
1943 unsigned int lightindex;
1948 float bounceminimumintensity2;
1949 float startrefractiveindex;
1951 randomseed_t randomseed;
1952 vec3_t baseshotcolor;
1954 normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1955 for (lightindex = 0;lightindex < range2;lightindex++)
1957 if (lightindex < range)
1959 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1962 rtlight = &light->rtlight;
1963 VectorClear(rtlight->bouncegrid_photoncolor);
1964 rtlight->bouncegrid_photons = 0;
1965 rtlight->bouncegrid_hits = 0;
1966 rtlight->bouncegrid_traces = 0;
1967 rtlight->bouncegrid_effectiveradius = 0;
1968 if (!(light->flags & flag))
1970 if (r_shadow_bouncegrid_state.settings.staticmode)
1972 // when static, we skip styled lights because they tend to change...
1973 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
1976 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
1981 rtlight = r_refdef.scene.lights[lightindex - range];
1982 VectorClear(rtlight->bouncegrid_photoncolor);
1983 rtlight->bouncegrid_photons = 0;
1984 rtlight->bouncegrid_hits = 0;
1985 rtlight->bouncegrid_traces = 0;
1986 rtlight->bouncegrid_effectiveradius = 0;
1988 // draw only visible lights (major speedup)
1989 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
1990 cullmins[0] = rtlight->shadoworigin[0] - radius;
1991 cullmins[1] = rtlight->shadoworigin[1] - radius;
1992 cullmins[2] = rtlight->shadoworigin[2] - radius;
1993 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
1994 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
1995 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
1996 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
1997 if (!r_shadow_bouncegrid_state.settings.staticmode)
1999 // skip if the expanded light box does not touch any visible leafs
2000 if (r_refdef.scene.worldmodel
2001 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2002 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2004 // skip if the expanded light box is not visible to traceline
2005 // note that PrepareLight already did this check but for a smaller box, so we
2006 // end up casting more traces per frame per light when using bouncegrid, which
2007 // is probably fine (and they use the same timer)
2008 if (r_shadow_culllights_trace.integer)
2010 if (rtlight->trace_timer != host.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))
2011 rtlight->trace_timer = host.realtime;
2012 if (host.realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2015 // skip if expanded light box is offscreen
2016 if (R_CullFrustum(cullmins, cullmaxs))
2018 // skip if overall light intensity is zero
2019 if (w * VectorLength2(rtlight->color) == 0.0f)
2022 // a light that does not emit any light before style is applied, can be
2023 // skipped entirely (it may just be a corona)
2024 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2026 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2027 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2028 // skip lights that will emit no photons
2029 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2031 // shoot particles from this light
2032 // use a calculation for the number of particles that will not
2033 // vary with lightstyle, otherwise we get randomized particle
2034 // distribution, the seeded random is only consistent for a
2035 // consistent number of particles on this light...
2036 s = rtlight->radius;
2037 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2038 if (lightindex >= range)
2039 lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2040 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2041 photoncount += rtlight->bouncegrid_photons;
2042 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2043 // if the lightstyle happens to be off right now, we can skip actually
2044 // firing the photons, but we did have to count them in the total.
2045 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2046 // rtlight->bouncegrid_photons = 0;
2048 // the user provided an energyperphoton value which we try to use
2049 // if that results in too many photons to shoot this frame, then we cap it
2050 // which causes photons to appear/disappear from frame to frame, so we don't
2051 // like doing that in the typical case
2052 photonscaling = 1.0f;
2053 photonintensity = 1.0f;
2054 if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2056 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2057 photonintensity = 1.0f / photonscaling;
2060 // modify the lights to reflect our computed scaling
2061 for (lightindex = 0; lightindex < range2; lightindex++)
2063 if (lightindex < range)
2065 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2068 rtlight = &light->rtlight;
2071 rtlight = r_refdef.scene.lights[lightindex - range];
2072 rtlight->bouncegrid_photons *= photonscaling;
2073 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2076 // compute a seed for the unstable random modes
2077 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, host.realtime * 1000.0);
2078 seed = host.realtime * 1000.0;
2080 for (lightindex = 0; lightindex < range2; lightindex++)
2082 if (lightindex < range)
2084 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2087 rtlight = &light->rtlight;
2090 rtlight = r_refdef.scene.lights[lightindex - range];
2091 // note that this code used to keep track of residual photons and
2092 // distribute them evenly to achieve exactly a desired photon count,
2093 // but that caused unwanted flickering in dynamic mode
2094 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2095 // skip if we won't be shooting any photons
2096 if (!shootparticles)
2098 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2099 //s = settings.particleintensity / shootparticles;
2100 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2101 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2102 if (VectorLength2(baseshotcolor) <= 0.0f)
2104 r_refdef.stats[r_stat_bouncegrid_lights]++;
2105 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2106 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2107 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2109 // check material at shadoworigin to see what the initial refractive index should be
2110 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2112 // for seeded random we start the RNG with the position of the light
2113 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2121 u.f[0] = rtlight->shadoworigin[0];
2122 u.f[1] = rtlight->shadoworigin[1];
2123 u.f[2] = rtlight->shadoworigin[2];
2125 switch (r_shadow_bouncegrid_state.settings.rng_type)
2129 // we have to shift the seed provided by the user because the result must be odd
2130 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2133 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2138 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2140 r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2141 VectorCopy(baseshotcolor, p->color);
2142 VectorCopy(rtlight->shadoworigin, p->start);
2143 switch (r_shadow_bouncegrid_state.settings.rng_type)
2147 // figure out a random direction for the initial photon to go
2148 VectorLehmerRandom(&randomseed, p->end);
2151 // figure out a random direction for the initial photon to go
2152 VectorCheeseRandom(seed, p->end);
2156 // we want a uniform distribution spherically, not merely within the sphere
2157 if (r_shadow_bouncegrid_state.settings.normalizevectors)
2158 VectorNormalize(p->end);
2160 VectorMA(p->start, radius, p->end, p->end);
2161 p->bounceminimumintensity2 = bounceminimumintensity2;
2162 p->startrefractiveindex = startrefractiveindex;
2170 static void R_Shadow_BounceGrid_Slice(int zi)
2172 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2173 int xi, yi; // pixel increments
2174 float color[32] = { 0 };
2175 float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2176 float iradius = 1.0f / radius;
2177 int slicemins[3], slicemaxs[3];
2179 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2180 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2182 int samples = r_shadow_bouncegrid_state.settings.subsamples;
2183 float isamples = 1.0f / samples;
2184 float samplescolorscale = isamples * isamples * isamples;
2186 // we use these a lot, so get a local copy
2187 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2189 for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2191 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2193 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2195 r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2196 float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2198 VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2199 VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2201 pathmins[2] = min(pathstart[2], pathend[2]);
2202 slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2203 pathmaxs[2] = max(pathstart[2], pathend[2]);
2204 slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2206 // skip if the path doesn't touch this slice
2207 if (zi < slicemins[2] || zi >= slicemaxs[2])
2210 pathmins[0] = min(pathstart[0], pathend[0]);
2211 slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2212 slicemins[0] = max(slicemins[0], 1);
2213 pathmaxs[0] = max(pathstart[0], pathend[0]);
2214 slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2215 slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2217 pathmins[1] = min(pathstart[1], pathend[1]);
2218 slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2219 slicemins[1] = max(slicemins[1], 1);
2220 pathmaxs[1] = max(pathstart[1], pathend[1]);
2221 slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2222 slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2224 // skip if the path is out of bounds on X or Y
2225 if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2228 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2229 // accumulate average shotcolor
2230 VectorSubtract(pathend, pathstart, pathdelta);
2231 pathlength2 = VectorLength2(pathdelta);
2232 pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2233 VectorScale(pathdelta, pathilength, pathdir);
2234 // the color is scaled by the number of subsamples
2235 color[0] = path->color[0] * samplescolorscale;
2236 color[1] = path->color[1] * samplescolorscale;
2237 color[2] = path->color[2] * samplescolorscale;
2241 // store bentnormal in case the shader has a use for it,
2242 // bentnormal is an intensity-weighted average of the directions,
2243 // and will be normalized on conversion to texture pixels.
2244 float intensity = VectorLength(color);
2245 color[4] = pathdir[0] * intensity;
2246 color[5] = pathdir[1] * intensity;
2247 color[6] = pathdir[2] * intensity;
2248 color[7] = intensity;
2249 // for each color component (R, G, B) calculate the amount that a
2250 // direction contributes
2251 color[8] = color[0] * max(0.0f, pathdir[0]);
2252 color[9] = color[0] * max(0.0f, pathdir[1]);
2253 color[10] = color[0] * max(0.0f, pathdir[2]);
2255 color[12] = color[1] * max(0.0f, pathdir[0]);
2256 color[13] = color[1] * max(0.0f, pathdir[1]);
2257 color[14] = color[1] * max(0.0f, pathdir[2]);
2259 color[16] = color[2] * max(0.0f, pathdir[0]);
2260 color[17] = color[2] * max(0.0f, pathdir[1]);
2261 color[18] = color[2] * max(0.0f, pathdir[2]);
2263 // and do the same for negative directions
2264 color[20] = color[0] * max(0.0f, -pathdir[0]);
2265 color[21] = color[0] * max(0.0f, -pathdir[1]);
2266 color[22] = color[0] * max(0.0f, -pathdir[2]);
2268 color[24] = color[1] * max(0.0f, -pathdir[0]);
2269 color[25] = color[1] * max(0.0f, -pathdir[1]);
2270 color[26] = color[1] * max(0.0f, -pathdir[2]);
2272 color[28] = color[2] * max(0.0f, -pathdir[0]);
2273 color[29] = color[2] * max(0.0f, -pathdir[1]);
2274 color[30] = color[2] * max(0.0f, -pathdir[2]);
2278 for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2280 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2282 float sample[3], diff[3], nearest[3], along, distance2;
2283 float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2285 // loop over the subsamples
2286 for (zs = 0; zs < samples; zs++)
2288 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2289 for (ys = 0; ys < samples; ys++)
2291 sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2292 for (xs = 0; xs < samples; xs++)
2294 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2296 // measure distance from subsample to line segment and see if it is within radius
2297 along = DotProduct(sample, pathdir) * pathilength;
2299 VectorCopy(pathstart, nearest);
2300 else if (along >= 1)
2301 VectorCopy(pathend, nearest);
2303 VectorLerp(pathstart, along, pathend, nearest);
2304 VectorSubtract(sample, nearest, diff);
2305 VectorScale(diff, iradius, diff);
2306 distance2 = VectorLength2(diff);
2307 if (distance2 < 1.0f)
2309 // contribute some color to this pixel, across all bands
2310 float w = 1.0f - sqrt(distance2);
2315 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2316 p[pixelsperband * 4 + 3] += color[7] * w;
2318 for (band = 0; band < pixelbands; band++)
2320 // add to the pixel color (RGB only - see above)
2321 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2322 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2323 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2335 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2337 R_Shadow_BounceGrid_Slice((int)t->i[0]);
2341 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2344 // we need to wait for the texture clear to finish before we start adding light to it
2345 if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2350 slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2351 for (i = 0; i < slices; i++)
2352 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2353 TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2354 TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2355 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2359 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2361 const float *inpixel;
2363 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2366 unsigned int x, y, z;
2367 unsigned int resolution[3];
2368 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2369 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2371 for (z = 1;z < resolution[2]-1;z++)
2373 for (y = 1;y < resolution[1]-1;y++)
2376 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2377 inpixel = inpixels + 4*index;
2378 outpixel = outpixels + 4*index;
2379 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2381 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2382 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2383 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2384 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2391 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2394 unsigned int resolution[3];
2395 if (r_shadow_bouncegrid_state.settings.blur)
2397 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2399 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2400 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2401 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2402 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2405 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2407 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2409 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2411 // toggle the state, highpixels now points to pixels[3] result
2412 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2413 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2418 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2420 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2421 unsigned char *pixelsbgra8 = NULL;
2422 unsigned char *pixelbgra8;
2423 unsigned short *pixelsrgba16f = NULL;
2424 unsigned short *pixelrgba16f;
2425 float *pixelsrgba32f = NULL;
2426 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2429 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2430 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2431 unsigned int pixelband;
2432 unsigned int x, y, z;
2433 unsigned int index, bandindex;
2434 unsigned int resolution[3];
2436 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2438 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2440 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2441 r_shadow_bouncegrid_state.texture = NULL;
2444 // if bentnormals exist, we need to normalize and bias them for the shader
2448 for (z = 0;z < resolution[2]-1;z++)
2450 for (y = 0;y < resolution[1]-1;y++)
2453 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2454 highpixel = highpixels + 4*index;
2455 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2457 // only convert pixels that were hit by photons
2458 if (highpixel[3] != 0.0f)
2459 VectorNormalize(highpixel);
2460 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2461 highpixel[pixelsperband * 4 + 3] = 1.0f;
2467 // start by clearing the pixels array - we won't be writing to all of it
2469 // then process only the pixels that have at least some color, skipping
2470 // the higher bands for speed on pixels that are black
2471 switch (floatcolors)
2474 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2475 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2476 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2477 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2480 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2482 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2484 for (z = 1;z < resolution[2]-1;z++)
2486 for (y = 1;y < resolution[1]-1;y++)
2490 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2491 highpixel = highpixels + 4*index;
2492 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2494 // only convert pixels that were hit by photons
2495 if (VectorLength2(highpixel))
2497 // normalize the bentnormal now
2500 VectorNormalize(highpixel + pixelsperband * 4);
2501 highpixel[pixelsperband * 4 + 3] = 1.0f;
2503 // process all of the pixelbands for this pixel
2504 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2506 pixelbgra8 = pixelsbgra8 + 4*bandindex;
2507 bandpixel = highpixels + 4*bandindex;
2508 c[0] = (int)(bandpixel[0]*256.0f);
2509 c[1] = (int)(bandpixel[1]*256.0f);
2510 c[2] = (int)(bandpixel[2]*256.0f);
2511 c[3] = (int)(bandpixel[3]*256.0f);
2512 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2513 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2514 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2515 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2522 if (!r_shadow_bouncegrid_state.createtexture)
2523 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands, 0);
2525 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);
2528 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2529 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2530 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2531 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2532 for (z = 1;z < resolution[2]-1;z++)
2534 for (y = 1;y < resolution[1]-1;y++)
2538 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2539 highpixel = highpixels + 4*index;
2540 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2542 // only convert pixels that were hit by photons
2543 if (VectorLength2(highpixel))
2545 // process all of the pixelbands for this pixel
2546 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2548 // time to have fun with IEEE 754 bit hacking...
2551 unsigned int raw[4];
2553 pixelrgba16f = pixelsrgba16f + 4*bandindex;
2554 bandpixel = highpixels + 4*bandindex;
2555 VectorCopy4(bandpixel, u.f);
2556 VectorCopy4(u.raw, c);
2557 // this math supports negative numbers, snaps denormals to zero
2558 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2559 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2560 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2561 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2562 // this math does not support negative
2563 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2564 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2565 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2566 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2573 if (!r_shadow_bouncegrid_state.createtexture)
2574 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands, 0);
2576 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);
2579 // our native format happens to match, so this is easy.
2580 pixelsrgba32f = highpixels;
2582 if (!r_shadow_bouncegrid_state.createtexture)
2583 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands, 0);
2585 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);
2589 r_shadow_bouncegrid_state.lastupdatetime = host.realtime;
2592 static void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2594 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2598 static void R_Shadow_BounceGrid_TracePhotons_Shot(r_shadow_bouncegrid_photon_t *p, int remainingbounces, vec3_t shotstart, vec3_t shotend, vec3_t shotcolor, float bounceminimumintensity2, float previousrefractiveindex)
2600 int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2602 vec3_t surfacenormal;
2603 vec3_t reflectstart, reflectend, reflectcolor;
2604 vec3_t refractstart, refractend, refractcolor;
2606 float reflectamount = 1.0f;
2608 // figure out what we want to interact with
2609 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2610 skipsupercontentsmask = 0;
2611 skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2612 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2613 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2614 if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2616 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2617 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2618 cliptrace = CL_TraceLine(shotstart, shotend, r_shadow_bouncegrid_state.settings.staticmode ? MOVE_WORLDONLY : (r_shadow_bouncegrid_state.settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value, true, false, NULL, true, true);
2622 // dynamic mode fires many rays and most will match the cache from the previous frame
2623 cliptrace = CL_Cache_TraceLineSurfaces(shotstart, shotend, r_shadow_bouncegrid_state.settings.staticmode ? MOVE_WORLDONLY : (r_shadow_bouncegrid_state.settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
2625 VectorCopy(cliptrace.endpos, shothit);
2626 if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2628 qbool notculled = true;
2629 // cull paths that fail R_CullFrustum in dynamic mode
2630 if (!r_shadow_bouncegrid_state.settings.staticmode
2631 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2633 vec3_t cullmins, cullmaxs;
2634 cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2635 cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2636 cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2637 cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2638 cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2639 cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2640 if (R_CullFrustum(cullmins, cullmaxs))
2645 r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2646 VectorCopy(shotstart, path->start);
2647 VectorCopy(shothit, path->end);
2648 VectorCopy(shotcolor, path->color);
2651 if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2653 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2654 // also clamp the resulting color to never add energy, even if the user requests extreme values
2655 VectorCopy(cliptrace.plane.normal, surfacenormal);
2656 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2657 VectorClear(refractcolor);
2658 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2659 if (cliptrace.hittexture)
2661 if (cliptrace.hittexture->currentskinframe)
2662 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2663 if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2665 reflectamount *= cliptrace.hittexture->currentalpha;
2666 if (cliptrace.hittexture->currentskinframe)
2667 reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2669 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2673 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2674 VectorSubtract(shotstart, shotend, lightdir);
2675 VectorNormalize(lightdir);
2676 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2677 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2678 reflectamount *= Fresnel;
2679 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2681 if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2682 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2683 // make sure we do not gain energy even if surface colors are out of bounds
2684 reflectcolor[0] = min(reflectcolor[0], 1.0f);
2685 reflectcolor[1] = min(reflectcolor[1], 1.0f);
2686 reflectcolor[2] = min(reflectcolor[2], 1.0f);
2687 refractcolor[0] = min(refractcolor[0], 1.0f);
2688 refractcolor[1] = min(refractcolor[1], 1.0f);
2689 refractcolor[2] = min(refractcolor[2], 1.0f);
2691 // reflected and refracted shots
2692 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2693 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2694 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2695 VectorMultiply(refractcolor, shotcolor, refractcolor);
2697 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2699 // reflect the remaining portion of the line across plane normal
2700 VectorSubtract(shotend, shothit, reflectend);
2701 VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2702 // calculate the new line start and end
2703 VectorCopy(shothit, reflectstart);
2704 VectorAdd(reflectstart, reflectend, reflectend);
2705 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2708 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2710 // Check what refractive index is on the other side
2711 float refractiveindex;
2712 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2713 refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2714 // reflect the remaining portion of the line across plane normal
2715 VectorSubtract(shotend, shothit, refractend);
2716 s = refractiveindex / previousrefractiveindex;
2717 VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2718 // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2719 // calculate the new line start and end
2720 VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2721 VectorAdd(refractstart, refractend, refractend);
2722 R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2727 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2729 r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2730 R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2734 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2737 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2738 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2739 TaskQueue_Setup(&r_shadow_bouncegrid_state.photons_done_task, NULL, TaskQueue_Task_CheckTasksDone, r_shadow_bouncegrid_state.numphotons, 0, r_shadow_bouncegrid_state.photons_tasks, NULL);
2740 if (r_shadow_bouncegrid_threaded.integer)
2742 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2743 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2747 // when not threaded we still have to report task status
2748 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2749 r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2750 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2755 void R_Shadow_UpdateBounceGridTexture(void)
2757 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2758 r_shadow_bouncegrid_settings_t settings;
2759 qbool enable = false;
2760 qbool settingschanged;
2762 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2764 R_Shadow_BounceGrid_GenerateSettings(&settings);
2766 // changing intensity does not require an update
2767 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2769 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2771 // when settings change, we free everything as it is just simpler that way.
2772 if (settingschanged || !enable)
2774 // not enabled, make sure we free anything we don't need anymore.
2775 if (r_shadow_bouncegrid_state.texture)
2777 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2778 r_shadow_bouncegrid_state.texture = NULL;
2780 R_Shadow_BounceGrid_FreeHighPixels();
2781 r_shadow_bouncegrid_state.numpixels = 0;
2782 r_shadow_bouncegrid_state.numphotons = 0;
2783 r_shadow_bouncegrid_state.directional = false;
2789 // if all the settings seem identical to the previous update, return
2790 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || host.realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2793 // store the new settings
2794 r_shadow_bouncegrid_state.settings = settings;
2796 R_Shadow_BounceGrid_UpdateSpacing();
2798 // allocate the highpixels array we'll be accumulating light into
2799 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2800 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2801 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2802 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2803 r_shadow_bouncegrid_state.highpixels_index = 0;
2804 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2806 // set up the tracking of photon data
2807 if (r_shadow_bouncegrid_state.photons == NULL)
2808 r_shadow_bouncegrid_state.photons = (r_shadow_bouncegrid_photon_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(r_shadow_bouncegrid_photon_t));
2809 if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2810 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2811 r_shadow_bouncegrid_state.numphotons = 0;
2813 // set up the tracking of slice tasks
2814 if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2815 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2817 memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2818 memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2819 memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2820 memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2821 memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2822 memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2823 memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2824 memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2825 memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2827 // clear the texture
2828 TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2829 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2831 // calculate weighting factors for distributing photons among the lights
2832 TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2833 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2835 // enqueue tasks to trace the photons from lights
2836 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2837 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2839 // accumulate the light paths into texture
2840 TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueue_slices_task, &r_shadow_bouncegrid_state.photons_done_task, R_Shadow_BounceGrid_EnqueueSlices_Task, 0, 0, NULL, NULL);
2841 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2843 // apply a mild blur filter to the texture
2844 TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2845 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2847 TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2848 R_TimeReport("bouncegrid_gen");
2850 // convert the pixels to lower precision and upload the texture
2851 // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2852 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2853 R_TimeReport("bouncegrid_tex");
2855 // after we compute the static lighting we don't need to keep the highpixels array around
2856 if (settings.staticmode)
2857 R_Shadow_BounceGrid_FreeHighPixels();
2860 void R_Shadow_RenderMode_VisibleLighting(qbool transparent)
2862 R_Shadow_RenderMode_Reset();
2863 GL_BlendFunc(GL_ONE, GL_ONE);
2864 GL_DepthRange(0, 1);
2865 GL_DepthTest(r_showlighting.integer < 2);
2866 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2868 GL_DepthFunc(GL_EQUAL);
2869 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2872 void R_Shadow_RenderMode_End(void)
2874 R_Shadow_RenderMode_Reset();
2875 R_Shadow_RenderMode_ActiveLight(NULL);
2877 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2878 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2881 int bboxedges[12][2] =
2900 qbool R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2902 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2904 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2905 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2906 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2907 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2910 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2911 return true; // invisible
2912 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2913 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2914 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2915 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2916 r_refdef.stats[r_stat_lights_scissored]++;
2920 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2922 // used to display how many times a surface is lit for level design purposes
2923 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2924 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2928 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])
2930 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2931 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false, false);
2935 extern cvar_t gl_lightmaps;
2936 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2939 float ambientcolor[3], diffusecolor[3], specularcolor[3];
2940 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2941 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2942 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2943 if (!r_shadow_usenormalmap.integer)
2945 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2946 VectorClear(diffusecolor);
2947 VectorClear(specularcolor);
2949 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2950 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2951 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2952 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2954 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2957 VectorNegate(ambientcolor, ambientcolor);
2958 VectorNegate(diffusecolor, diffusecolor);
2959 VectorNegate(specularcolor, specularcolor);
2960 GL_BlendEquationSubtract(true);
2962 RSurf_SetupDepthAndCulling(false);
2963 switch (r_shadow_rendermode)
2965 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2966 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2967 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2969 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2970 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2973 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2977 GL_BlendEquationSubtract(false);
2980 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)
2982 matrix4x4_t tempmatrix = *matrix;
2983 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2985 // if this light has been compiled before, free the associated data
2986 R_RTLight_Uncompile(rtlight);
2988 // clear it completely to avoid any lingering data
2989 memset(rtlight, 0, sizeof(*rtlight));
2991 // copy the properties
2992 rtlight->matrix_lighttoworld = tempmatrix;
2993 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2994 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2995 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2996 VectorCopy(color, rtlight->color);
2997 rtlight->cubemapname[0] = 0;
2998 if (cubemapname && cubemapname[0])
2999 dp_strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3000 rtlight->shadow = shadow;
3001 rtlight->corona = corona;
3002 rtlight->style = style;
3003 rtlight->isstatic = isstatic;
3004 rtlight->coronasizescale = coronasizescale;
3005 rtlight->ambientscale = ambientscale;
3006 rtlight->diffusescale = diffusescale;
3007 rtlight->specularscale = specularscale;
3008 rtlight->flags = flags;
3010 // compute derived data
3011 //rtlight->cullradius = rtlight->radius;
3012 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3013 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3014 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3015 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3016 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3017 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3018 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3021 // compiles rtlight geometry
3022 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3023 void R_RTLight_Compile(rtlight_t *rtlight)
3026 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3027 int lighttris, shadowtris;
3028 entity_render_t *ent = r_refdef.scene.worldentity;
3029 model_t *model = r_refdef.scene.worldmodel;
3030 unsigned char *data;
3032 // compile the light
3033 rtlight->compiled = true;
3034 rtlight->static_numleafs = 0;
3035 rtlight->static_numleafpvsbytes = 0;
3036 rtlight->static_leaflist = NULL;
3037 rtlight->static_leafpvs = NULL;
3038 rtlight->static_numsurfaces = 0;
3039 rtlight->static_surfacelist = NULL;
3040 rtlight->static_shadowmap_receivers = 0x3F;
3041 rtlight->static_shadowmap_casters = 0x3F;
3042 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3043 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3044 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3045 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3046 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3047 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3049 if (model && model->GetLightInfo)
3051 // this variable must be set for the CompileShadowMap code
3052 r_shadow_compilingrtlight = rtlight;
3053 R_FrameData_SetMark();
3054 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);
3055 R_FrameData_ReturnToMark();
3056 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3057 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3058 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3059 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3060 rtlight->static_numsurfaces = numsurfaces;
3061 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3062 rtlight->static_numleafs = numleafs;
3063 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3064 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3065 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3066 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3067 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3068 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3069 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3070 if (rtlight->static_numsurfaces)
3071 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3072 if (rtlight->static_numleafs)
3073 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3074 if (rtlight->static_numleafpvsbytes)
3075 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3076 if (rtlight->static_numshadowtrispvsbytes)
3077 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3078 if (rtlight->static_numlighttrispvsbytes)
3079 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3080 R_FrameData_SetMark();
3081 if (model->CompileShadowMap && rtlight->shadow)
3082 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3083 R_FrameData_ReturnToMark();
3084 // now we're done compiling the rtlight
3085 r_shadow_compilingrtlight = NULL;
3089 // use smallest available cullradius - box radius or light radius
3090 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3091 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3094 if (rtlight->static_numlighttrispvsbytes)
3095 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3096 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3100 if (rtlight->static_numshadowtrispvsbytes)
3101 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3102 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3105 if (developer_extra.integer)
3106 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);
3109 void R_RTLight_Uncompile(rtlight_t *rtlight)
3111 if (rtlight->compiled)
3113 if (rtlight->static_meshchain_shadow_shadowmap)
3114 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3115 rtlight->static_meshchain_shadow_shadowmap = NULL;
3116 // these allocations are grouped
3117 if (rtlight->static_surfacelist)
3118 Mem_Free(rtlight->static_surfacelist);
3119 rtlight->static_numleafs = 0;
3120 rtlight->static_numleafpvsbytes = 0;
3121 rtlight->static_leaflist = NULL;
3122 rtlight->static_leafpvs = NULL;
3123 rtlight->static_numsurfaces = 0;
3124 rtlight->static_surfacelist = NULL;
3125 rtlight->static_numshadowtrispvsbytes = 0;
3126 rtlight->static_shadowtrispvs = NULL;
3127 rtlight->static_numlighttrispvsbytes = 0;
3128 rtlight->static_lighttrispvs = NULL;
3129 rtlight->compiled = false;
3133 void R_Shadow_UncompileWorldLights(void)
3137 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3138 for (lightindex = 0;lightindex < range;lightindex++)
3140 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3143 R_RTLight_Uncompile(&light->rtlight);
3147 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3151 // reset the count of frustum planes
3152 // see rtlight->cached_frustumplanes definition for how much this array
3154 rtlight->cached_numfrustumplanes = 0;
3156 if (r_trippy.integer)
3159 // haven't implemented a culling path for ortho rendering
3160 if (!r_refdef.view.useperspective)
3162 // check if the light is on screen and copy the 4 planes if it is
3163 for (i = 0;i < 4;i++)
3164 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3167 for (i = 0;i < 4;i++)
3168 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3173 // generate a deformed frustum that includes the light origin, this is
3174 // used to cull shadow casting surfaces that can not possibly cast a
3175 // shadow onto the visible light-receiving surfaces, which can be a
3178 // if the light origin is onscreen the result will be 4 planes exactly
3179 // if the light origin is offscreen on only one axis the result will
3180 // be exactly 5 planes (split-side case)
3181 // if the light origin is offscreen on two axes the result will be
3182 // exactly 4 planes (stretched corner case)
3183 for (i = 0;i < 4;i++)
3185 // quickly reject standard frustum planes that put the light
3186 // origin outside the frustum
3187 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3190 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3192 // if all the standard frustum planes were accepted, the light is onscreen
3193 // otherwise we need to generate some more planes below...
3194 if (rtlight->cached_numfrustumplanes < 4)
3196 // at least one of the stock frustum planes failed, so we need to
3197 // create one or two custom planes to enclose the light origin
3198 for (i = 0;i < 4;i++)
3200 // create a plane using the view origin and light origin, and a
3201 // single point from the frustum corner set
3202 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3203 VectorNormalize(plane.normal);
3204 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3205 // see if this plane is backwards and flip it if so
3206 for (j = 0;j < 4;j++)
3207 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3211 VectorNegate(plane.normal, plane.normal);
3213 // flipped plane, test again to see if it is now valid
3214 for (j = 0;j < 4;j++)
3215 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3217 // if the plane is still not valid, then it is dividing the
3218 // frustum and has to be rejected
3222 // we have created a valid plane, compute extra info
3223 PlaneClassify(&plane);
3225 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3227 // if we've found 5 frustum planes then we have constructed a
3228 // proper split-side case and do not need to keep searching for
3229 // planes to enclose the light origin
3230 if (rtlight->cached_numfrustumplanes == 5)
3238 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3240 plane = rtlight->cached_frustumplanes[i];
3241 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));
3246 // now add the light-space box planes if the light box is rotated, as any
3247 // caster outside the oriented light box is irrelevant (even if it passed
3248 // the worldspace light box, which is axial)
3249 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3251 for (i = 0;i < 6;i++)
3255 v[i >> 1] = (i & 1) ? -1 : 1;
3256 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3257 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3258 plane.dist = VectorNormalizeLength(plane.normal);
3259 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3260 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3266 // add the world-space reduced box planes
3267 for (i = 0;i < 6;i++)
3269 VectorClear(plane.normal);
3270 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3271 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3272 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3281 // reduce all plane distances to tightly fit the rtlight cull box, which
3283 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3284 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3285 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3286 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3287 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3288 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3289 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3290 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3291 oldnum = rtlight->cached_numfrustumplanes;
3292 rtlight->cached_numfrustumplanes = 0;
3293 for (j = 0;j < oldnum;j++)
3295 // find the nearest point on the box to this plane
3296 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3297 for (i = 1;i < 8;i++)
3299 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3300 if (bestdist > dist)
3303 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);
3304 // if the nearest point is near or behind the plane, we want this
3305 // plane, otherwise the plane is useless as it won't cull anything
3306 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3308 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3309 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3316 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3318 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3320 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3322 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3323 if (mesh->sidetotals[r_shadow_shadowmapside])
3326 GL_CullFace(GL_NONE);
3327 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3328 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3329 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);
3333 else if (r_refdef.scene.worldentity->model)
3334 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);
3336 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3339 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3341 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3342 vec_t relativeshadowradius;
3343 RSurf_ActiveModelEntity(ent, false, false, false);
3344 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3345 // we need to re-init the shader for each entity because the matrix changed
3346 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3347 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3348 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3349 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3350 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3351 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3352 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3353 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->submodelsurfaces_end - ent->model->submodelsurfaces_start, ent->model->modelsurfaces_sorted + ent->model->submodelsurfaces_start, NULL, relativeshadowmins, relativeshadowmaxs);
3354 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3357 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3359 // set up properties for rendering light onto this entity
3360 RSurf_ActiveModelEntity(ent, true, true, false);
3361 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3362 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3363 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3364 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3367 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3369 if (!r_refdef.scene.worldmodel->DrawLight)
3372 // set up properties for rendering light onto this entity
3373 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3374 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3375 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3376 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3377 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3379 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3381 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3384 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3386 model_t *model = ent->model;
3387 if (!model->DrawLight)
3390 R_Shadow_SetupEntityLight(ent);
3392 model->DrawLight(ent, model->submodelsurfaces_end - model->submodelsurfaces_start, model->modelsurfaces_sorted + model->submodelsurfaces_start, NULL);
3394 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3397 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3401 int numleafs, numsurfaces;
3402 int *leaflist, *surfacelist;
3403 unsigned char *leafpvs;
3404 unsigned char *shadowtrispvs;
3405 unsigned char *lighttrispvs;
3406 //unsigned char *surfacesides;
3407 int numlightentities;
3408 int numlightentities_noselfshadow;
3409 int numshadowentities;
3410 int numshadowentities_noselfshadow;
3411 // FIXME: bounds check lightentities and shadowentities, etc.
3412 static entity_render_t *lightentities[MAX_EDICTS];
3413 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3414 static entity_render_t *shadowentities[MAX_EDICTS];
3415 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3419 rtlight->draw = false;
3420 rtlight->cached_numlightentities = 0;
3421 rtlight->cached_numlightentities_noselfshadow = 0;
3422 rtlight->cached_numshadowentities = 0;
3423 rtlight->cached_numshadowentities_noselfshadow = 0;
3424 rtlight->cached_numsurfaces = 0;
3425 rtlight->cached_lightentities = NULL;
3426 rtlight->cached_lightentities_noselfshadow = NULL;
3427 rtlight->cached_shadowentities = NULL;
3428 rtlight->cached_shadowentities_noselfshadow = NULL;
3429 rtlight->cached_shadowtrispvs = NULL;
3430 rtlight->cached_lighttrispvs = NULL;
3431 rtlight->cached_surfacelist = NULL;
3432 rtlight->shadowmapsidesize = 0;
3434 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3435 // skip lights that are basically invisible (color 0 0 0)
3436 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3438 // loading is done before visibility checks because loading should happen
3439 // all at once at the start of a level, not when it stalls gameplay.
3440 // (especially important to benchmarks)
3442 if (rtlight->isstatic && !nolight && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3443 R_RTLight_Compile(rtlight);
3446 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3448 // look up the light style value at this time
3449 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3450 VectorScale(rtlight->color, f, rtlight->currentcolor);
3452 if (rtlight->selected)
3454 f = 2 + sin(host.realtime * M_PI * 4.0);
3455 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3459 // skip if lightstyle is currently off
3460 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3463 // skip processing on corona-only lights
3467 // skip if the light box is not touching any visible leafs
3468 if (r_shadow_culllights_pvs.integer
3469 && r_refdef.scene.worldmodel
3470 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3471 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3474 // skip if the light box is not visible to traceline
3475 if (r_shadow_culllights_trace.integer)
3477 if (rtlight->trace_timer != host.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))
3478 rtlight->trace_timer = host.realtime;
3479 if (host.realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3483 // skip if the light box is off screen
3484 if (R_CullFrustum(rtlight->cullmins, rtlight->cullmaxs))
3487 // in the typical case this will be quickly replaced by GetLightInfo
3488 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3489 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3491 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3493 // 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
3494 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3497 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3499 // compiled light, world available and can receive realtime lighting
3500 // retrieve leaf information
3501 numleafs = rtlight->static_numleafs;
3502 leaflist = rtlight->static_leaflist;
3503 leafpvs = rtlight->static_leafpvs;
3504 numsurfaces = rtlight->static_numsurfaces;
3505 surfacelist = rtlight->static_surfacelist;
3506 //surfacesides = NULL;
3507 shadowtrispvs = rtlight->static_shadowtrispvs;
3508 lighttrispvs = rtlight->static_lighttrispvs;
3510 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3512 // dynamic light, world available and can receive realtime lighting
3513 // calculate lit surfaces and leafs
3514 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);
3515 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3516 leaflist = r_shadow_buffer_leaflist;
3517 leafpvs = r_shadow_buffer_leafpvs;
3518 surfacelist = r_shadow_buffer_surfacelist;
3519 //surfacesides = r_shadow_buffer_surfacesides;
3520 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3521 lighttrispvs = r_shadow_buffer_lighttrispvs;
3522 // if the reduced leaf bounds are offscreen, skip it
3523 if (R_CullFrustum(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3534 //surfacesides = NULL;
3535 shadowtrispvs = NULL;
3536 lighttrispvs = NULL;
3538 // check if light is illuminating any visible leafs
3541 for (i = 0; i < numleafs; i++)
3542 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3548 // make a list of lit entities and shadow casting entities
3549 numlightentities = 0;
3550 numlightentities_noselfshadow = 0;
3551 numshadowentities = 0;
3552 numshadowentities_noselfshadow = 0;
3554 // add dynamic entities that are lit by the light
3555 for (i = 0; i < r_refdef.scene.numentities; i++)
3558 entity_render_t *ent = r_refdef.scene.entities[i];
3560 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3562 // skip the object entirely if it is not within the valid
3563 // shadow-casting region (which includes the lit region)
3564 if (R_CullBox(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3566 if (!(model = ent->model))
3568 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3570 // this entity wants to receive light, is visible, and is
3571 // inside the light box
3572 // TODO: check if the surfaces in the model can receive light
3573 // so now check if it's in a leaf seen by the light
3574 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))
3576 if (ent->flags & RENDER_NOSELFSHADOW)
3577 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3579 lightentities[numlightentities++] = ent;
3580 // since it is lit, it probably also casts a shadow...
3581 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3582 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3583 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3585 // note: exterior models without the RENDER_NOSELFSHADOW
3586 // flag still create a RENDER_NOSELFSHADOW shadow but
3587 // are lit normally, this means that they are
3588 // self-shadowing but do not shadow other
3589 // RENDER_NOSELFSHADOW entities such as the gun
3590 // (very weird, but keeps the player shadow off the gun)
3591 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3592 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3594 shadowentities[numshadowentities++] = ent;
3597 else if (ent->flags & RENDER_SHADOW)
3599 // this entity is not receiving light, but may still need to
3601 // TODO: check if the surfaces in the model can cast shadow
3602 // now check if it is in a leaf seen by the light
3603 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))
3605 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3606 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3607 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3609 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3610 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3612 shadowentities[numshadowentities++] = ent;
3617 // return if there's nothing at all to light
3618 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3621 // count this light in the r_speeds
3622 r_refdef.stats[r_stat_lights]++;
3624 // flag it as worth drawing later
3625 rtlight->draw = true;
3627 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3628 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3630 numshadowentities = numshadowentities_noselfshadow = 0;
3631 rtlight->castshadows = castshadows;
3633 // cache all the animated entities that cast a shadow but are not visible
3634 for (i = 0; i < numshadowentities; i++)
3635 R_AnimCache_GetEntity(shadowentities[i], false, false);
3636 for (i = 0; i < numshadowentities_noselfshadow; i++)
3637 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3639 // 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)
3640 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3642 for (i = 0; i < numshadowentities_noselfshadow; i++)
3643 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3644 numshadowentities_noselfshadow = 0;
3647 // we can convert noselfshadow to regular if there are no casters of that type
3648 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3650 for (i = 0; i < numlightentities_noselfshadow; i++)
3651 lightentities[numlightentities++] = lightentities_noselfshadow[i];
3652 numlightentities_noselfshadow = 0;
3655 // allocate some temporary memory for rendering this light later in the frame
3656 // reusable buffers need to be copied, static data can be used as-is
3657 rtlight->cached_numlightentities = numlightentities;
3658 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3659 rtlight->cached_numshadowentities = numshadowentities;
3660 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3661 rtlight->cached_numsurfaces = numsurfaces;
3662 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3663 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3664 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3665 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3666 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3668 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3669 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3670 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3671 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3672 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3676 // compiled light data
3677 rtlight->cached_shadowtrispvs = shadowtrispvs;
3678 rtlight->cached_lighttrispvs = lighttrispvs;
3679 rtlight->cached_surfacelist = surfacelist;
3682 if (R_Shadow_ShadowMappingEnabled())
3684 // figure out the shadowmapping parameters for this light
3685 vec3_t nearestpoint;
3688 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3689 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3690 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3691 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3692 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3693 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3694 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3695 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3696 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3700 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3704 unsigned char *shadowtrispvs, *surfacesides;
3705 int numlightentities;
3706 int numlightentities_noselfshadow;
3707 int numshadowentities;
3708 int numshadowentities_noselfshadow;
3709 entity_render_t **lightentities;
3710 entity_render_t **lightentities_noselfshadow;
3711 entity_render_t **shadowentities;
3712 entity_render_t **shadowentities_noselfshadow;
3714 static unsigned char entitysides[MAX_EDICTS];
3715 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3721 matrix4x4_t radiustolight;
3723 // check if we cached this light this frame (meaning it is worth drawing)
3724 if (!rtlight->draw || !rtlight->castshadows)
3727 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3728 if (rtlight->shadowmapatlassidesize == 0)
3730 rtlight->castshadows = false;
3734 // set up a scissor rectangle for this light
3735 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3738 // don't let sound skip if going slow
3739 if (r_refdef.scene.extraupdate)
3742 numlightentities = rtlight->cached_numlightentities;
3743 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3744 numshadowentities = rtlight->cached_numshadowentities;
3745 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3746 numsurfaces = rtlight->cached_numsurfaces;
3747 lightentities = rtlight->cached_lightentities;
3748 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3749 shadowentities = rtlight->cached_shadowentities;
3750 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3751 shadowtrispvs = rtlight->cached_shadowtrispvs;
3752 surfacelist = rtlight->cached_surfacelist;
3754 // make this the active rtlight for rendering purposes
3755 R_Shadow_RenderMode_ActiveLight(rtlight);
3757 radiustolight = rtlight->matrix_worldtolight;
3758 Matrix4x4_Abs(&radiustolight);
3760 size = rtlight->shadowmapatlassidesize;
3761 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3763 surfacesides = NULL;
3768 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3770 castermask = rtlight->static_shadowmap_casters;
3771 receivermask = rtlight->static_shadowmap_receivers;
3775 surfacesides = r_shadow_buffer_surfacesides;
3776 for (i = 0; i < numsurfaces; i++)
3778 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3779 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3780 castermask |= surfacesides[i];
3781 receivermask |= surfacesides[i];
3786 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3787 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3788 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3789 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3791 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3795 for (i = 0; i < numshadowentities; i++)
3796 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3797 for (i = 0; i < numshadowentities_noselfshadow; i++)
3798 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3801 // there is no need to render shadows for sides that have no receivers...
3802 castermask &= receivermask;
3804 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3806 // render shadow casters into shadowmaps for this light
3807 for (side = 0; side < 6; side++)
3809 int bit = 1 << side;
3810 if (castermask & bit)
3812 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3814 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3815 for (i = 0; i < numshadowentities; i++)
3816 if (entitysides[i] & bit)
3817 R_Shadow_DrawEntityShadow(shadowentities[i]);
3818 for (i = 0; i < numshadowentities_noselfshadow; i++)
3819 if (entitysides_noselfshadow[i] & bit)
3820 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3823 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3824 if (numshadowentities_noselfshadow)
3826 for (side = 0; side < 6; side++)
3828 int bit = 1 << side;
3829 if (castermask & bit)
3831 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3833 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3834 for (i = 0; i < numshadowentities; i++)
3835 if (entitysides[i] & bit)
3836 R_Shadow_DrawEntityShadow(shadowentities[i]);
3842 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3846 unsigned char *lighttrispvs;
3847 int numlightentities;
3848 int numlightentities_noselfshadow;
3849 entity_render_t **lightentities;
3850 entity_render_t **lightentities_noselfshadow;
3854 // check if we cached this light this frame (meaning it is worth drawing)
3858 // set up a scissor rectangle for this light
3859 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3862 // don't let sound skip if going slow
3863 if (r_refdef.scene.extraupdate)
3866 numlightentities = rtlight->cached_numlightentities;
3867 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3868 numsurfaces = rtlight->cached_numsurfaces;
3869 lightentities = rtlight->cached_lightentities;
3870 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3871 lighttrispvs = rtlight->cached_lighttrispvs;
3872 surfacelist = rtlight->cached_surfacelist;
3873 castshadows = rtlight->castshadows;
3875 // make this the active rtlight for rendering purposes
3876 R_Shadow_RenderMode_ActiveLight(rtlight);
3878 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3880 // optionally draw the illuminated areas
3881 // for performance analysis by level designers
3882 R_Shadow_RenderMode_VisibleLighting(false);
3884 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3885 for (i = 0;i < numlightentities;i++)
3886 R_Shadow_DrawEntityLight(lightentities[i]);
3887 for (i = 0;i < numlightentities_noselfshadow;i++)
3888 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3891 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3893 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3894 Matrix4x4_Abs(&radiustolight);
3896 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3898 // render lighting using the depth texture as shadowmap
3899 // draw lighting in the unmasked areas
3900 if (numsurfaces + numlightentities)
3902 R_Shadow_RenderMode_Lighting(false, true, false);
3903 // draw lighting in the unmasked areas
3905 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3906 for (i = 0; i < numlightentities; i++)
3907 R_Shadow_DrawEntityLight(lightentities[i]);
3909 // offset to the noselfshadow part of the atlas and draw those too
3910 if (numlightentities_noselfshadow)
3912 R_Shadow_RenderMode_Lighting(false, true, true);
3913 for (i = 0; i < numlightentities_noselfshadow; i++)
3914 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3917 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3918 if (r_shadow_usingdeferredprepass)
3919 R_Shadow_RenderMode_DrawDeferredLight(true);
3923 // draw lighting in the unmasked areas
3924 R_Shadow_RenderMode_Lighting(false, false, false);
3926 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3927 for (i = 0;i < numlightentities;i++)
3928 R_Shadow_DrawEntityLight(lightentities[i]);
3929 for (i = 0;i < numlightentities_noselfshadow;i++)
3930 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3932 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3933 if (r_shadow_usingdeferredprepass)
3934 R_Shadow_RenderMode_DrawDeferredLight(false);
3938 static void R_Shadow_FreeDeferred(void)
3940 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3941 r_shadow_prepassgeometryfbo = 0;
3943 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3944 r_shadow_prepasslightingdiffusespecularfbo = 0;
3946 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3947 r_shadow_prepasslightingdiffusefbo = 0;
3949 if (r_shadow_prepassgeometrydepthbuffer)
3950 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3951 r_shadow_prepassgeometrydepthbuffer = NULL;
3953 if (r_shadow_prepassgeometrynormalmaptexture)
3954 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3955 r_shadow_prepassgeometrynormalmaptexture = NULL;
3957 if (r_shadow_prepasslightingdiffusetexture)
3958 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3959 r_shadow_prepasslightingdiffusetexture = NULL;
3961 if (r_shadow_prepasslightingspeculartexture)
3962 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3963 r_shadow_prepasslightingspeculartexture = NULL;
3966 void R_Shadow_DrawPrepass(void)
3970 entity_render_t *ent;
3971 float clearcolor[4];
3973 R_Mesh_ResetTextureState();
3975 GL_ColorMask(1,1,1,1);
3976 GL_BlendFunc(GL_ONE, GL_ZERO);
3979 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3980 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3981 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3982 if (r_timereport_active)
3983 R_TimeReport("prepasscleargeom");
3985 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3986 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3987 if (r_timereport_active)
3988 R_TimeReport("prepassworld");
3990 for (i = 0;i < r_refdef.scene.numentities;i++)
3992 if (!r_refdef.viewcache.entityvisible[i])
3994 ent = r_refdef.scene.entities[i];
3995 if (ent->model && ent->model->DrawPrepass != NULL)
3996 ent->model->DrawPrepass(ent);
3999 if (r_timereport_active)
4000 R_TimeReport("prepassmodels");
4002 GL_DepthMask(false);
4003 GL_ColorMask(1,1,1,1);
4006 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4007 Vector4Set(clearcolor, 0, 0, 0, 0);
4008 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4009 if (r_timereport_active)
4010 R_TimeReport("prepassclearlit");
4012 R_Shadow_RenderMode_Begin();
4014 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4015 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4017 R_Shadow_RenderMode_End();
4019 if (r_timereport_active)
4020 R_TimeReport("prepasslights");
4023 #define MAX_SCENELIGHTS 65536
4024 static qbool R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4026 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4028 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4030 r_shadow_scenemaxlights *= 2;
4031 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4032 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4034 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4038 void R_Shadow_DrawLightSprites(void);
4039 void R_Shadow_PrepareLights(void)
4048 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4049 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4050 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4052 if (r_shadow_shadowmode_shadowmapping != r_shadow_shadowmapping.integer ||
4053 r_shadow_shadowmode_deferred != r_shadow_deferred.integer ||
4054 r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4055 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4056 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4057 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4058 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4059 r_shadow_shadowmapborder != shadowmapborder ||
4060 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4061 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4062 R_Shadow_FreeShadowMaps();
4064 r_shadow_usingshadowmaportho = false;
4066 switch (vid.renderpath)
4068 case RENDERPATH_GL32:
4070 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4072 r_shadow_usingdeferredprepass = false;
4073 if (r_shadow_prepass_width)
4074 R_Shadow_FreeDeferred();
4075 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4079 if (r_shadow_prepass_width != r_fb.screentexturewidth || r_shadow_prepass_height != r_fb.screentextureheight)
4081 R_Shadow_FreeDeferred();
4083 r_shadow_usingdeferredprepass = true;
4084 r_shadow_prepass_width = r_fb.screentexturewidth;
4085 r_shadow_prepass_height = r_fb.screentextureheight;
4086 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", r_fb.screentexturewidth, r_fb.screentextureheight, TEXTYPE_DEPTHBUFFER24);
4087 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4088 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4089 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4091 // set up the geometry pass fbo (depth + normalmap)
4092 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4093 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4094 // render depth into a renderbuffer and other important properties into the normalmap texture
4096 // set up the lighting pass fbo (diffuse + specular)
4097 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4098 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4099 // render diffuse into one texture and specular into another,
4100 // with depth and normalmap bound as textures,
4101 // with depth bound as attachment as well
4103 // set up the lighting pass fbo (diffuse)
4104 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4105 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4106 // render diffuse into one texture,
4107 // with depth and normalmap bound as textures,
4108 // with depth bound as attachment as well
4112 case RENDERPATH_GLES2:
4113 r_shadow_usingdeferredprepass = false;
4117 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);
4119 r_shadow_scenenumlights = 0;
4120 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4121 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4122 for (lightindex = 0; lightindex < range; lightindex++)
4124 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4125 if (light && (light->flags & flag))
4127 R_Shadow_PrepareLight(&light->rtlight);
4128 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4131 if (r_refdef.scene.rtdlight)
4133 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4135 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4136 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4139 else if (gl_flashblend.integer)
4141 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4143 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4144 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4145 VectorScale(rtlight->color, f, rtlight->currentcolor);
4149 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4150 if (r_shadow_debuglight.integer >= 0)
4152 r_shadow_scenenumlights = 0;
4153 lightindex = r_shadow_debuglight.integer;
4154 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4157 R_Shadow_PrepareLight(&light->rtlight);
4158 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4162 // if we're doing shadowmaps we need to prepare the atlas layout now
4163 if (R_Shadow_ShadowMappingEnabled())
4167 // allocate shadowmaps in the atlas now
4168 // 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...
4169 for (lod = 0; lod < 16; lod++)
4171 int packing_success = 0;
4172 int packing_failure = 0;
4173 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4174 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4175 if (r_shadow_shadowmapatlas_modelshadows_size)
4176 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);
4177 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4179 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4180 int size = rtlight->shadowmapsidesize >> lod;
4182 if (!rtlight->castshadows)
4184 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4187 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4188 if (rtlight->cached_numshadowentities_noselfshadow)
4190 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4192 rtlight->shadowmapatlassidesize = size;
4197 // note down that we failed to pack this one, it will have to disable shadows
4198 rtlight->shadowmapatlassidesize = 0;
4202 // generally everything fits and we stop here on the first iteration
4203 if (packing_failure == 0)
4208 if (r_editlights.integer)
4209 R_Shadow_DrawLightSprites();
4212 void R_Shadow_DrawShadowMaps(void)
4214 R_Shadow_RenderMode_Begin();
4215 R_Shadow_RenderMode_ActiveLight(NULL);
4217 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4218 R_Shadow_ClearShadowMapTexture();
4220 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4221 if (r_shadow_shadowmapatlas_modelshadows_size)
4223 R_Shadow_DrawModelShadowMaps();
4224 // don't let sound skip if going slow
4225 if (r_refdef.scene.extraupdate)
4229 if (R_Shadow_ShadowMappingEnabled())
4232 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4233 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4236 R_Shadow_RenderMode_End();
4239 void R_Shadow_DrawLights(void)
4243 R_Shadow_RenderMode_Begin();
4245 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4246 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4248 R_Shadow_RenderMode_End();
4251 #define MAX_MODELSHADOWS 1024
4252 static int r_shadow_nummodelshadows;
4253 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4255 void R_Shadow_PrepareModelShadows(void)
4258 float scale, size, radius, dot1, dot2;
4259 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4260 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4261 entity_render_t *ent;
4263 r_shadow_nummodelshadows = 0;
4264 r_shadow_shadowmapatlas_modelshadows_size = 0;
4266 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4269 size = r_shadow_shadowmaptexturesize / 4;
4270 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4271 radius = 0.5f * size / scale;
4273 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4274 VectorCopy(prvmshadowdir, shadowdir);
4275 VectorNormalize(shadowdir);
4276 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4277 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4278 if (fabs(dot1) <= fabs(dot2))
4279 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4281 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4282 VectorNormalize(shadowforward);
4283 CrossProduct(shadowdir, shadowforward, shadowright);
4284 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4285 VectorCopy(prvmshadowfocus, shadowfocus);
4286 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4287 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4288 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4289 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4290 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4292 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4294 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4295 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4296 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4297 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4298 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4299 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4301 for (i = 0; i < r_refdef.scene.numentities; i++)
4303 ent = r_refdef.scene.entities[i];
4304 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4306 // cast shadows from anything of the map (submodels are optional)
4307 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4309 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4311 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4312 R_AnimCache_GetEntity(ent, false, false);
4316 if (r_shadow_nummodelshadows)
4318 r_shadow_shadowmapatlas_modelshadows_x = 0;
4319 r_shadow_shadowmapatlas_modelshadows_y = 0;
4320 r_shadow_shadowmapatlas_modelshadows_size = size;
4324 static void R_Shadow_DrawModelShadowMaps(void)
4327 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4328 entity_render_t *ent;
4329 vec3_t relativelightorigin;
4330 vec3_t relativelightdirection, relativeforward, relativeright;
4331 vec3_t relativeshadowmins, relativeshadowmaxs;
4332 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4333 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4335 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4336 r_viewport_t viewport;
4338 size = r_shadow_shadowmapatlas_modelshadows_size;
4339 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4340 radius = 0.5f / scale;
4341 nearclip = -r_shadows_throwdistance.value;
4342 farclip = r_shadows_throwdistance.value;
4343 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);
4345 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4346 r_shadow_modelshadowmap_parameters[0] = size;
4347 r_shadow_modelshadowmap_parameters[1] = size;
4348 r_shadow_modelshadowmap_parameters[2] = 1.0;
4349 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4350 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4351 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4352 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4353 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4354 r_shadow_usingshadowmaportho = true;
4356 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4357 VectorCopy(prvmshadowdir, shadowdir);
4358 VectorNormalize(shadowdir);
4359 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4360 VectorCopy(prvmshadowfocus, shadowfocus);
4361 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4362 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4363 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4364 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4365 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4366 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4367 if (fabs(dot1) <= fabs(dot2))
4368 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4370 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4371 VectorNormalize(shadowforward);
4372 VectorM(scale, shadowforward, &m[0]);
4373 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4375 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4376 CrossProduct(shadowdir, shadowforward, shadowright);
4377 VectorM(scale, shadowright, &m[4]);
4378 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4379 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4380 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4381 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4382 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4383 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);
4384 R_SetViewport(&viewport);
4386 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4388 // render into a slightly restricted region so that the borders of the
4389 // shadowmap area fade away, rather than streaking across everything
4390 // outside the usable area
4391 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4393 for (i = 0;i < r_shadow_nummodelshadows;i++)
4395 ent = r_shadow_modelshadows[i];
4396 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4397 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4398 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4399 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4400 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4401 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4402 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4403 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4404 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4405 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4406 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4407 RSurf_ActiveModelEntity(ent, false, false, false);
4408 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->submodelsurfaces_end - ent->model->submodelsurfaces_start, ent->model->modelsurfaces_sorted + ent->model->submodelsurfaces_start, NULL, relativeshadowmins, relativeshadowmaxs);
4409 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4415 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4417 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4419 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4420 Cvar_SetValueQuick(&r_test, 0);
4425 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4426 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4427 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4428 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4429 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4430 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4433 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qbool usequery)
4436 vec3_t centerorigin;
4440 // if it's too close, skip it
4441 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4443 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4446 if (usequery && r_numqueries + 2 <= r_maxqueries)
4448 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4449 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4450 // 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
4451 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4453 switch(vid.renderpath)
4455 case RENDERPATH_GL32:
4456 case RENDERPATH_GLES2:
4459 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4460 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4461 GL_DepthFunc(GL_ALWAYS);
4462 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4463 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4464 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4465 qglEndQuery(GL_SAMPLES_PASSED);
4466 GL_DepthFunc(GL_LEQUAL);
4467 qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4468 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4469 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4470 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4471 qglEndQuery(GL_SAMPLES_PASSED);
4477 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4480 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4482 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4485 unsigned int occlude = 0;
4487 // now we have to check the query result
4488 if (rtlight->corona_queryindex_visiblepixels)
4490 switch(vid.renderpath)
4492 case RENDERPATH_GL32:
4493 case RENDERPATH_GLES2:
4495 // store the pixel counts into a uniform buffer for the shader to
4496 // use - we'll never know the results on the cpu without
4497 // synchronizing and we don't want that
4498 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
4499 if (!r_shadow_occlusion_buf) {
4500 qglGenBuffers(1, &r_shadow_occlusion_buf);
4501 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4502 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4504 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4506 qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4507 qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4508 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4509 occlude = MATERIALFLAG_OCCLUDE;
4510 cscale *= rtlight->corona_visibility;
4520 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4523 VectorScale(rtlight->currentcolor, cscale, color);
4524 if (VectorLength(color) > (1.0f / 256.0f))
4527 qbool negated = (color[0] + color[1] + color[2] < 0);
4530 VectorNegate(color, color);
4531 GL_BlendEquationSubtract(true);
4533 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4534 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);
4535 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4537 GL_BlendEquationSubtract(false);
4541 void R_Shadow_DrawCoronas(void)
4544 qbool usequery = false;
4549 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4551 if (r_fb.water.renderingscene)
4553 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4554 R_EntityMatrix(&identitymatrix);
4556 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4558 // check occlusion of coronas, using occlusion queries or raytraces
4560 switch (vid.renderpath)
4562 case RENDERPATH_GL32:
4563 case RENDERPATH_GLES2:
4564 // buffer binding target GL_QUERY_BUFFER: Core since version 4.4
4565 usequery = r_coronas_occlusionquery.integer && vid.support.glversion >= 44;
4569 GL_ColorMask(0,0,0,0);
4570 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4571 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4574 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4575 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4577 qglGenQueries(r_maxqueries - i, r_queries + i);
4580 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4581 GL_BlendFunc(GL_ONE, GL_ZERO);
4582 GL_CullFace(GL_NONE);
4583 GL_DepthMask(false);
4584 GL_DepthRange(0, 1);
4585 GL_PolygonOffset(0, 0);
4587 R_Mesh_ResetTextureState();
4588 R_SetupShader_Generic_NoTexture(false, false);
4593 for (lightindex = 0;lightindex < range;lightindex++)
4595 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4598 rtlight = &light->rtlight;
4599 rtlight->corona_visibility = 0;
4600 rtlight->corona_queryindex_visiblepixels = 0;
4601 rtlight->corona_queryindex_allpixels = 0;
4602 if (!(rtlight->flags & flag))
4604 if (rtlight->corona <= 0)
4606 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4608 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4610 for (i = 0;i < r_refdef.scene.numlights;i++)
4612 rtlight = r_refdef.scene.lights[i];
4613 rtlight->corona_visibility = 0;
4614 rtlight->corona_queryindex_visiblepixels = 0;
4615 rtlight->corona_queryindex_allpixels = 0;
4616 if (!(rtlight->flags & flag))
4618 if (rtlight->corona <= 0)
4620 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4623 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4625 // now draw the coronas using the query data for intensity info
4626 for (lightindex = 0;lightindex < range;lightindex++)
4628 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4631 rtlight = &light->rtlight;
4632 if (rtlight->corona_visibility <= 0)
4634 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4636 for (i = 0;i < r_refdef.scene.numlights;i++)
4638 rtlight = r_refdef.scene.lights[i];
4639 if (rtlight->corona_visibility <= 0)
4641 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4647 static dlight_t *R_Shadow_NewWorldLight(void)
4649 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4652 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)
4656 // 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
4658 // validate parameters
4662 // copy to light properties
4663 VectorCopy(origin, light->origin);
4664 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4665 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4666 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4668 light->color[0] = max(color[0], 0);
4669 light->color[1] = max(color[1], 0);
4670 light->color[2] = max(color[2], 0);
4672 light->color[0] = color[0];
4673 light->color[1] = color[1];
4674 light->color[2] = color[2];
4675 light->radius = max(radius, 0);
4676 light->style = style;
4677 light->shadow = shadowenable;
4678 light->corona = corona;
4679 dp_strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4680 light->coronasizescale = coronasizescale;
4681 light->ambientscale = ambientscale;
4682 light->diffusescale = diffusescale;
4683 light->specularscale = specularscale;
4684 light->flags = flags;
4686 // update renderable light data
4687 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4688 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);
4691 static void R_Shadow_FreeWorldLight(dlight_t *light)
4693 if (r_shadow_selectedlight == light)
4694 r_shadow_selectedlight = NULL;
4695 R_RTLight_Uncompile(&light->rtlight);
4696 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4699 void R_Shadow_ClearWorldLights(void)
4703 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4704 for (lightindex = 0;lightindex < range;lightindex++)
4706 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4708 R_Shadow_FreeWorldLight(light);
4710 r_shadow_selectedlight = NULL;
4713 static void R_Shadow_SelectLight(dlight_t *light)
4715 if (r_shadow_selectedlight)
4716 r_shadow_selectedlight->selected = false;
4717 r_shadow_selectedlight = light;
4718 if (r_shadow_selectedlight)
4719 r_shadow_selectedlight->selected = true;
4722 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4724 // this is never batched (there can be only one)
4726 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4727 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4728 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4731 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4736 skinframe_t *skinframe;
4739 // this is never batched (due to the ent parameter changing every time)
4740 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4741 const dlight_t *light = (dlight_t *)ent;
4744 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4747 VectorScale(light->color, intensity, spritecolor);
4748 if (VectorLength(spritecolor) < 0.1732f)
4749 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4750 if (VectorLength(spritecolor) > 1.0f)
4751 VectorNormalize(spritecolor);
4753 // draw light sprite
4754 if (light->cubemapname[0] && !light->shadow)
4755 skinframe = r_editlights_sprcubemapnoshadowlight;
4756 else if (light->cubemapname[0])
4757 skinframe = r_editlights_sprcubemaplight;
4758 else if (!light->shadow)
4759 skinframe = r_editlights_sprnoshadowlight;
4761 skinframe = r_editlights_sprlight;
4763 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);
4764 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4766 // draw selection sprite if light is selected
4767 if (light->selected)
4769 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4770 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4771 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4775 void R_Shadow_DrawLightSprites(void)
4779 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4780 for (lightindex = 0;lightindex < range;lightindex++)
4782 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4784 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4786 if (!r_editlights_lockcursor)
4787 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4790 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4795 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4796 if (lightindex >= range)
4798 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4801 rtlight = &light->rtlight;
4802 //if (!(rtlight->flags & flag))
4804 VectorCopy(rtlight->shadoworigin, origin);
4805 *radius = rtlight->radius;
4806 VectorCopy(rtlight->color, color);
4810 static void R_Shadow_SelectLightInView(void)
4812 float bestrating, rating, temp[3];
4816 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4820 if (r_editlights_lockcursor)
4822 for (lightindex = 0;lightindex < range;lightindex++)
4824 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4827 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4828 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4831 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4832 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)
4834 bestrating = rating;
4839 R_Shadow_SelectLight(best);
4842 void R_Shadow_LoadWorldLights(void)
4844 int n, a, style, shadow, flags;
4845 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4846 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4847 if (cl.worldmodel == NULL)
4849 Con_Print("No map loaded.\n");
4852 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4853 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4863 for (;COM_Parse(t, true) && strcmp(
4864 if (COM_Parse(t, true))
4866 if (com_token[0] == '!')
4869 origin[0] = atof(com_token+1);
4872 origin[0] = atof(com_token);
4877 while (*s && *s != '\n' && *s != '\r')
4883 // check for modifier flags
4890 #if _MSC_VER >= 1400
4891 #define sscanf sscanf_s
4893 cubemapname[sizeof(cubemapname)-1] = 0;
4894 #if MAX_QPATH != 128
4895 #error update this code if MAX_QPATH changes
4897 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
4898 #if _MSC_VER >= 1400
4899 , (unsigned int)sizeof(cubemapname)
4901 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4904 flags = LIGHTFLAG_REALTIMEMODE;
4912 coronasizescale = 0.25f;
4914 VectorClear(angles);
4917 if (a < 9 || !strcmp(cubemapname, "\"\""))
4919 // remove quotes on cubemapname
4920 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4923 namelen = strlen(cubemapname) - 2;
4924 memmove(cubemapname, cubemapname + 1, namelen);
4925 cubemapname[namelen] = '\0';
4929 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);
4932 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4940 Con_Printf("invalid rtlights file \"%s\"\n", name);
4941 Mem_Free(lightsstring);
4945 void R_Shadow_SaveWorldLights(void)
4949 size_t bufchars, bufmaxchars;
4951 char name[MAX_QPATH];
4952 char line[MAX_INPUTLINE];
4953 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4954 // I hate lines which are 3 times my screen size :( --blub
4957 if (cl.worldmodel == NULL)
4959 Con_Print("No map loaded.\n");
4962 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4963 bufchars = bufmaxchars = 0;
4965 for (lightindex = 0;lightindex < range;lightindex++)
4967 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4970 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4971 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);
4972 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4973 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]);
4975 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);
4976 if (bufchars + strlen(line) > bufmaxchars)
4978 bufmaxchars = bufchars + strlen(line) + 2048;
4980 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4984 memcpy(buf, oldbuf, bufchars);
4990 memcpy(buf + bufchars, line, strlen(line));
4991 bufchars += strlen(line);
4995 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5000 void R_Shadow_LoadLightsFile(void)
5003 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5004 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5005 if (cl.worldmodel == NULL)
5007 Con_Print("No map loaded.\n");
5010 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5011 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5019 while (*s && *s != '\n' && *s != '\r')
5025 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);
5029 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);
5032 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5033 radius = bound(15, radius, 4096);
5034 VectorScale(color, (2.0f / (8388608.0f)), color);
5035 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5043 Con_Printf("invalid lights file \"%s\"\n", name);
5044 Mem_Free(lightsstring);
5048 // tyrlite/hmap2 light types in the delay field
5049 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5051 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5063 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5064 char key[256], value[MAX_INPUTLINE];
5067 if (cl.worldmodel == NULL)
5069 Con_Print("No map loaded.\n");
5072 // try to load a .ent file first
5073 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5074 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5075 // and if that is not found, fall back to the bsp file entity string
5077 data = cl.worldmodel->brush.entities;
5080 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5082 type = LIGHTTYPE_MINUSX;
5083 origin[0] = origin[1] = origin[2] = 0;
5084 originhack[0] = originhack[1] = originhack[2] = 0;
5085 angles[0] = angles[1] = angles[2] = 0;
5086 color[0] = color[1] = color[2] = 1;
5087 light[0] = light[1] = light[2] = 1;light[3] = 300;
5088 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5098 if (!COM_ParseToken_Simple(&data, false, false, true))
5100 if (com_token[0] == '}')
5101 break; // end of entity
5102 if (com_token[0] == '_')
5103 dp_strlcpy(key, com_token + 1, sizeof(key));
5105 dp_strlcpy(key, com_token, sizeof(key));
5106 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5107 key[strlen(key)-1] = 0;
5108 if (!COM_ParseToken_Simple(&data, false, false, true))
5110 dp_strlcpy(value, com_token, sizeof(value));
5112 // now that we have the key pair worked out...
5113 if (!strcmp("light", key))
5115 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5119 light[0] = vec[0] * (1.0f / 256.0f);
5120 light[1] = vec[0] * (1.0f / 256.0f);
5121 light[2] = vec[0] * (1.0f / 256.0f);
5127 light[0] = vec[0] * (1.0f / 255.0f);
5128 light[1] = vec[1] * (1.0f / 255.0f);
5129 light[2] = vec[2] * (1.0f / 255.0f);
5133 else if (!strcmp("delay", key))
5135 else if (!strcmp("origin", key))
5136 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5137 else if (!strcmp("angle", key))
5138 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5139 else if (!strcmp("angles", key))
5140 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5141 else if (!strcmp("color", key))
5142 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5143 else if (!strcmp("wait", key))
5144 fadescale = atof(value);
5145 else if (!strcmp("classname", key))
5147 if (!strncmp(value, "light", 5))
5150 if (!strcmp(value, "light_fluoro"))
5155 overridecolor[0] = 1;
5156 overridecolor[1] = 1;
5157 overridecolor[2] = 1;
5159 if (!strcmp(value, "light_fluorospark"))
5164 overridecolor[0] = 1;
5165 overridecolor[1] = 1;
5166 overridecolor[2] = 1;
5168 if (!strcmp(value, "light_globe"))
5173 overridecolor[0] = 1;
5174 overridecolor[1] = 0.8;
5175 overridecolor[2] = 0.4;
5177 if (!strcmp(value, "light_flame_large_yellow"))
5182 overridecolor[0] = 1;
5183 overridecolor[1] = 0.5;
5184 overridecolor[2] = 0.1;
5186 if (!strcmp(value, "light_flame_small_yellow"))
5191 overridecolor[0] = 1;
5192 overridecolor[1] = 0.5;
5193 overridecolor[2] = 0.1;
5195 if (!strcmp(value, "light_torch_small_white"))
5200 overridecolor[0] = 1;
5201 overridecolor[1] = 0.5;
5202 overridecolor[2] = 0.1;
5204 if (!strcmp(value, "light_torch_small_walltorch"))
5209 overridecolor[0] = 1;
5210 overridecolor[1] = 0.5;
5211 overridecolor[2] = 0.1;
5215 else if (!strcmp("style", key))
5216 style = atoi(value);
5217 else if (!strcmp("skin", key))
5218 skin = (int)atof(value);
5219 else if (!strcmp("pflags", key))
5220 pflags = (int)atof(value);
5221 //else if (!strcmp("effects", key))
5222 // effects = (int)atof(value);
5223 else if (cl.worldmodel->type == mod_brushq3)
5225 if (!strcmp("scale", key))
5226 lightscale = atof(value);
5227 if (!strcmp("fade", key))
5228 fadescale = atof(value);
5233 if (lightscale <= 0)
5237 if (color[0] == color[1] && color[0] == color[2])
5239 color[0] *= overridecolor[0];
5240 color[1] *= overridecolor[1];
5241 color[2] *= overridecolor[2];
5243 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5244 color[0] = color[0] * light[0];
5245 color[1] = color[1] * light[1];
5246 color[2] = color[2] * light[2];
5249 case LIGHTTYPE_MINUSX:
5251 case LIGHTTYPE_RECIPX:
5253 VectorScale(color, (1.0f / 16.0f), color);
5255 case LIGHTTYPE_RECIPXX:
5257 VectorScale(color, (1.0f / 16.0f), color);
5260 case LIGHTTYPE_NONE:
5264 case LIGHTTYPE_MINUSXX:
5267 VectorAdd(origin, originhack, origin);
5269 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);
5272 Mem_Free(entfiledata);
5276 static void R_Shadow_SetCursorLocationForView(void)
5279 vec3_t dest, endpos;
5281 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5282 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5283 if (trace.fraction < 1)
5285 dist = trace.fraction * r_editlights_cursordistance.value;
5286 push = r_editlights_cursorpushback.value;
5290 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5291 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5295 VectorClear( endpos );
5297 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5298 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5299 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5302 void R_Shadow_UpdateWorldLightSelection(void)
5304 if (r_editlights.integer)
5306 R_Shadow_SetCursorLocationForView();
5307 R_Shadow_SelectLightInView();
5310 R_Shadow_SelectLight(NULL);
5313 static void R_Shadow_EditLights_Clear_f(cmd_state_t *cmd)
5315 R_Shadow_ClearWorldLights();
5318 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd)
5322 dp_strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5323 R_Shadow_ClearWorldLights();
5324 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5326 R_Shadow_LoadWorldLights();
5327 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5328 R_Shadow_LoadLightsFile();
5330 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5332 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5333 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5337 static void R_Shadow_EditLights_Save_f(cmd_state_t *cmd)
5341 R_Shadow_SaveWorldLights();
5344 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(cmd_state_t *cmd)
5346 R_Shadow_ClearWorldLights();
5347 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5350 static void R_Shadow_EditLights_ImportLightsFile_f(cmd_state_t *cmd)
5352 R_Shadow_ClearWorldLights();
5353 R_Shadow_LoadLightsFile();
5356 static void R_Shadow_EditLights_Spawn_f(cmd_state_t *cmd)
5359 if (!r_editlights.integer)
5361 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5364 if (Cmd_Argc(cmd) != 1)
5366 Con_Print("r_editlights_spawn does not take parameters\n");
5369 color[0] = color[1] = color[2] = 1;
5370 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5373 static void R_Shadow_EditLights_Edit_f(cmd_state_t *cmd)
5375 vec3_t origin, angles, color;
5376 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5377 int style, shadows, flags, normalmode, realtimemode;
5378 char cubemapname[MAX_INPUTLINE];
5379 if (!r_editlights.integer)
5381 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5384 if (!r_shadow_selectedlight)
5386 Con_Print("No selected light.\n");
5389 VectorCopy(r_shadow_selectedlight->origin, origin);
5390 VectorCopy(r_shadow_selectedlight->angles, angles);
5391 VectorCopy(r_shadow_selectedlight->color, color);
5392 radius = r_shadow_selectedlight->radius;
5393 style = r_shadow_selectedlight->style;
5394 if (*r_shadow_selectedlight->cubemapname)
5395 dp_strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5398 shadows = r_shadow_selectedlight->shadow;
5399 corona = r_shadow_selectedlight->corona;
5400 coronasizescale = r_shadow_selectedlight->coronasizescale;
5401 ambientscale = r_shadow_selectedlight->ambientscale;
5402 diffusescale = r_shadow_selectedlight->diffusescale;
5403 specularscale = r_shadow_selectedlight->specularscale;
5404 flags = r_shadow_selectedlight->flags;
5405 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5406 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5407 if (!strcmp(Cmd_Argv(cmd, 1), "origin"))
5409 if (Cmd_Argc(cmd) != 5)
5411 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5414 origin[0] = atof(Cmd_Argv(cmd, 2));
5415 origin[1] = atof(Cmd_Argv(cmd, 3));
5416 origin[2] = atof(Cmd_Argv(cmd, 4));
5418 else if (!strcmp(Cmd_Argv(cmd, 1), "originscale"))
5420 if (Cmd_Argc(cmd) != 5)
5422 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5425 origin[0] *= atof(Cmd_Argv(cmd, 2));
5426 origin[1] *= atof(Cmd_Argv(cmd, 3));
5427 origin[2] *= atof(Cmd_Argv(cmd, 4));
5429 else if (!strcmp(Cmd_Argv(cmd, 1), "originx"))
5431 if (Cmd_Argc(cmd) != 3)
5433 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5436 origin[0] = atof(Cmd_Argv(cmd, 2));
5438 else if (!strcmp(Cmd_Argv(cmd, 1), "originy"))
5440 if (Cmd_Argc(cmd) != 3)
5442 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5445 origin[1] = atof(Cmd_Argv(cmd, 2));
5447 else if (!strcmp(Cmd_Argv(cmd, 1), "originz"))
5449 if (Cmd_Argc(cmd) != 3)
5451 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5454 origin[2] = atof(Cmd_Argv(cmd, 2));
5456 else if (!strcmp(Cmd_Argv(cmd, 1), "move"))
5458 if (Cmd_Argc(cmd) != 5)
5460 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5463 origin[0] += atof(Cmd_Argv(cmd, 2));
5464 origin[1] += atof(Cmd_Argv(cmd, 3));
5465 origin[2] += atof(Cmd_Argv(cmd, 4));
5467 else if (!strcmp(Cmd_Argv(cmd, 1), "movex"))
5469 if (Cmd_Argc(cmd) != 3)
5471 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5474 origin[0] += atof(Cmd_Argv(cmd, 2));
5476 else if (!strcmp(Cmd_Argv(cmd, 1), "movey"))
5478 if (Cmd_Argc(cmd) != 3)
5480 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5483 origin[1] += atof(Cmd_Argv(cmd, 2));
5485 else if (!strcmp(Cmd_Argv(cmd, 1), "movez"))
5487 if (Cmd_Argc(cmd) != 3)
5489 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5492 origin[2] += atof(Cmd_Argv(cmd, 2));
5494 else if (!strcmp(Cmd_Argv(cmd, 1), "angles"))
5496 if (Cmd_Argc(cmd) != 5)
5498 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5501 angles[0] = atof(Cmd_Argv(cmd, 2));
5502 angles[1] = atof(Cmd_Argv(cmd, 3));
5503 angles[2] = atof(Cmd_Argv(cmd, 4));
5505 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesx"))
5507 if (Cmd_Argc(cmd) != 3)
5509 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5512 angles[0] = atof(Cmd_Argv(cmd, 2));
5514 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesy"))
5516 if (Cmd_Argc(cmd) != 3)
5518 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5521 angles[1] = atof(Cmd_Argv(cmd, 2));
5523 else if (!strcmp(Cmd_Argv(cmd, 1), "anglesz"))
5525 if (Cmd_Argc(cmd) != 3)
5527 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5530 angles[2] = atof(Cmd_Argv(cmd, 2));
5532 else if (!strcmp(Cmd_Argv(cmd, 1), "color"))
5534 if (Cmd_Argc(cmd) != 5)
5536 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(cmd, 1));
5539 color[0] = atof(Cmd_Argv(cmd, 2));
5540 color[1] = atof(Cmd_Argv(cmd, 3));
5541 color[2] = atof(Cmd_Argv(cmd, 4));
5543 else if (!strcmp(Cmd_Argv(cmd, 1), "radius"))
5545 if (Cmd_Argc(cmd) != 3)
5547 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5550 radius = atof(Cmd_Argv(cmd, 2));
5552 else if (!strcmp(Cmd_Argv(cmd, 1), "colorscale"))
5554 if (Cmd_Argc(cmd) == 3)
5556 double scale = atof(Cmd_Argv(cmd, 2));
5563 if (Cmd_Argc(cmd) != 5)
5565 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(cmd, 1));
5568 color[0] *= atof(Cmd_Argv(cmd, 2));
5569 color[1] *= atof(Cmd_Argv(cmd, 3));
5570 color[2] *= atof(Cmd_Argv(cmd, 4));
5573 else if (!strcmp(Cmd_Argv(cmd, 1), "radiusscale") || !strcmp(Cmd_Argv(cmd, 1), "sizescale"))
5575 if (Cmd_Argc(cmd) != 3)
5577 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5580 radius *= atof(Cmd_Argv(cmd, 2));
5582 else if (!strcmp(Cmd_Argv(cmd, 1), "style"))
5584 if (Cmd_Argc(cmd) != 3)
5586 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5589 style = atoi(Cmd_Argv(cmd, 2));
5591 else if (!strcmp(Cmd_Argv(cmd, 1), "cubemap"))
5593 if (Cmd_Argc(cmd) > 3)
5595 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5598 if (Cmd_Argc(cmd) == 3)
5599 dp_strlcpy(cubemapname, Cmd_Argv(cmd, 2), sizeof(cubemapname));
5603 else if (!strcmp(Cmd_Argv(cmd, 1), "shadows"))
5605 if (Cmd_Argc(cmd) != 3)
5607 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5610 shadows = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5612 else if (!strcmp(Cmd_Argv(cmd, 1), "corona"))
5614 if (Cmd_Argc(cmd) != 3)
5616 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5619 corona = atof(Cmd_Argv(cmd, 2));
5621 else if (!strcmp(Cmd_Argv(cmd, 1), "coronasize"))
5623 if (Cmd_Argc(cmd) != 3)
5625 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5628 coronasizescale = atof(Cmd_Argv(cmd, 2));
5630 else if (!strcmp(Cmd_Argv(cmd, 1), "ambient"))
5632 if (Cmd_Argc(cmd) != 3)
5634 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5637 ambientscale = atof(Cmd_Argv(cmd, 2));
5639 else if (!strcmp(Cmd_Argv(cmd, 1), "diffuse"))
5641 if (Cmd_Argc(cmd) != 3)
5643 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5646 diffusescale = atof(Cmd_Argv(cmd, 2));
5648 else if (!strcmp(Cmd_Argv(cmd, 1), "specular"))
5650 if (Cmd_Argc(cmd) != 3)
5652 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5655 specularscale = atof(Cmd_Argv(cmd, 2));
5657 else if (!strcmp(Cmd_Argv(cmd, 1), "normalmode"))
5659 if (Cmd_Argc(cmd) != 3)
5661 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5664 normalmode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5666 else if (!strcmp(Cmd_Argv(cmd, 1), "realtimemode"))
5668 if (Cmd_Argc(cmd) != 3)
5670 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5673 realtimemode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5677 Con_Print("usage: r_editlights_edit [property] [value]\n");
5678 Con_Print("Selected light's properties:\n");
5679 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5680 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5681 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5682 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5683 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5684 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5685 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5686 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5687 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5688 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5689 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5690 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5691 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5692 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5695 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5696 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5699 static void R_Shadow_EditLights_EditAll_f(cmd_state_t *cmd)
5702 dlight_t *light, *oldselected;
5705 if (!r_editlights.integer)
5707 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5711 oldselected = r_shadow_selectedlight;
5712 // EditLights doesn't seem to have a "remove" command or something so:
5713 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5714 for (lightindex = 0;lightindex < range;lightindex++)
5716 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5719 R_Shadow_SelectLight(light);
5720 R_Shadow_EditLights_Edit_f(cmd_local);
5722 // return to old selected (to not mess editing once selection is locked)
5723 R_Shadow_SelectLight(oldselected);
5726 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5728 int lightnumber, lightcount;
5729 size_t lightindex, range;
5734 if (!r_editlights.integer)
5737 // update cvars so QC can query them
5738 if (r_shadow_selectedlight)
5740 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5741 Cvar_SetQuick(&r_editlights_current_origin, temp);
5742 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5743 Cvar_SetQuick(&r_editlights_current_angles, temp);
5744 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5745 Cvar_SetQuick(&r_editlights_current_color, temp);
5746 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5747 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5748 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5749 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5750 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5751 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5752 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5753 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5754 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5755 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5756 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5759 // draw properties on screen
5760 if (!r_editlights_drawproperties.integer)
5762 x = vid_conwidth.value - 320;
5764 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5767 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5768 for (lightindex = 0;lightindex < range;lightindex++)
5770 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5773 if (light == r_shadow_selectedlight)
5774 lightnumber = (int)lightindex;
5777 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;
5778 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;
5780 if (r_shadow_selectedlight == NULL)
5782 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;
5783 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;
5784 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;
5785 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;
5786 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;
5787 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;
5788 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;
5789 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;
5790 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;
5791 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;
5792 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;
5793 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;
5794 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;
5795 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;
5796 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;
5798 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;
5799 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;
5800 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;
5801 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;
5802 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;
5803 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;
5804 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;
5805 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;
5806 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;
5807 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;
5810 static void R_Shadow_EditLights_ToggleShadow_f(cmd_state_t *cmd)
5812 if (!r_editlights.integer)
5814 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5817 if (!r_shadow_selectedlight)
5819 Con_Print("No selected light.\n");
5822 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);
5825 static void R_Shadow_EditLights_ToggleCorona_f(cmd_state_t *cmd)
5827 if (!r_editlights.integer)
5829 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5832 if (!r_shadow_selectedlight)
5834 Con_Print("No selected light.\n");
5837 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);
5840 static void R_Shadow_EditLights_Remove_f(cmd_state_t *cmd)
5842 if (!r_editlights.integer)
5844 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5847 if (!r_shadow_selectedlight)
5849 Con_Print("No selected light.\n");
5852 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5853 r_shadow_selectedlight = NULL;
5856 static void R_Shadow_EditLights_Help_f(cmd_state_t *cmd)
5859 "Documentation on r_editlights system:\n"
5861 "r_editlights : enable/disable editing mode\n"
5862 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5863 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5864 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5865 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5866 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5868 "r_editlights_help : this help\n"
5869 "r_editlights_clear : remove all lights\n"
5870 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5871 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5872 "r_editlights_save : save to .rtlights file\n"
5873 "r_editlights_spawn : create a light with default settings\n"
5874 "r_editlights_edit command : edit selected light - more documentation below\n"
5875 "r_editlights_remove : remove selected light\n"
5876 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5877 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5878 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5880 "origin x y z : set light location\n"
5881 "originx x: set x component of light location\n"
5882 "originy y: set y component of light location\n"
5883 "originz z: set z component of light location\n"
5884 "move x y z : adjust light location\n"
5885 "movex x: adjust x component of light location\n"
5886 "movey y: adjust y component of light location\n"
5887 "movez z: adjust z component of light location\n"
5888 "angles x y z : set light angles\n"
5889 "anglesx x: set x component of light angles\n"
5890 "anglesy y: set y component of light angles\n"
5891 "anglesz z: set z component of light angles\n"
5892 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5893 "radius radius : set radius (size) of light\n"
5894 "colorscale grey : multiply color of light (1 does nothing)\n"
5895 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5896 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5897 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5898 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5899 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5900 "cubemap basename : set filter cubemap of light\n"
5901 "shadows 1/0 : turn on/off shadows\n"
5902 "corona n : set corona intensity\n"
5903 "coronasize n : set corona size (0-1)\n"
5904 "ambient n : set ambient intensity (0-1)\n"
5905 "diffuse n : set diffuse intensity (0-1)\n"
5906 "specular n : set specular intensity (0-1)\n"
5907 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5908 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5909 "<nothing> : print light properties to console\n"
5913 static void R_Shadow_EditLights_CopyInfo_f(cmd_state_t *cmd)
5915 if (!r_editlights.integer)
5917 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5920 if (!r_shadow_selectedlight)
5922 Con_Print("No selected light.\n");
5925 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5926 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5927 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5928 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5929 if (*r_shadow_selectedlight->cubemapname)
5930 dp_strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5932 r_shadow_bufferlight.cubemapname[0] = 0;
5933 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5934 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5935 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5936 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5937 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5938 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5939 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5942 static void R_Shadow_EditLights_PasteInfo_f(cmd_state_t *cmd)
5944 if (!r_editlights.integer)
5946 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5949 if (!r_shadow_selectedlight)
5951 Con_Print("No selected light.\n");
5954 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);
5957 static void R_Shadow_EditLights_Lock_f(cmd_state_t *cmd)
5959 if (!r_editlights.integer)
5961 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5964 if (r_editlights_lockcursor)
5966 r_editlights_lockcursor = false;
5969 if (!r_shadow_selectedlight)
5971 Con_Print("No selected light to lock on.\n");
5974 r_editlights_lockcursor = true;
5977 static void R_Shadow_EditLights_Init(void)
5979 Cvar_RegisterVariable(&r_editlights);
5980 Cvar_RegisterVariable(&r_editlights_cursordistance);
5981 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5982 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5983 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5984 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5985 Cvar_RegisterVariable(&r_editlights_drawproperties);
5986 Cvar_RegisterVariable(&r_editlights_current_origin);
5987 Cvar_RegisterVariable(&r_editlights_current_angles);
5988 Cvar_RegisterVariable(&r_editlights_current_color);
5989 Cvar_RegisterVariable(&r_editlights_current_radius);
5990 Cvar_RegisterVariable(&r_editlights_current_corona);
5991 Cvar_RegisterVariable(&r_editlights_current_coronasize);
5992 Cvar_RegisterVariable(&r_editlights_current_style);
5993 Cvar_RegisterVariable(&r_editlights_current_shadows);
5994 Cvar_RegisterVariable(&r_editlights_current_cubemap);
5995 Cvar_RegisterVariable(&r_editlights_current_ambient);
5996 Cvar_RegisterVariable(&r_editlights_current_diffuse);
5997 Cvar_RegisterVariable(&r_editlights_current_specular);
5998 Cvar_RegisterVariable(&r_editlights_current_normalmode);
5999 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6000 Cmd_AddCommand(CF_CLIENT, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6001 Cmd_AddCommand(CF_CLIENT, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6002 Cmd_AddCommand(CF_CLIENT, "r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
6003 Cmd_AddCommand(CF_CLIENT, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6004 Cmd_AddCommand(CF_CLIENT, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6005 Cmd_AddCommand(CF_CLIENT, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6006 Cmd_AddCommand(CF_CLIENT, "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)");
6007 Cmd_AddCommand(CF_CLIENT, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6008 Cmd_AddCommand(CF_CLIENT, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6009 Cmd_AddCommand(CF_CLIENT, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6010 Cmd_AddCommand(CF_CLIENT, "r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6011 Cmd_AddCommand(CF_CLIENT, "r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6012 Cmd_AddCommand(CF_CLIENT, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6013 Cmd_AddCommand(CF_CLIENT, "r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
6014 Cmd_AddCommand(CF_CLIENT, "r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6020 =============================================================================
6024 =============================================================================
6027 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6029 int i, numlights, flag, q;
6032 float relativepoint[3];
6037 float sa[3], sx[3], sy[3], sz[3], sd[3];
6040 // use first order spherical harmonics to combine directional lights
6041 for (q = 0; q < 3; q++)
6042 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6044 if (flags & LP_LIGHTMAP)
6046 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6048 float tempambient[3];
6049 for (q = 0; q < 3; q++)
6050 tempambient[q] = color[q] = relativepoint[q] = 0;
6051 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6052 // calculate a weighted average light direction as well
6053 intensity = VectorLength(color);
6054 for (q = 0; q < 3; q++)
6056 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6057 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6058 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6059 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6060 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6065 // unlit map - fullbright but scaled by lightmapintensity
6066 for (q = 0; q < 3; q++)
6067 sa[q] += lightmapintensity;
6071 if (flags & LP_RTWORLD)
6073 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6074 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6075 for (i = 0; i < numlights; i++)
6077 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6080 light = &dlight->rtlight;
6081 if (!(light->flags & flag))
6084 lightradius2 = light->radius * light->radius;
6085 VectorSubtract(light->shadoworigin, p, relativepoint);
6086 dist2 = VectorLength2(relativepoint);
6087 if (dist2 >= lightradius2)
6089 dist = sqrt(dist2) / light->radius;
6090 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6091 if (intensity <= 0.0f)
6093 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)
6095 for (q = 0; q < 3; q++)
6096 color[q] = light->currentcolor[q] * intensity;
6097 intensity = VectorLength(color);
6098 VectorNormalize(relativepoint);
6099 for (q = 0; q < 3; q++)
6101 sa[q] += 0.5f * color[q];
6102 sx[q] += relativepoint[0] * color[q];
6103 sy[q] += relativepoint[1] * color[q];
6104 sz[q] += relativepoint[2] * color[q];
6105 sd[q] += intensity * relativepoint[q];
6108 // FIXME: sample bouncegrid too!
6111 if (flags & LP_DYNLIGHT)
6114 for (i = 0;i < r_refdef.scene.numlights;i++)
6116 light = r_refdef.scene.lights[i];
6118 lightradius2 = light->radius * light->radius;
6119 VectorSubtract(light->shadoworigin, p, relativepoint);
6120 dist2 = VectorLength2(relativepoint);
6121 if (dist2 >= lightradius2)
6123 dist = sqrt(dist2) / light->radius;
6124 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6125 if (intensity <= 0.0f)
6127 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6129 for (q = 0; q < 3; q++)
6130 color[q] = light->currentcolor[q] * intensity;
6131 intensity = VectorLength(color);
6132 VectorNormalize(relativepoint);
6133 for (q = 0; q < 3; q++)
6135 sa[q] += 0.5f * color[q];
6136 sx[q] += relativepoint[0] * color[q];
6137 sy[q] += relativepoint[1] * color[q];
6138 sz[q] += relativepoint[2] * color[q];
6139 sd[q] += intensity * relativepoint[q];
6144 // calculate the weighted-average light direction (bentnormal)
6145 for (q = 0; q < 3; q++)
6146 lightdir[q] = sd[q];
6147 VectorNormalize(lightdir);
6148 for (q = 0; q < 3; q++)
6150 // extract the diffuse color along the chosen direction and scale it
6151 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6152 // subtract some of diffuse from ambient
6153 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;