cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
-cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
+cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "4", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
//cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
-cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, requires r_shadow_realtime_world 1"};
+cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"};
+cvar_t r_shadow_bouncegrid_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
cvar_t r_shadow_bouncegrid_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dlightparticlemultiplier", "0", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
+cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
-cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
-cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "3", "maximum number of bounces for a particle (minimum is 1)"};
-cvar_t r_shadow_bouncegrid_nolerpsplat = {CVAR_SAVE, "r_shadow_bouncegrid_nolerpsplat", "0", "enables slightly quicker (but worse looking) photon accumulation"};
-cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "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"};
-cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "2", "brightness of particles contributing to bouncegrid texture"};
+cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "4", "particles stop at this fraction of light radius (can be more than 1)"};
+cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
+cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "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"};
+cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
cvar_t r_shadow_bouncegrid_photons = {CVAR_SAVE, "r_shadow_bouncegrid_photons", "2000", "total photons to shoot per update, divided proportionately between lights"};
-cvar_t r_shadow_bouncegrid_spacingx = {CVAR_SAVE, "r_shadow_bouncegrid_spacingx", "64", "unit size of bouncegrid pixel on X axis"};
-cvar_t r_shadow_bouncegrid_spacingy = {CVAR_SAVE, "r_shadow_bouncegrid_spacingy", "64", "unit size of bouncegrid pixel on Y axis"};
-cvar_t r_shadow_bouncegrid_spacingz = {CVAR_SAVE, "r_shadow_bouncegrid_spacingz", "64", "unit size of bouncegrid pixel on Z axis"};
+cvar_t r_shadow_bouncegrid_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_spacing", "64", "unit size of bouncegrid pixel"};
cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
+cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
+cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
+cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
+cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
+cvar_t r_shadow_bouncegrid_static_photons = {CVAR_SAVE, "r_shadow_bouncegrid_static_photons", "25000", "photons value to use when in static mode"};
cvar_t r_shadow_bouncegrid_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"};
cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
+typedef struct r_shadow_bouncegrid_settings_s
+{
+ qboolean staticmode;
+ qboolean bounceanglediffuse;
+ qboolean directionalshading;
+ qboolean includedirectlighting;
+ float dlightparticlemultiplier;
+ qboolean hitmodels;
+ float lightradiusscale;
+ int maxbounce;
+ float particlebounceintensity;
+ float particleintensity;
+ int photons;
+ float spacing[3];
+ int stablerandom;
+}
+r_shadow_bouncegrid_settings_t;
+
+r_shadow_bouncegrid_settings_t r_shadow_bouncegridsettings;
rtexture_t *r_shadow_bouncegridtexture;
matrix4x4_t r_shadow_bouncegridmatrix;
vec_t r_shadow_bouncegridintensity;
+qboolean r_shadow_bouncegriddirectional;
static double r_shadow_bouncegridtime;
static int r_shadow_bouncegridresolution[3];
static int r_shadow_bouncegridnumpixels;
static unsigned char *r_shadow_bouncegridpixels;
-static unsigned short *r_shadow_bouncegridhighpixels;
+static float *r_shadow_bouncegridhighpixels;
// note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
#define ATTENTABLESIZE 256
r_shadow_shadowmappcf = 1;
r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
break;
- case RENDERPATH_GL13:
- break;
case RENDERPATH_GL11:
- break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GLES1:
case RENDERPATH_GLES2:
break;
}
r_shadow_bouncegridhighpixels = NULL;
r_shadow_bouncegridnumpixels = 0;
r_shadow_bouncegridtexture = NULL;
+ r_shadow_bouncegriddirectional = false;
r_shadow_attenuationgradienttexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_attenuation3dtexture = NULL;
r_shadow_bouncegridpixels = NULL;
r_shadow_bouncegridhighpixels = NULL;
r_shadow_bouncegridnumpixels = 0;
+ r_shadow_bouncegriddirectional = false;
r_shadow_attenuationgradienttexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_attenuation3dtexture = NULL;
Cvar_RegisterVariable(&r_shadow_texture3d);
Cvar_RegisterVariable(&r_shadow_bouncegrid);
Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
- Cvar_RegisterVariable(&r_shadow_bouncegrid_nolerpsplat);
Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
- Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
- Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
- Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing);
Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_static_photons);
Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
pixels[y][x][3] = 255;
}
}
- r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
+ r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
}
static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
GL_DepthMask(false);
GL_Color(0, 0, 0, 1);
GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
-
+
r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
case RENDERPATH_GLES2:
r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
break;
- case RENDERPATH_GL13:
case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GLES1:
if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
void R_Shadow_RenderMode_Reset(void)
{
- R_Mesh_ResetRenderTargets();
+ R_Mesh_SetMainRenderTargets();
R_SetViewport(&r_refdef.view.viewport);
GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
R_Mesh_ResetTextureState();
GL_Color(1, 1, 1, 1);
GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
GL_BlendFunc(GL_ONE, GL_ZERO);
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+ R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
r_shadow_usingshadowmap2d = false;
r_shadow_usingshadowmaportho = false;
R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
GL_ColorMask(0, 0, 0, 0);
GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
GL_CullFace(GL_NONE);
- R_SetupShader_DepthOrShadow();
+ R_SetupShader_DepthOrShadow(false);
r_shadow_rendermode = mode;
switch(mode)
{
r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
R_Mesh_ResetTextureState();
- R_Mesh_ResetRenderTargets();
R_Shadow_RenderMode_Reset();
- if (fbo)
- {
- R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
- R_SetupShader_DepthOrShadow();
- }
- else
- R_SetupShader_ShowDepth();
+ R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
+ R_SetupShader_DepthOrShadow(true);
GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
GL_DepthMask(true);
GL_DepthTest(true);
case RENDERPATH_GL13:
case RENDERPATH_GL20:
case RENDERPATH_SOFT:
+ case RENDERPATH_GLES1:
case RENDERPATH_GLES2:
GL_CullFace(r_refdef.view.cullface_back);
// OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
{
R_Mesh_ResetTextureState();
- R_Mesh_ResetRenderTargets();
+ R_Mesh_SetMainRenderTargets();
if (transparent)
{
r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
// only draw light where this geometry was already rendered AND the
// stencil is 128 (values other than this mean shadow)
R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
- R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+ if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
+ R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+ else
+ R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
r_shadow_usingshadowmap2d = shadowmapping;
R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
}
-static void R_Shadow_UpdateBounceGridTexture(void)
+void R_Shadow_UpdateBounceGridTexture(void)
{
#define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
dlight_t *light;
int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
int bouncecount;
- int c[3];
int hitsupercontentsmask;
int maxbounce;
int numpixels;
//trace_t cliptrace3;
unsigned char *pixel;
unsigned char *pixels;
- unsigned short *highpixel;
- unsigned short *highpixels;
+ float *highpixel;
+ float *highpixels;
unsigned int lightindex;
unsigned int range;
unsigned int range1;
vec3_t size;
vec3_t spacing;
vec3_t lightcolor;
+ vec3_t steppos;
+ vec3_t stepdelta;
+ vec3_t cullmins, cullmaxs;
vec_t radius;
vec_t s;
vec_t lightintensity;
vec_t photonscaling;
vec_t photonresidual;
float m[16];
- int texlerp[2][3];
- int splatcolor[3];
+ float texlerp[2][3];
+ float splatcolor[32];
+ float pixelweight[8];
+ float w;
+ int c[4];
int pixelindex[8];
- int pixelweight[8];
int corner;
- qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
+ int pixelsperband;
+ int pixelband;
+ int pixelbands;
+ int numsteps;
+ int step;
+ int x, y, z;
rtlight_t *rtlight;
- if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
+ r_shadow_bouncegrid_settings_t settings;
+ qboolean enable = r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
+ qboolean allowdirectionalshading = false;
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ allowdirectionalshading = true;
+ if (!vid.support.ext_texture_3d)
+ return;
+ break;
+ case RENDERPATH_GLES2:
+ // for performance reasons, do not use directional shading on GLES devices
+ if (!vid.support.ext_texture_3d)
+ return;
+ break;
+ // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
+ case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GLES1:
+ case RENDERPATH_SOFT:
+ case RENDERPATH_D3D9:
+ case RENDERPATH_D3D10:
+ case RENDERPATH_D3D11:
+ return;
+ }
+
+ r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
+
+ // see if there are really any lights to render...
+ if (enable && r_shadow_bouncegrid_static.integer)
+ {
+ enable = false;
+ range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+ for (lightindex = 0;lightindex < range;lightindex++)
+ {
+ light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (!light || !(light->flags & flag))
+ continue;
+ rtlight = &light->rtlight;
+ // when static, we skip styled lights because they tend to change...
+ if (rtlight->style > 0)
+ continue;
+ VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
+ if (!VectorLength2(lightcolor))
+ continue;
+ enable = true;
+ break;
+ }
+ }
+
+ if (!enable)
{
if (r_shadow_bouncegridtexture)
{
Mem_Free(r_shadow_bouncegridhighpixels);
r_shadow_bouncegridhighpixels = NULL;
r_shadow_bouncegridnumpixels = 0;
+ r_shadow_bouncegriddirectional = false;
return;
}
- if (r_refdef.scene.worldmodel && isstatic)
- {
- VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
- VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
- VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
- VectorSubtract(maxs, mins, size);
- resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
- resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
- resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
- resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
- resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
- resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
- spacing[0] = size[0] / resolution[0];
- spacing[1] = size[1] / resolution[1];
- spacing[2] = size[2] / resolution[2];
- ispacing[0] = 1.0f / spacing[0];
- ispacing[1] = 1.0f / spacing[1];
- ispacing[2] = 1.0f / spacing[2];
+
+ // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
+ memset(&settings, 0, sizeof(settings));
+ settings.staticmode = r_shadow_bouncegrid_static.integer != 0;
+ settings.bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
+ settings.directionalshading = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && allowdirectionalshading;
+ settings.dlightparticlemultiplier = r_shadow_bouncegrid_dlightparticlemultiplier.value;
+ settings.hitmodels = r_shadow_bouncegrid_hitmodels.integer != 0;
+ settings.includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
+ settings.lightradiusscale = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value);
+ settings.maxbounce = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer);
+ settings.particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
+ settings.particleintensity = r_shadow_bouncegrid_particleintensity.value * 16384.0f * (settings.directionalshading ? 4.0f : 1.0f) / (r_shadow_bouncegrid_spacing.value * r_shadow_bouncegrid_spacing.value);
+ settings.photons = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_photons.integer : r_shadow_bouncegrid_photons.integer;
+ settings.spacing[0] = r_shadow_bouncegrid_spacing.value;
+ settings.spacing[1] = r_shadow_bouncegrid_spacing.value;
+ settings.spacing[2] = r_shadow_bouncegrid_spacing.value;
+ settings.stablerandom = r_shadow_bouncegrid_stablerandom.integer;
+
+ // bound the values for sanity
+ settings.photons = bound(1, settings.photons, 1048576);
+ settings.lightradiusscale = bound(0.0001f, settings.lightradiusscale, 1024.0f);
+ settings.maxbounce = bound(0, settings.maxbounce, 16);
+ settings.spacing[0] = bound(1, settings.spacing[0], 512);
+ settings.spacing[1] = bound(1, settings.spacing[1], 512);
+ settings.spacing[2] = bound(1, settings.spacing[2], 512);
+
+ // get the spacing values
+ spacing[0] = settings.spacing[0];
+ spacing[1] = settings.spacing[1];
+ spacing[2] = settings.spacing[2];
+ ispacing[0] = 1.0f / spacing[0];
+ ispacing[1] = 1.0f / spacing[1];
+ ispacing[2] = 1.0f / spacing[2];
+
+ // calculate texture size enclosing entire world bounds at the spacing
+ VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
+ VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
+ VectorSubtract(maxs, mins, size);
+ // now we can calculate the resolution we want
+ c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
+ c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
+ c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
+ // figure out the exact texture size (honoring power of 2 if required)
+ c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
+ c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
+ c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
+ if (vid.support.arb_texture_non_power_of_two)
+ {
+ resolution[0] = c[0];
+ resolution[1] = c[1];
+ resolution[2] = c[2];
}
else
{
- VectorSet(resolution, bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
- VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
- VectorMultiply(resolution, spacing, size);
- ispacing[0] = 1.0f / spacing[0];
- ispacing[1] = 1.0f / spacing[1];
- ispacing[2] = 1.0f / spacing[2];
+ for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
+ for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
+ for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
+ }
+ size[0] = spacing[0] * resolution[0];
+ size[1] = spacing[1] * resolution[1];
+ size[2] = spacing[2] * resolution[2];
+
+ // if dynamic we may or may not want to use the world bounds
+ // if the dynamic size is smaller than the world bounds, use it instead
+ if (!settings.staticmode && (r_shadow_bouncegrid_x.integer * r_shadow_bouncegrid_y.integer * r_shadow_bouncegrid_z.integer < resolution[0] * resolution[1] * resolution[2]))
+ {
+ // we know the resolution we want
+ c[0] = r_shadow_bouncegrid_x.integer;
+ c[1] = r_shadow_bouncegrid_y.integer;
+ c[2] = r_shadow_bouncegrid_z.integer;
+ // now we can calculate the texture size (power of 2 if required)
+ c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
+ c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
+ c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
+ if (vid.support.arb_texture_non_power_of_two)
+ {
+ resolution[0] = c[0];
+ resolution[1] = c[1];
+ resolution[2] = c[2];
+ }
+ else
+ {
+ for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
+ for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
+ for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
+ }
+ size[0] = spacing[0] * resolution[0];
+ size[1] = spacing[1] * resolution[1];
+ size[2] = spacing[2] * resolution[2];
+ // center the rendering on the view
mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
- VectorAdd(mins, size, maxs);
}
- r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
- if (r_shadow_bouncegridtexture && realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value && resolution[0] == r_shadow_bouncegridresolution[0] && resolution[1] == r_shadow_bouncegridresolution[1] && resolution[2] == r_shadow_bouncegridresolution[2])
+
+ // recalculate the maxs in case the resolution was not satisfactory
+ VectorAdd(mins, size, maxs);
+
+ // if all the settings seem identical to the previous update, return
+ if (r_shadow_bouncegridtexture && (settings.staticmode || realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value) && !memcmp(&r_shadow_bouncegridsettings, &settings, sizeof(settings)))
return;
+
+ // store the new settings
+ r_shadow_bouncegridsettings = settings;
+
+ pixelbands = settings.directionalshading ? 8 : 1;
+ pixelsperband = resolution[0]*resolution[1]*resolution[2];
+ numpixels = pixelsperband*pixelbands;
+
// we're going to update the bouncegrid, update the matrix...
memset(m, 0, sizeof(m));
m[0] = 1.0f / size[0];
m[11] = -mins[2] * m[10];
m[15] = 1.0f;
Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
- numpixels = resolution[0]*resolution[1]*resolution[2];
// reallocate pixels for this update if needed...
if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
{
+ if (r_shadow_bouncegridtexture)
+ {
+ R_FreeTexture(r_shadow_bouncegridtexture);
+ r_shadow_bouncegridtexture = NULL;
+ }
r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
- r_shadow_bouncegridhighpixels = (unsigned short *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(unsigned short[4]));
+ r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[4]));
}
r_shadow_bouncegridnumpixels = numpixels;
pixels = r_shadow_bouncegridpixels;
highpixels = r_shadow_bouncegridhighpixels;
- memset(pixels, 0, numpixels * sizeof(unsigned char[4]));
- memset(highpixels, 0, numpixels * sizeof(unsigned short[3]));
+ x = pixelsperband*4;
+ for (pixelband = 0;pixelband < pixelbands;pixelband++)
+ {
+ if (pixelband == 1)
+ memset(pixels + pixelband * x, 128, x);
+ else
+ memset(pixels + pixelband * x, 0, x);
+ }
+ memset(highpixels, 0, numpixels * sizeof(float[4]));
// figure out what we want to interact with
- if (r_shadow_bouncegrid_hitmodels.integer)
- hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
+ if (settings.hitmodels)
+ hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
else
- hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
- maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
+ hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
+ maxbounce = settings.maxbounce;
+ // clear variables that produce warnings otherwise
+ memset(splatcolor, 0, sizeof(splatcolor));
// iterate world rtlights
range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
- range1 = isstatic ? 0 : r_refdef.scene.numlights;
+ range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
range2 = range + range1;
photoncount = 0;
for (lightindex = 0;lightindex < range2;lightindex++)
{
- if (isstatic)
+ if (lightindex < range)
{
light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- if (!light || !(light->flags & flag))
+ if (!light)
continue;
rtlight = &light->rtlight;
- // when static, we skip styled lights because they tend to change...
- if (rtlight->style > 0)
+ VectorClear(rtlight->photoncolor);
+ rtlight->photons = 0;
+ if (!(light->flags & flag))
continue;
- VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
+ if (settings.staticmode)
+ {
+ // when static, we skip styled lights because they tend to change...
+ if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
+ continue;
+ }
}
else
{
- if (lightindex < range)
- {
- light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- rtlight = &light->rtlight;
- }
- else
- rtlight = r_refdef.scene.lights[lightindex - range];
- // draw only visible lights (major speedup)
- if (!rtlight->draw)
- continue;
- VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
+ rtlight = r_refdef.scene.lights[lightindex - range];
+ VectorClear(rtlight->photoncolor);
+ rtlight->photons = 0;
}
- if (!VectorLength2(lightcolor))
+ // draw only visible lights (major speedup)
+ radius = rtlight->radius * settings.lightradiusscale;
+ cullmins[0] = rtlight->shadoworigin[0] - radius;
+ cullmins[1] = rtlight->shadoworigin[1] - radius;
+ cullmins[2] = rtlight->shadoworigin[2] - radius;
+ cullmaxs[0] = rtlight->shadoworigin[0] + radius;
+ cullmaxs[1] = rtlight->shadoworigin[1] + radius;
+ cullmaxs[2] = rtlight->shadoworigin[2] + radius;
+ if (R_CullBox(cullmins, cullmaxs))
+ continue;
+ if (r_refdef.scene.worldmodel
+ && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
+ && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
continue;
+ w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
+ if (w * VectorLength2(rtlight->color) == 0.0f)
+ continue;
+ w *= (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
+ VectorScale(rtlight->color, w, rtlight->photoncolor);
+ //if (!VectorLength2(rtlight->photoncolor))
+ // continue;
// shoot particles from this light
// use a calculation for the number of particles that will not
// vary with lightstyle, otherwise we get randomized particle
// distribution, the seeded random is only consistent for a
// consistent number of particles on this light...
- radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
s = rtlight->radius;
lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
if (lightindex >= range)
- lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
- photoncount += max(0.0f, lightintensity * s * s);
+ lightintensity *= settings.dlightparticlemultiplier;
+ rtlight->photons = max(0.0f, lightintensity * s * s);
+ photoncount += rtlight->photons;
}
- photonscaling = bound(1, r_shadow_bouncegrid_photons.value, 1048576) / max(1, photoncount);
+ photonscaling = (float)settings.photons / max(1, photoncount);
photonresidual = 0.0f;
for (lightindex = 0;lightindex < range2;lightindex++)
{
- if (isstatic)
+ if (lightindex < range)
{
light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- if (!light || !(light->flags & flag))
+ if (!light)
continue;
rtlight = &light->rtlight;
- // when static, we skip styled lights because they tend to change...
- if (rtlight->style > 0)
- continue;
- VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
}
else
- {
- if (lightindex < range)
- {
- light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- rtlight = &light->rtlight;
- }
- else
- rtlight = r_refdef.scene.lights[lightindex - range];
- // draw only visible lights (major speedup)
- if (!rtlight->draw)
- continue;
- VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
- }
- if (!VectorLength2(lightcolor))
+ rtlight = r_refdef.scene.lights[lightindex - range];
+ // skip a light with no photons
+ if (rtlight->photons == 0.0f)
continue;
- // shoot particles from this light
- // use a calculation for the number of particles that will not
- // vary with lightstyle, otherwise we get randomized particle
- // distribution, the seeded random is only consistent for a
- // consistent number of particles on this light...
- radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
- s = rtlight->radius;
- lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
- if (lightindex >= range)
- lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
- photonresidual += lightintensity * s * s * photonscaling;
+ // skip a light with no photon color)
+ if (VectorLength2(rtlight->photoncolor) == 0.0f)
+ continue;
+ photonresidual += rtlight->photons * photonscaling;
shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
if (!shootparticles)
continue;
photonresidual -= shootparticles;
- s = 65535.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
- VectorScale(lightcolor, s, baseshotcolor);
- if (VectorLength2(baseshotcolor) < 3.0f)
- break;
+ radius = rtlight->radius * settings.lightradiusscale;
+ s = settings.particleintensity / shootparticles;
+ VectorScale(rtlight->photoncolor, s, baseshotcolor);
r_refdef.stats.bouncegrid_lights++;
r_refdef.stats.bouncegrid_particles += shootparticles;
for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
{
- if (r_shadow_bouncegrid_stablerandom.integer > 0)
+ if (settings.stablerandom > 0)
seed = lightindex * 11937 + shotparticles;
VectorCopy(baseshotcolor, shotcolor);
VectorCopy(rtlight->shadoworigin, clipstart);
- if (r_shadow_bouncegrid_stablerandom.integer < 0)
+ if (settings.stablerandom < 0)
VectorRandom(clipend);
else
VectorCheeseRandom(clipend);
r_refdef.stats.bouncegrid_traces++;
//r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
//r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
- cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true, true);
- //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
- if (cliptrace.fraction >= 1.0f)
- break;
- r_refdef.stats.bouncegrid_hits++;
- if (bouncecount > 0)
+ //if (settings.staticmode)
+ // Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, true);
+ //else
+ cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, true, false, NULL, true, true);
+ if (bouncecount > 0 || settings.includedirectlighting)
{
- r_refdef.stats.bouncegrid_splats++;
- // figure out which texture pixel this is in
- texlerp[1][0] = (int)(((cliptrace.endpos[0] - mins[0]) * ispacing[0]) * 256.0f);
- texlerp[1][1] = (int)(((cliptrace.endpos[1] - mins[1]) * ispacing[1]) * 256.0f);
- texlerp[1][2] = (int)(((cliptrace.endpos[2] - mins[2]) * ispacing[2]) * 256.0f);
- tex[0] = texlerp[1][0] >> 8;
- tex[1] = texlerp[1][1] >> 8;
- tex[2] = texlerp[1][2] >> 8;
- if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 2 && tex[1] < resolution[1] - 2 && tex[2] < resolution[2] - 2)
+ // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
+ // accumulate average shotcolor
+ w = VectorLength(shotcolor);
+ splatcolor[ 0] = shotcolor[0];
+ splatcolor[ 1] = shotcolor[1];
+ splatcolor[ 2] = shotcolor[2];
+ splatcolor[ 3] = 0.0f;
+ if (pixelbands > 1)
{
- // it is within bounds...
- splatcolor[0] = (int)shotcolor[2];
- splatcolor[1] = (int)shotcolor[1];
- splatcolor[2] = (int)shotcolor[0];
- // calculate the lerp factors
- if (r_shadow_bouncegrid_nolerpsplat.integer)
- {
- pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );
- pixel = pixels + 4 * pixelindex[0];
- highpixel = highpixels + 3 * pixelindex[0];
- // add to the high precision pixel color
- c[0] = highpixel[0] + splatcolor[0];
- c[1] = highpixel[1] + splatcolor[1];
- c[2] = highpixel[2] + splatcolor[2];
- highpixel[0] = (unsigned short)min(c[0], 65535);
- highpixel[1] = (unsigned short)min(c[1], 65535);
- highpixel[2] = (unsigned short)min(c[2], 65535);
- // update the low precision pixel color
- pixel[0] = highpixel[0] >> 8;
- pixel[1] = highpixel[1] >> 8;
- pixel[2] = highpixel[2] >> 8;
- pixel[3] = 255;
- }
- else
+ VectorSubtract(clipstart, cliptrace.endpos, clipdiff);
+ VectorNormalize(clipdiff);
+ // store bentnormal in case the shader has a use for it
+ splatcolor[ 4] = clipdiff[0] * w;
+ splatcolor[ 5] = clipdiff[1] * w;
+ splatcolor[ 6] = clipdiff[2] * w;
+ splatcolor[ 7] = w;
+ // accumulate directional contributions (+X, +Y, +Z, -X, -Y, -Z)
+ splatcolor[ 8] = shotcolor[0] * max(0.0f, clipdiff[0]);
+ splatcolor[ 9] = shotcolor[0] * max(0.0f, clipdiff[1]);
+ splatcolor[10] = shotcolor[0] * max(0.0f, clipdiff[2]);
+ splatcolor[11] = 0.0f;
+ splatcolor[12] = shotcolor[1] * max(0.0f, clipdiff[0]);
+ splatcolor[13] = shotcolor[1] * max(0.0f, clipdiff[1]);
+ splatcolor[14] = shotcolor[1] * max(0.0f, clipdiff[2]);
+ splatcolor[15] = 0.0f;
+ splatcolor[16] = shotcolor[2] * max(0.0f, clipdiff[0]);
+ splatcolor[17] = shotcolor[2] * max(0.0f, clipdiff[1]);
+ splatcolor[18] = shotcolor[2] * max(0.0f, clipdiff[2]);
+ splatcolor[19] = 0.0f;
+ splatcolor[20] = shotcolor[0] * max(0.0f, -clipdiff[0]);
+ splatcolor[21] = shotcolor[0] * max(0.0f, -clipdiff[1]);
+ splatcolor[22] = shotcolor[0] * max(0.0f, -clipdiff[2]);
+ splatcolor[23] = 0.0f;
+ splatcolor[24] = shotcolor[1] * max(0.0f, -clipdiff[0]);
+ splatcolor[25] = shotcolor[1] * max(0.0f, -clipdiff[1]);
+ splatcolor[26] = shotcolor[1] * max(0.0f, -clipdiff[2]);
+ splatcolor[27] = 0.0f;
+ splatcolor[28] = shotcolor[2] * max(0.0f, -clipdiff[0]);
+ splatcolor[29] = shotcolor[2] * max(0.0f, -clipdiff[1]);
+ splatcolor[30] = shotcolor[2] * max(0.0f, -clipdiff[2]);
+ splatcolor[31] = 0.0f;
+ }
+ // calculate the number of steps we need to traverse this distance
+ VectorSubtract(cliptrace.endpos, clipstart, stepdelta);
+ numsteps = (int)(VectorLength(stepdelta) * ispacing[0]);
+ numsteps = bound(1, numsteps, 1024);
+ w = 1.0f / numsteps;
+ VectorScale(stepdelta, w, stepdelta);
+ VectorMA(clipstart, 0.5f, stepdelta, steppos);
+ for (step = 0;step < numsteps;step++)
+ {
+ r_refdef.stats.bouncegrid_splats++;
+ // figure out which texture pixel this is in
+ texlerp[1][0] = ((steppos[0] - mins[0]) * ispacing[0]) - 0.5f;
+ texlerp[1][1] = ((steppos[1] - mins[1]) * ispacing[1]) - 0.5f;
+ texlerp[1][2] = ((steppos[2] - mins[2]) * ispacing[2]) - 0.5f;
+ tex[0] = (int)floor(texlerp[1][0]);
+ tex[1] = (int)floor(texlerp[1][1]);
+ tex[2] = (int)floor(texlerp[1][2]);
+ if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 2 && tex[1] < resolution[1] - 2 && tex[2] < resolution[2] - 2)
{
- texlerp[1][0] &= 0xFF;
- texlerp[1][1] &= 0xFF;
- texlerp[1][2] &= 0xFF;
- texlerp[0][0] = 256 - texlerp[1][0];
- texlerp[0][1] = 256 - texlerp[1][1];
- texlerp[0][2] = 256 - texlerp[1][2];
+ // it is within bounds... do the real work now
+ // calculate the lerp factors
+ texlerp[1][0] -= tex[0];
+ texlerp[1][1] -= tex[1];
+ texlerp[1][2] -= tex[2];
+ texlerp[0][0] = 1.0f - texlerp[1][0];
+ texlerp[0][1] = 1.0f - texlerp[1][1];
+ texlerp[0][2] = 1.0f - texlerp[1][2];
// calculate individual pixel indexes and weights
- pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]) >> 16;
- pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]) >> 16;
- pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]) >> 16;
- pixelindex[3] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[3] = (texlerp[1][0]*texlerp[1][1]*texlerp[0][2]) >> 16;
- pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]) >> 16;
- pixelindex[5] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[5] = (texlerp[1][0]*texlerp[0][1]*texlerp[1][2]) >> 16;
- pixelindex[6] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[6] = (texlerp[0][0]*texlerp[1][1]*texlerp[1][2]) >> 16;
- pixelindex[7] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[7] = (texlerp[1][0]*texlerp[1][1]*texlerp[1][2]) >> 16;
+ pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
+ pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
+ pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
+ pixelindex[3] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[3] = (texlerp[1][0]*texlerp[1][1]*texlerp[0][2]);
+ pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
+ pixelindex[5] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[5] = (texlerp[1][0]*texlerp[0][1]*texlerp[1][2]);
+ pixelindex[6] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[6] = (texlerp[0][0]*texlerp[1][1]*texlerp[1][2]);
+ pixelindex[7] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[7] = (texlerp[1][0]*texlerp[1][1]*texlerp[1][2]);
// update the 8 pixels...
- for (corner = 0;corner < 8;corner++)
+ for (pixelband = 0;pixelband < pixelbands;pixelband++)
{
- pixel = pixels + 4 * pixelindex[corner];
- highpixel = highpixels + 3 * pixelindex[corner];
- // add to the high precision pixel color
- c[0] = highpixel[0] + ((splatcolor[0]*pixelweight[corner])>>8);
- c[1] = highpixel[1] + ((splatcolor[1]*pixelweight[corner])>>8);
- c[2] = highpixel[2] + ((splatcolor[2]*pixelweight[corner])>>8);
- highpixel[0] = (unsigned short)min(c[0], 65535);
- highpixel[1] = (unsigned short)min(c[1], 65535);
- highpixel[2] = (unsigned short)min(c[2], 65535);
- // update the low precision pixel color
- pixel[0] = highpixel[0] >> 8;
- pixel[1] = highpixel[1] >> 8;
- pixel[2] = highpixel[2] >> 8;
- pixel[3] = 255;
+ for (corner = 0;corner < 8;corner++)
+ {
+ // calculate address for pixel
+ w = pixelweight[corner];
+ pixel = pixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
+ highpixel = highpixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
+ // add to the high precision pixel color
+ highpixel[0] += (splatcolor[pixelband*4+0]*w);
+ highpixel[1] += (splatcolor[pixelband*4+1]*w);
+ highpixel[2] += (splatcolor[pixelband*4+2]*w);
+ highpixel[3] += (splatcolor[pixelband*4+3]*w);
+ // flag the low precision pixel as needing to be updated
+ pixel[3] = 255;
+ // advance to next band of coefficients
+ //pixel += pixelsperband*4;
+ //highpixel += pixelsperband*4;
+ }
}
}
+ VectorAdd(steppos, stepdelta, steppos);
}
}
+ if (cliptrace.fraction >= 1.0f)
+ break;
+ r_refdef.stats.bouncegrid_hits++;
if (bouncecount >= maxbounce)
break;
// scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
else
VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
- VectorScale(surfcolor, r_shadow_bouncegrid_particlebounceintensity.value, surfcolor);
+ VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
surfcolor[0] = min(surfcolor[0], 1.0f);
surfcolor[1] = min(surfcolor[1], 1.0f);
surfcolor[2] = min(surfcolor[2], 1.0f);
VectorMultiply(shotcolor, surfcolor, shotcolor);
- if (VectorLength2(shotcolor) < 3.0f)
+ if (VectorLength2(baseshotcolor) == 0.0f)
break;
r_refdef.stats.bouncegrid_bounces++;
- if (r_shadow_bouncegrid_bounceanglediffuse.integer)
+ if (settings.bounceanglediffuse)
{
// random direction, primarily along plane normal
s = VectorDistance(cliptrace.endpos, clipend);
- if (r_shadow_bouncegrid_stablerandom.integer < 0)
+ if (settings.stablerandom < 0)
VectorRandom(clipend);
else
VectorCheeseRandom(clipend);
}
}
}
- if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
- R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
+ // generate pixels array from highpixels array
+ // skip first and last columns, rows, and layers as these are blank
+ // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated
+ for (pixelband = 0;pixelband < pixelbands;pixelband++)
+ {
+ for (z = 1;z < resolution[2]-1;z++)
+ {
+ for (y = 1;y < resolution[1]-1;y++)
+ {
+ for (x = 1, pixelindex[0] = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x, pixel = pixels + 4*pixelindex[0], highpixel = highpixels + 4*pixelindex[0];x < resolution[0]-1;x++, pixel += 4, highpixel += 4)
+ {
+ // only convert pixels that were hit by photons
+ if (pixel[3] == 255)
+ {
+ // normalize the bentnormal...
+ if (pixelband == 1)
+ {
+ VectorNormalize(highpixel);
+ c[0] = (int)(highpixel[0]*128.0f+128.0f);
+ c[1] = (int)(highpixel[1]*128.0f+128.0f);
+ c[2] = (int)(highpixel[2]*128.0f+128.0f);
+ c[3] = (int)(highpixel[3]*128.0f+128.0f);
+ }
+ else
+ {
+ c[0] = (int)(highpixel[0]*256.0f);
+ c[1] = (int)(highpixel[1]*256.0f);
+ c[2] = (int)(highpixel[2]*256.0f);
+ c[3] = (int)(highpixel[3]*256.0f);
+ }
+ pixel[2] = (unsigned char)bound(0, c[0], 255);
+ pixel[1] = (unsigned char)bound(0, c[1], 255);
+ pixel[0] = (unsigned char)bound(0, c[2], 255);
+ pixel[3] = (unsigned char)bound(0, c[3], 255);
+ }
+ }
+ }
+ }
+ }
+ if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2] && r_shadow_bouncegriddirectional == settings.directionalshading)
+ R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
else
{
VectorCopy(resolution, r_shadow_bouncegridresolution);
+ r_shadow_bouncegriddirectional = settings.directionalshading;
if (r_shadow_bouncegridtexture)
R_FreeTexture(r_shadow_bouncegridtexture);
- r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2], pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
+ r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
}
r_shadow_bouncegridtime = realtime;
}
qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
{
- if (!r_shadow_scissor.integer)
+ if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
{
r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
{
// ARB2 GLSL shader path (GFFX5200, Radeon 9500)
- R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
- if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
- GL_DepthFunc(GL_EQUAL);
+ R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
RSurf_DrawBatch();
- if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
- GL_DepthFunc(GL_LEQUAL);
}
static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
if(negated)
{
VectorNegate(lightcolor, lightcolor);
- switch(vid.renderpath)
- {
- case RENDERPATH_GL11:
- case RENDERPATH_GL13:
- case RENDERPATH_GL20:
- case RENDERPATH_GLES2:
- qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
- break;
- case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
- IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
-#endif
- break;
- case RENDERPATH_D3D10:
- Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_D3D11:
- Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_SOFT:
- DPSOFTRAST_BlendSubtract(true);
- break;
- }
+ GL_BlendEquationSubtract(true);
}
RSurf_SetupDepthAndCulling();
switch (r_shadow_rendermode)
break;
}
if(negated)
- {
- switch(vid.renderpath)
- {
- case RENDERPATH_GL11:
- case RENDERPATH_GL13:
- case RENDERPATH_GL20:
- case RENDERPATH_GLES2:
- qglBlendEquationEXT(GL_FUNC_ADD_EXT);
- break;
- case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
- IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
-#endif
- break;
- case RENDERPATH_D3D10:
- Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_D3D11:
- Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_SOFT:
- DPSOFTRAST_BlendSubtract(false);
- break;
- }
- }
+ GL_BlendEquationSubtract(false);
}
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)
// can hold
rtlight->cached_numfrustumplanes = 0;
+ if (r_trippy.integer)
+ return;
+
// haven't implemented a culling path for ortho rendering
if (!r_refdef.view.useperspective)
{
if (r_refdef.scene.lights[lnum]->draw)
R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
- R_Mesh_ResetRenderTargets();
+ R_Mesh_SetMainRenderTargets();
R_Shadow_RenderMode_End();
}
}
break;
- case RENDERPATH_GL13:
case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GLES1:
r_shadow_usingdeferredprepass = false;
break;
}
R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
- if (r_shadow_debuglight.integer >= 0)
+ if (r_shadow_bouncegrid.integer != 2)
{
- lightindex = r_shadow_debuglight.integer;
- light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- if (light && (light->flags & flag))
- R_Shadow_PrepareLight(&light->rtlight);
- }
- else
- {
- range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
- for (lightindex = 0;lightindex < range;lightindex++)
+ if (r_shadow_debuglight.integer >= 0)
{
+ lightindex = r_shadow_debuglight.integer;
light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- if (light && (light->flags & flag))
+ if (light)
R_Shadow_PrepareLight(&light->rtlight);
}
+ else
+ {
+ range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+ for (lightindex = 0;lightindex < range;lightindex++)
+ {
+ light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (light && (light->flags & flag))
+ R_Shadow_PrepareLight(&light->rtlight);
+ }
+ }
}
if (r_refdef.scene.rtdlight)
{
if (r_editlights.integer)
R_Shadow_DrawLightSprites();
-
- R_Shadow_UpdateBounceGridTexture();
}
void R_Shadow_DrawLights(void)
R_Shadow_RenderMode_Begin();
- flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
- if (r_shadow_debuglight.integer >= 0)
- {
- lightindex = r_shadow_debuglight.integer;
- light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- if (light && (light->flags & flag))
- R_Shadow_DrawLight(&light->rtlight);
- }
- else
+ if (r_shadow_bouncegrid.integer != 2)
{
- range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
- for (lightindex = 0;lightindex < range;lightindex++)
+ flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+ if (r_shadow_debuglight.integer >= 0)
{
+ lightindex = r_shadow_debuglight.integer;
light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- if (light && (light->flags & flag))
+ if (light)
R_Shadow_DrawLight(&light->rtlight);
}
+ else
+ {
+ range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+ for (lightindex = 0;lightindex < range;lightindex++)
+ {
+ light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (light && (light->flags & flag))
+ R_Shadow_DrawLight(&light->rtlight);
+ }
+ }
}
if (r_refdef.scene.rtdlight)
for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
- R_SetupShader_DepthOrShadow();
+ R_SetupShader_DepthOrShadow(true);
GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
GL_DepthMask(true);
GL_DepthTest(true);
#if 0
// debugging
- R_Mesh_ResetRenderTargets();
- R_SetupShader_ShowDepth();
+ R_Mesh_SetMainRenderTargets();
+ R_SetupShader_ShowDepth(true);
GL_ColorMask(1,1,1,1);
GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
#endif
case RENDERPATH_GL13:
case RENDERPATH_GL20:
case RENDERPATH_SOFT:
+ case RENDERPATH_GLES1:
case RENDERPATH_GLES2:
break;
case RENDERPATH_D3D9:
// apply the blend to the shadowed areas
R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+ R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, true);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
// restore the viewport
switch(vid.renderpath)
{
- case RENDERPATH_GL20:
- case RENDERPATH_GL13:
case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL20:
+ case RENDERPATH_GLES1:
case RENDERPATH_GLES2:
CHECKGLERROR
// NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
{
switch(vid.renderpath)
{
- case RENDERPATH_GL20:
- case RENDERPATH_GL13:
case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL20:
+ case RENDERPATH_GLES1:
case RENDERPATH_GLES2:
CHECKGLERROR
qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
if(negated)
{
VectorNegate(color, color);
- switch(vid.renderpath)
- {
- case RENDERPATH_GL11:
- case RENDERPATH_GL13:
- case RENDERPATH_GL20:
- case RENDERPATH_GLES2:
- qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
- break;
- case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
- IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
-#endif
- break;
- case RENDERPATH_D3D10:
- Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_D3D11:
- Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_SOFT:
- DPSOFTRAST_BlendSubtract(true);
- break;
- }
+ GL_BlendEquationSubtract(true);
}
R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
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);
R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
if(negated)
- {
- switch(vid.renderpath)
- {
- case RENDERPATH_GL11:
- case RENDERPATH_GL13:
- case RENDERPATH_GL20:
- case RENDERPATH_GLES2:
- qglBlendEquationEXT(GL_FUNC_ADD_EXT);
- break;
- case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
- IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
-#endif
- break;
- case RENDERPATH_D3D10:
- Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_D3D11:
- Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_SOFT:
- DPSOFTRAST_BlendSubtract(false);
- break;
- }
- }
+ GL_BlendEquationSubtract(false);
}
}
case RENDERPATH_GL11:
case RENDERPATH_GL13:
case RENDERPATH_GL20:
+ case RENDERPATH_GLES1:
case RENDERPATH_GLES2:
usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
if (usequery)
GL_PolygonOffset(0, 0);
GL_DepthTest(true);
R_Mesh_ResetTextureState();
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+ R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
}
break;
case RENDERPATH_D3D9:
origin[1] = atof(Cmd_Argv(3));
origin[2] = atof(Cmd_Argv(4));
}
+ else if (!strcmp(Cmd_Argv(1), "originscale"))
+ {
+ if (Cmd_Argc() != 5)
+ {
+ Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
+ return;
+ }
+ origin[0] *= atof(Cmd_Argv(2));
+ origin[1] *= atof(Cmd_Argv(3));
+ origin[2] *= atof(Cmd_Argv(4));
+ }
else if (!strcmp(Cmd_Argv(1), "originx"))
{
if (Cmd_Argc() != 3)
"colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
"radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
"sizescale scale : multiply radius (size) of light (1 does nothing)\n"
+"originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
"style style : set lightstyle of light (flickering patterns, switches, etc)\n"
"cubemap basename : set filter cubemap of light (not yet supported)\n"
"shadows 1/0 : turn on/off shadows\n"
=============================================================================
*/
+void R_LightPoint(vec3_t color, const vec3_t p, const int flags)
+{
+ int i, numlights, flag;
+ float f, relativepoint[3], dist, dist2, lightradius2;
+ vec3_t diffuse, n;
+ rtlight_t *light;
+ dlight_t *dlight;
+
+ if (r_fullbright.integer)
+ {
+ VectorSet(color, 1, 1, 1);
+ return;
+ }
+
+ VectorClear(color);
+
+ if (flags & LP_LIGHTMAP)
+ {
+ if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
+ {
+ VectorClear(diffuse);
+ r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
+ VectorAdd(color, diffuse, color);
+ }
+ else
+ VectorSet(color, 1, 1, 1);
+ color[0] += r_refdef.scene.ambient;
+ color[1] += r_refdef.scene.ambient;
+ color[2] += r_refdef.scene.ambient;
+ }
+
+ if (flags & LP_RTWORLD)
+ {
+ flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+ numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
+ for (i = 0; i < numlights; i++)
+ {
+ dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
+ if (!dlight)
+ continue;
+ light = &dlight->rtlight;
+ if (!(light->flags & flag))
+ continue;
+ // sample
+ lightradius2 = light->radius * light->radius;
+ VectorSubtract(light->shadoworigin, p, relativepoint);
+ dist2 = VectorLength2(relativepoint);
+ if (dist2 >= lightradius2)
+ continue;
+ dist = sqrt(dist2) / light->radius;
+ f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
+ if (f <= 0)
+ continue;
+ // todo: add to both ambient and diffuse
+ if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
+ VectorMA(color, f, light->currentcolor, color);
+ }
+ }
+ if (flags & LP_DYNLIGHT)
+ {
+ // sample dlights
+ for (i = 0;i < r_refdef.scene.numlights;i++)
+ {
+ light = r_refdef.scene.lights[i];
+ // sample
+ lightradius2 = light->radius * light->radius;
+ VectorSubtract(light->shadoworigin, p, relativepoint);
+ dist2 = VectorLength2(relativepoint);
+ if (dist2 >= lightradius2)
+ continue;
+ dist = sqrt(dist2) / light->radius;
+ f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
+ if (f <= 0)
+ continue;
+ // todo: add to both ambient and diffuse
+ if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
+ VectorMA(color, f, light->color, color);
+ }
+ }
+}
+
void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
{
int i, numlights, flag;
return;
}
- if (flags & LP_LIGHTMAP)
+ if (flags == LP_LIGHTMAP)
{
VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
VectorClear(diffuse);
VectorClear(lightdir);
- if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
+ if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
+ else
+ VectorSet(ambient, 1, 1, 1);
return;
}
memset(sample, 0, sizeof(sample));
VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
- if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
+ if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
{
vec3_t tempambient;
VectorClear(tempambient);
intensity *= VectorLength(color);
VectorMA(sample + 12, intensity, relativepoint, sample + 12);
}
+ // FIXME: sample bouncegrid too!
}
if (flags & LP_DYNLIGHT)