#include "cl_collision.h"
#include "portals.h"
#include "image.h"
+#include "dpsoftrast.h"
#ifdef SUPPORTD3D
#include <d3d9.h>
int r_shadow_shadowmaplod; // changes for each light based on distance
GLuint r_shadow_prepassgeometryfbo;
-GLuint r_shadow_prepasslightingfbo;
+GLuint r_shadow_prepasslightingdiffusespecularfbo;
+GLuint r_shadow_prepasslightingdiffusefbo;
int r_shadow_prepass_width;
int r_shadow_prepass_height;
rtexture_t *r_shadow_prepassgeometrydepthtexture;
cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
-cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
+cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
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_particletrace = {CVAR_SAVE, "r_shadow_particletrace", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity), requires r_shadow_deferred 1, requires r_shadow_realtime_world 1, EXTREMELY SLOW"};
+cvar_t r_shadow_particletrace_intensity = {CVAR_SAVE, "r_shadow_particletrace_intensity", "128", "overall brightness of particle traced radiosity"};
+cvar_t r_shadow_particletrace_size = {CVAR_SAVE, "r_shadow_particletrace_size", "32", "particles produce bounce lights of this radius"};
+cvar_t r_shadow_particletrace_radiusscale = {CVAR_SAVE, "r_shadow_particletrace_radiusscale", "1", "particles stop at this fraction of light radius"};
+cvar_t r_shadow_particletrace_maxbounce = {CVAR_SAVE, "r_shadow_particletrace_maxbounce", "1", "maximum number of bounces for a particle (minimum is 1)"};
+cvar_t r_shadow_particletrace_bounceintensity = {CVAR_SAVE, "r_shadow_particletrace_bounceintensity", "1", "amount of energy carried over after each bounce"};
+cvar_t r_shadow_particletrace_particlespacing = {CVAR_SAVE, "r_shadow_particletrace_particlespacing", "0.25", "overlap setting in terms of particle size, this affects how many particles are used"};
+cvar_t r_shadow_particletrace_updatepercentage = {CVAR_SAVE, "r_shadow_particletrace_updatepercentage", "0.01", "update this fraction of the particles of a light each frame (0 = best performance)"};
+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_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_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_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "1", "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_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "amount of energy carried over after each bounce"};
+cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "4", "brightness of particles contributing to bouncegrid texture"};
+cvar_t r_shadow_bouncegrid_particlespacing = {CVAR_SAVE, "r_shadow_bouncegrid_particlespacing", "32", "emit one particle per this many units (squared) of radius (squared)"};
+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_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
+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_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"};
cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
-cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
+cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
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"};
+rtexture_t *r_shadow_bouncegridtexture;
+matrix4x4_t r_shadow_bouncegridmatrix;
+vec_t r_shadow_bouncegridintensity;
+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;
+
// 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
// 1D gradient, 2D circle and 3D sphere attenuation textures
}
}
r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
- // Cg has very little choice in depth texture sampling
- if (vid.cgcontext)
- r_shadow_shadowmapsampler = false;
break;
- case RENDERPATH_CGGL:
case RENDERPATH_D3D9:
case RENDERPATH_D3D10:
case RENDERPATH_D3D11:
+ case RENDERPATH_SOFT:
r_shadow_shadowmapsampler = false;
r_shadow_shadowmappcf = 1;
r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
break;
case RENDERPATH_GL11:
break;
+ case RENDERPATH_GLES2:
+ break;
}
}
}
void r_shadow_start(void)
{
// allocate vertex processing arrays
+ r_shadow_bouncegridpixels = NULL;
+ r_shadow_bouncegridhighpixels = NULL;
+ r_shadow_bouncegridnumpixels = 0;
+ r_shadow_bouncegridtexture = NULL;
r_shadow_attenuationgradienttexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_attenuation3dtexture = NULL;
r_shadow_prepass_width = r_shadow_prepass_height = 0;
CHECKGLERROR
+ r_shadow_bouncegridtexture = NULL;
+ r_shadow_bouncegridpixels = NULL;
+ r_shadow_bouncegridhighpixels = NULL;
+ r_shadow_bouncegridnumpixels = 0;
r_shadow_attenuationgradienttexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_attenuation3dtexture = NULL;
void r_shadow_newmap(void)
{
+ if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
Cvar_RegisterVariable(&r_shadow_polygonfactor);
Cvar_RegisterVariable(&r_shadow_polygonoffset);
Cvar_RegisterVariable(&r_shadow_texture3d);
+ Cvar_RegisterVariable(&r_shadow_particletrace);
+ Cvar_RegisterVariable(&r_shadow_particletrace_intensity);
+ Cvar_RegisterVariable(&r_shadow_particletrace_size);
+ Cvar_RegisterVariable(&r_shadow_particletrace_radiusscale);
+ Cvar_RegisterVariable(&r_shadow_particletrace_maxbounce);
+ Cvar_RegisterVariable(&r_shadow_particletrace_bounceintensity);
+ Cvar_RegisterVariable(&r_shadow_particletrace_particlespacing);
+ Cvar_RegisterVariable(&r_shadow_particletrace_updatepercentage);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_particlespacing);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
Cvar_RegisterVariable(&r_coronas);
Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
Cvar_RegisterVariable(&r_coronas_occlusionquery);
Cvar_RegisterVariable(&gl_flashblend);
Cvar_RegisterVariable(&gl_ext_separatestencil);
Cvar_RegisterVariable(&gl_ext_stenciltwoside);
- if (gamemode == GAME_TENEBRAE)
- {
- Cvar_SetValue("r_shadow_gloss", 2);
- Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
- }
R_Shadow_EditLights_Init();
Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
maxshadowtriangles = 0;
else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
{
tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
- R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
+ R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
}
else
GL_CullFace(r_refdef.view.cullface_back);
R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
}
- R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
+ R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
}
}
Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
}
-//static const r_vertexposition_t resetvertexposition[3] = {{0, 0, 0}};
-
void R_Shadow_RenderMode_Begin(void)
{
#if 0
CHECKGLERROR
R_Mesh_ResetTextureState();
-// R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_DepthRange(0, 1);
GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
switch(vid.renderpath)
{
case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
case RENDERPATH_D3D9:
case RENDERPATH_D3D10:
case RENDERPATH_D3D11:
+ case RENDERPATH_SOFT:
+ case RENDERPATH_GLES2:
r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
break;
case RENDERPATH_GL13:
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();
-// R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
GL_DepthRange(0, 1);
GL_DepthTest(true);
GL_DepthMask(false);
case RENDERPATH_GL11:
case RENDERPATH_GL13:
case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
+ case RENDERPATH_SOFT:
+ 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
if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
break;
case RENDERPATH_D3D9:
+ case RENDERPATH_D3D10:
+ case RENDERPATH_D3D11:
Vector4Set(clearcolor, 1,1,1,1);
// completely different meaning than in OpenGL path
r_shadow_shadowmap_parameters[1] = 0;
GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
}
break;
- case RENDERPATH_D3D10:
- case RENDERPATH_D3D11:
- // D3D considers it an error to use a scissor larger than the viewport... clear just this view
- GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
- GL_ColorMask(0,0,0,0);
- if (clear)
- GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
- break;
}
}
// 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_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+ R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
r_shadow_usingshadowmap2d = shadowmapping;
GL_DepthTest(true);
GL_DepthFunc(GL_GREATER);
GL_CullFace(r_refdef.view.cullface_back);
- R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
+ R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
}
+static 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;
+ int pixelindex;
+ int resolution[3];
+ int shootparticles;
+ int shotparticles;
+ int tex[3];
+ trace_t cliptrace;
+ unsigned char *pixel;
+ unsigned char *pixels;
+ unsigned short *highpixel;
+ unsigned short *highpixels;
+ unsigned int lightindex;
+ unsigned int range;
+ unsigned int range1;
+ unsigned int range2;
+ unsigned int seed = (unsigned int)(realtime * 1000.0f);
+ vec3_t shotcolor;
+ vec3_t baseshotcolor;
+ vec3_t clipend;
+ vec3_t clipstart;
+ vec3_t clipdiff;
+ vec3_t ispacing;
+ vec3_t maxs;
+ vec3_t mins;
+ vec3_t size;
+ vec3_t spacing;
+ vec3_t lightcolor;
+ vec_t radius;
+ vec_t s;
+ vec_t lightintensity;
+ float m[16];
+ qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
+ rtlight_t *rtlight;
+ if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
+ {
+ if (r_shadow_bouncegridtexture)
+ {
+ R_FreeTexture(r_shadow_bouncegridtexture);
+ r_shadow_bouncegridtexture = NULL;
+ }
+ if (r_shadow_bouncegridpixels)
+ Mem_Free(r_shadow_bouncegridpixels);
+ r_shadow_bouncegridpixels = NULL;
+ if (r_shadow_bouncegridhighpixels)
+ Mem_Free(r_shadow_bouncegridhighpixels);
+ r_shadow_bouncegridhighpixels = NULL;
+ r_shadow_bouncegridnumpixels = 0;
+ 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];
+ }
+ 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];
+ 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])
+ return;
+ // we're going to update the bouncegrid, update the matrix...
+ memset(m, 0, sizeof(m));
+ m[0] = 1.0f / size[0];
+ m[3] = -mins[0] * m[0];
+ m[5] = 1.0f / size[1];
+ m[7] = -mins[1] * m[5];
+ m[10] = 1.0f / size[2];
+ 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)
+ {
+ 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_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]));
+ // figure out what we want to interact with
+ if (r_shadow_bouncegrid_hitmodels.integer)
+ hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
+ else
+ hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
+ maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
+ // iterate world rtlights
+ range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+ range1 = isstatic ? 0 : r_refdef.scene.numlights;
+ range2 = range + range1;
+ for (lightindex = 0;lightindex < range2;lightindex++)
+ {
+ if (isstatic)
+ {
+ 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) * (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))
+ 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 / bound(1.0f, r_shadow_bouncegrid_particlespacing.value, 1048576.0f);
+ lightintensity = VectorLength(rtlight->color) * rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale;
+ if (lightindex >= range)
+ lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
+ shootparticles = (int)bound(0, lightintensity * s *s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
+ if (!shootparticles)
+ continue;
+ s = 65535.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
+ VectorScale(lightcolor, s, baseshotcolor);
+ if (VectorLength2(baseshotcolor) < 3.0f)
+ break;
+ r_refdef.stats.bouncegrid_lights++;
+ r_refdef.stats.bouncegrid_particles += shootparticles;
+ for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
+ {
+ if (r_shadow_bouncegrid_stablerandom.integer > 0)
+ seed = lightindex * 11937 + shotparticles;
+ VectorCopy(baseshotcolor, shotcolor);
+ VectorCopy(rtlight->shadoworigin, clipstart);
+ if (r_shadow_bouncegrid_stablerandom.integer < 0)
+ VectorRandom(clipend);
+ else
+ VectorCheeseRandom(clipend);
+ VectorMA(clipstart, radius, clipend, clipend);
+ for (bouncecount = 0;;bouncecount++)
+ {
+ r_refdef.stats.bouncegrid_traces++;
+ cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
+ //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
+ if (cliptrace.fraction >= 1.0f)
+ break;
+ r_refdef.stats.bouncegrid_hits++;
+ if (bouncecount > 0)
+ {
+ r_refdef.stats.bouncegrid_splats++;
+ // figure out which texture pixel this is in
+ tex[0] = (int)((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
+ tex[1] = (int)((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
+ tex[2] = (int)((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
+ if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 1 && tex[1] < resolution[1] - 1 && tex[2] < resolution[2] - 1)
+ {
+ // it is within bounds...
+ pixelindex = ((tex[2]*resolution[1]+tex[1])*resolution[0]+tex[0]);
+ pixel = pixels + 4 * pixelindex;
+ highpixel = highpixels + 3 * pixelindex;
+ // add to the high precision pixel color
+ c[0] = highpixel[0] + (int)shotcolor[2];
+ c[1] = highpixel[1] + (int)shotcolor[1];
+ c[2] = highpixel[2] + (int)shotcolor[0];
+ 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;
+ }
+ }
+ if (bouncecount >= maxbounce)
+ break;
+ // scale down shot color by bounce intensity and texture color
+ VectorScale(shotcolor, r_shadow_bouncegrid_particlebounceintensity.value, shotcolor);
+ if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
+ VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
+ if (VectorLength2(shotcolor) < 3.0f)
+ break;
+ r_refdef.stats.bouncegrid_bounces++;
+ if (r_shadow_bouncegrid_bounceanglediffuse.integer)
+ {
+ // random direction, primarily along plane normal
+ s = VectorDistance(cliptrace.endpos, clipend);
+ if (r_shadow_bouncegrid_stablerandom.integer < 0)
+ VectorRandom(clipend);
+ else
+ VectorCheeseRandom(clipend);
+ VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
+ VectorNormalize(clipend);
+ VectorScale(clipend, s, clipend);
+ }
+ else
+ {
+ // reflect the remaining portion of the line across plane normal
+ VectorSubtract(clipend, cliptrace.endpos, clipdiff);
+ VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
+ }
+ // calculate the new line start and end
+ VectorCopy(cliptrace.endpos, clipstart);
+ VectorAdd(clipstart, clipend, 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]);
+ else
+ {
+ VectorCopy(resolution, r_shadow_bouncegridresolution);
+ 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_bouncegridtime = realtime;
+}
+
+#define MAXPARTICLESPERLIGHT 262144
+#define MAXLIGHTSPERDRAW 1024
+
+static void R_Shadow_RenderParticlesForLight(rtlight_t *rtlight)
+{
+ int batchcount;
+ int i;
+ int j;
+ int bouncecount;
+ int hitsupercontentsmask;
+ int n;
+ int shotparticles;
+ int shootparticles = 0;
+ int bouncelimit;
+ int maxbounce;
+ unsigned int seed = 0;
+ static unsigned short bouncelight_elements[MAXLIGHTSPERDRAW*36];
+ static float vertex3f[MAXLIGHTSPERDRAW*24];
+ static float lightorigin4f[MAXLIGHTSPERDRAW*32];
+ static float color4f[MAXLIGHTSPERDRAW*32];
+ float scaledpoints[8][3];
+ float *v3f;
+ float *lo4f;
+ float *c4f;
+ rtlight_particle_t *p;
+ vec_t wantparticles = 0;
+ vec_t s;
+ vec_t radius;
+ vec_t particlesize;
+ vec_t iparticlesize;
+// vec3_t offset;
+// vec3_t right;
+// vec3_t up;
+ vec4_t org;
+ vec4_t color;
+ vec3_t currentcolor;
+ vec3_t clipstart;
+ vec3_t clipend;
+ vec3_t shotcolor;
+ trace_t cliptrace;
+ if (!rtlight->draw || !rtlight->isstatic || !r_shadow_usingdeferredprepass)
+ return;
+ if (r_shadow_particletrace.integer)
+ {
+ radius = rtlight->radius * bound(0.0001f, r_shadow_particletrace_radiusscale.value, 1.0f) - r_shadow_particletrace_size.value;
+ s = rtlight->radius / bound(1.0f, r_shadow_particletrace_particlespacing.value * r_shadow_particletrace_size.value, 1048576.0f);
+ wantparticles = s*s;
+ n = (int)bound(0, wantparticles, MAXPARTICLESPERLIGHT);
+ }
+ else
+ n = 0;
+ shootparticles = (int)(n * r_shadow_particletrace_updatepercentage.value);
+ if ((n && !rtlight->particlecache_particles) || rtlight->particlecache_maxparticles != n)
+ {
+ if (rtlight->particlecache_particles)
+ Mem_Free(rtlight->particlecache_particles);
+ rtlight->particlecache_particles = NULL;
+ rtlight->particlecache_numparticles = 0;
+ rtlight->particlecache_maxparticles = n;
+ rtlight->particlecache_updateparticle = 0;
+ if (rtlight->particlecache_maxparticles)
+ rtlight->particlecache_particles = (rtlight_particle_t *)Mem_Alloc(r_main_mempool, rtlight->particlecache_maxparticles * sizeof(*rtlight->particlecache_particles));
+ shootparticles = n * 16;
+ }
+
+ if (!rtlight->particlecache_maxparticles)
+ return;
+
+// if (rtlight->particlecache_numparticles < rtlight->particlecache_maxparticles)
+// shootparticles = rtlight->particlecache_maxparticles;
+
+// if (rtlight->particlecache_numparticles >= rtlight->particlecache_maxparticles)
+// shootparticles = 0;
+
+ maxbounce = bound(1, r_shadow_particletrace_maxbounce.integer, 16);
+ //r_refdef.stats.lights_bouncelightsupdated += shootparticles;
+ for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
+ {
+ seed = rtlight->particlecache_updateparticle;
+ VectorSet(shotcolor, 1.0f, 1.0f, 1.0f);
+ VectorCopy(rtlight->shadoworigin, clipstart);
+ VectorRandom(clipend);
+ VectorMA(clipstart, radius, clipend, clipend);
+ hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
+ bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
+ for (bouncecount = 0;;bouncecount++)
+ {
+ cliptrace = CL_TraceLine(clipstart, clipend, MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
+ //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
+ if (cliptrace.fraction >= 1.0f)
+ break;
+ if (VectorLength2(shotcolor) < (1.0f / 262144.0f))
+ break;
+ if (bouncecount >= bouncelimit)
+ {
+ VectorCopy(cliptrace.endpos, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].origin);
+ VectorCopy(shotcolor, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].color);
+ rtlight->particlecache_updateparticle++;
+ if (rtlight->particlecache_numparticles < rtlight->particlecache_updateparticle)
+ rtlight->particlecache_numparticles = rtlight->particlecache_updateparticle;
+ if (rtlight->particlecache_updateparticle >= rtlight->particlecache_maxparticles)
+ {
+ rtlight->particlecache_updateparticle = 0;
+ shotparticles = shootparticles;
+ }
+ break;
+ }
+ // scale down shot color by bounce intensity and texture color
+ VectorScale(shotcolor, r_shadow_particletrace_bounceintensity.value, shotcolor);
+ if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
+ VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
+ // reflect the remaining portion of the line across plane normal
+ //VectorSubtract(clipend, cliptrace.endpos, clipdiff);
+ //VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
+ // random direction, primarily along plane normal
+ s = VectorDistance(cliptrace.endpos, clipend);
+ VectorRandom(clipend);
+ VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
+ VectorNormalize(clipend);
+ VectorScale(clipend, s, clipend);
+ // calculate the new line start and end
+ VectorCopy(cliptrace.endpos, clipstart);
+ VectorAdd(clipstart, clipend, clipend);
+ }
+ }
+
+ if (!rtlight->particlecache_numparticles)
+ return;
+
+ // render the particles as deferred lights
+// do global setup needed for the chosen lighting mode
+ R_Shadow_RenderMode_Reset();
+ r_shadow_rendermode = r_shadow_lightingrendermode;
+ r_shadow_usingshadowmap2d = false;
+ R_EntityMatrix(&identitymatrix);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ // only draw light where this geometry was already rendered AND the
+ // stencil is 128 (values other than this mean shadow)
+ R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
+ R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
+ R_SetupShader_DeferredBounceLight();
+ GL_ColorMask(1,1,1,1);
+ GL_DepthMask(false);
+ GL_DepthRange(0, 1);
+ GL_PolygonOffset(0, 0);
+ GL_DepthTest(true);
+ GL_DepthFunc(GL_GREATER);
+ GL_CullFace(r_refdef.view.cullface_back);
+ s = r_shadow_particletrace_intensity.value / (float)rtlight->particlecache_numparticles;
+ VectorScale(rtlight->currentcolor, s, currentcolor);
+ particlesize = bound(0.0001f, r_shadow_particletrace_size.value, 1024.0f);
+ iparticlesize = 1.0f / particlesize;
+// VectorScale(r_refdef.view.forward, particlesize, offset);
+// VectorScale(r_refdef.view.left, -particlesize, right);
+// VectorScale(r_refdef.view.up, particlesize, up);
+ org[3] = iparticlesize;
+ color[3] = 1.0f;
+ v3f = vertex3f;
+ lo4f = lightorigin4f;
+ c4f = color4f;
+ batchcount = 0;
+ if (!bouncelight_elements[1])
+ for (i = 0;i < MAXLIGHTSPERDRAW;i++)
+ for (j = 0;j < 36;j++)
+ bouncelight_elements[i*36+j] = i*8+bboxelements[j];
+ for (j = 0;j < 8;j++)
+ VectorScale(bboxpoints[j], particlesize, scaledpoints[j]);
+ //r_refdef.stats.lights_bouncelightscounted += rtlight->particlecache_numparticles;
+ for (j = 0, p = rtlight->particlecache_particles, n = rtlight->particlecache_numparticles;j < n;j++, p++)
+ {
+ VectorCopy(p->origin, org);
+ // org[3] is set above
+ VectorMultiply(p->color, currentcolor, color);
+ // color[3] is set above
+ VectorAdd(scaledpoints[0], org, v3f + 0);
+ VectorAdd(scaledpoints[1], org, v3f + 3);
+ VectorAdd(scaledpoints[2], org, v3f + 6);
+ VectorAdd(scaledpoints[3], org, v3f + 9);
+ VectorAdd(scaledpoints[4], org, v3f + 12);
+ VectorAdd(scaledpoints[5], org, v3f + 15);
+ VectorAdd(scaledpoints[6], org, v3f + 18);
+ VectorAdd(scaledpoints[7], org, v3f + 21);
+ Vector4Copy(org, lo4f + 0);
+ Vector4Copy(org, lo4f + 4);
+ Vector4Copy(org, lo4f + 8);
+ Vector4Copy(org, lo4f + 12);
+ Vector4Copy(org, lo4f + 16);
+ Vector4Copy(org, lo4f + 20);
+ Vector4Copy(org, lo4f + 24);
+ Vector4Copy(org, lo4f + 28);
+ Vector4Copy(color, c4f + 0);
+ Vector4Copy(color, c4f + 4);
+ Vector4Copy(color, c4f + 8);
+ Vector4Copy(color, c4f + 12);
+ Vector4Copy(color, c4f + 16);
+ Vector4Copy(color, c4f + 20);
+ Vector4Copy(color, c4f + 24);
+ Vector4Copy(color, c4f + 28);
+ v3f += 24;
+ lo4f += 32;
+ c4f += 32;
+ batchcount++;
+ if (batchcount >= MAXLIGHTSPERDRAW)
+ {
+ //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
+ R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
+ R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
+ v3f = vertex3f;
+ lo4f = lightorigin4f;
+ c4f = color4f;
+ batchcount = 0;
+ }
+ }
+ if (batchcount)
+ {
+ //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
+ R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
+ R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
+ v3f = vertex3f;
+ lo4f = lightorigin4f;
+ c4f = color4f;
+ batchcount = 0;
+ }
+}
+
void R_Shadow_RenderMode_VisibleShadowVolumes(void)
{
R_Shadow_RenderMode_Reset();
case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
if (VectorLength2(diffusecolor) > 0)
{
- for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
+ for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
{
Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
}
else
{
- for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
+ for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
{
VectorCopy(ambientcolor, color4f);
if (r_refdef.fogenabled)
case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
if (VectorLength2(diffusecolor) > 0)
{
- for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
+ for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
{
Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
}
else
{
- for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
+ for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
{
Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
if (VectorLength2(diffusecolor) > 0)
{
- for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
+ for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
{
Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
}
else
{
- for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
+ for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
{
Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
// renders them at once
for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
{
- if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
+ if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
{
if (newnumtriangles)
{
// handling of negative colors
// (some old drivers even have improper handling of >1 color)
stop = true;
- for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
+ for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
{
if (c[0] > 1 || c[1] > 1 || c[2] > 1)
{
diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
- RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
+ RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
+ rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
- R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
+ R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
R_Mesh_TexBind(0, basetexture);
R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
case RENDERPATH_GL11:
case RENDERPATH_GL13:
case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
+ case RENDERPATH_GLES2:
qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
break;
case RENDERPATH_D3D9:
case RENDERPATH_D3D11:
Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
break;
+ case RENDERPATH_SOFT:
+ DPSOFTRAST_BlendSubtract(true);
+ break;
}
}
RSurf_SetupDepthAndCulling();
case RENDERPATH_GL11:
case RENDERPATH_GL13:
case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
+ case RENDERPATH_GLES2:
qglBlendEquationEXT(GL_FUNC_ADD_EXT);
break;
case RENDERPATH_D3D9:
case RENDERPATH_D3D11:
Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
break;
+ case RENDERPATH_SOFT:
+ DPSOFTRAST_BlendSubtract(false);
+ break;
}
}
}
{
// this variable must be set for the CompileShadowVolume/CompileShadowMap code
r_shadow_compilingrtlight = rtlight;
+ R_FrameData_SetMark();
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);
+ R_FrameData_ReturnToMark();
numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
if (rtlight->static_numlighttrispvsbytes)
memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
+ R_FrameData_SetMark();
switch (rtlight->shadowmode)
{
case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
break;
}
+ R_FrameData_ReturnToMark();
// now we're done compiling the rtlight
r_shadow_compilingrtlight = NULL;
}
{
CHECKGLERROR
GL_CullFace(GL_NONE);
- mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
- for (;mesh;mesh = mesh->next)
- {
+ mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
+ for (;mesh;mesh = mesh->next)
+ {
if (!mesh->sidetotals[r_shadow_shadowmapside])
continue;
- r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
- R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
- 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);
- }
- CHECKGLERROR
- }
+ r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
+ if (mesh->vertex3fbuffer)
+ R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
+ else
+ R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
+ 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);
+ }
+ CHECKGLERROR
+ }
else if (r_refdef.scene.worldentity->model)
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);
for (;mesh;mesh = mesh->next)
{
r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
- R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
+ if (mesh->vertex3fbuffer)
+ R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
+ else
+ R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
{
// increment stencil if frontface is infront of depthbuffer
{
// set up properties for rendering light onto this entity
RSurf_ActiveModelEntity(ent, true, true, false);
- GL_AlphaTest(false);
Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
// set up properties for rendering light onto this entity
RSurf_ActiveWorldEntity();
- GL_AlphaTest(false);
rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
if (!rtlight->draw)
return;
- // if R_FrameData_Store ran out of space we skip anything dependent on it
- if (r_framedata_failed)
- return;
-
numlightentities = rtlight->cached_numlightentities;
numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
numshadowentities = rtlight->cached_numshadowentities;
else
R_Shadow_RenderMode_DrawDeferredLight(false, false);
}
+
+ if (r_shadow_particletrace.integer)
+ R_Shadow_RenderParticlesForLight(rtlight);
}
static void R_Shadow_FreeDeferred(void)
R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
r_shadow_prepassgeometryfbo = 0;
- R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
- r_shadow_prepasslightingfbo = 0;
+ R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
+ r_shadow_prepasslightingdiffusespecularfbo = 0;
+
+ R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
+ r_shadow_prepasslightingdiffusefbo = 0;
if (r_shadow_prepassgeometrydepthtexture)
R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
entity_render_t *ent;
float clearcolor[4];
- GL_AlphaTest(false);
R_Mesh_ResetTextureState();
GL_DepthMask(true);
GL_ColorMask(1,1,1,1);
GL_ColorMask(1,1,1,1);
GL_Color(1,1,1,1);
GL_DepthTest(true);
- R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+ R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
Vector4Set(clearcolor, 0, 0, 0, 0);
GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
if (r_timereport_active)
switch (vid.renderpath)
{
case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
case RENDERPATH_D3D9:
case RENDERPATH_D3D10:
case RENDERPATH_D3D11:
+ case RENDERPATH_SOFT:
+ case RENDERPATH_GLES2:
if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
{
r_shadow_usingdeferredprepass = false;
}
// set up the lighting pass fbo (diffuse + specular)
- r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
- R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+ r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+ R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
// render diffuse into one texture and specular into another,
// with depth and normalmap bound as textures,
// with depth bound as attachment as well
r_shadow_usingdeferredprepass = false;
}
}
+
+ // set up the lighting pass fbo (diffuse)
+ r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
+ R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
+ // render diffuse into one texture,
+ // with depth and normalmap bound as textures,
+ // with depth bound as attachment as well
+ if (qglDrawBuffersARB)
+ {
+ qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
+ Cvar_SetValueQuick(&r_shadow_deferred, 0);
+ r_shadow_usingdeferredprepass = false;
+ }
+ }
}
break;
case RENDERPATH_GL13:
if (r_editlights.integer)
R_Shadow_DrawLightSprites();
+
+ R_Shadow_UpdateBounceGridTexture();
}
void R_Shadow_DrawLights(void)
case RENDERPATH_GL11:
case RENDERPATH_GL13:
case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
+ case RENDERPATH_SOFT:
+ case RENDERPATH_GLES2:
break;
case RENDERPATH_D3D9:
case RENDERPATH_D3D10:
case RENDERPATH_GL20:
case RENDERPATH_GL13:
case RENDERPATH_GL11:
- case RENDERPATH_CGGL:
+ case RENDERPATH_GLES2:
CHECKGLERROR
// NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
GL_DepthFunc(GL_ALWAYS);
R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
- R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
+ R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
GL_DepthFunc(GL_LEQUAL);
qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
- R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
+ R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
CHECKGLERROR
case RENDERPATH_D3D11:
Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
break;
+ case RENDERPATH_SOFT:
+ //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
}
}
rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
case RENDERPATH_GL20:
case RENDERPATH_GL13:
case RENDERPATH_GL11:
- case RENDERPATH_CGGL:
+ case RENDERPATH_GLES2:
CHECKGLERROR
qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
case RENDERPATH_D3D11:
Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
break;
+ case RENDERPATH_SOFT:
+ //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
}
//Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
if (visiblepixels < 1 || allpixels < 1)
case RENDERPATH_GL11:
case RENDERPATH_GL13:
case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
+ case RENDERPATH_GLES2:
qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
break;
case RENDERPATH_D3D9:
case RENDERPATH_D3D11:
Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
break;
+ case RENDERPATH_SOFT:
+ DPSOFTRAST_BlendSubtract(true);
+ break;
}
}
R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
case RENDERPATH_GL11:
case RENDERPATH_GL13:
case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
+ case RENDERPATH_GLES2:
qglBlendEquationEXT(GL_FUNC_ADD_EXT);
break;
case RENDERPATH_D3D9:
case RENDERPATH_D3D11:
Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
break;
+ case RENDERPATH_SOFT:
+ DPSOFTRAST_BlendSubtract(false);
+ break;
}
}
}
case RENDERPATH_GL11:
case RENDERPATH_GL13:
case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
+ case RENDERPATH_GLES2:
usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
if (usequery)
{
case RENDERPATH_D3D11:
Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
break;
+ case RENDERPATH_SOFT:
+ usequery = false;
+ //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
}
for (lightindex = 0;lightindex < range;lightindex++)
{
=============================================================================
*/
-void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
+void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
{
int i, numlights, flag;
- float f, relativepoint[3], dist, dist2, lightradius2;
rtlight_t *light;
dlight_t *dlight;
+ float relativepoint[3];
+ float color[3];
+ float dir[3];
+ float dist;
+ float dist2;
+ float intensity;
+ float sample[5*3];
+ float lightradius2;
- VectorClear(diffusecolor);
- VectorClear(diffusenormal);
+ if (r_fullbright.integer)
+ {
+ VectorSet(ambient, 1, 1, 1);
+ VectorClear(diffuse);
+ VectorClear(lightdir);
+ return;
+ }
if (flags & LP_LIGHTMAP)
{
- if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
- {
- ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
- r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
- }
- else
- VectorSet(ambientcolor, 1, 1, 1);
+ 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)
+ r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
+ 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)
+ {
+ vec3_t tempambient;
+ VectorClear(tempambient);
+ VectorClear(color);
+ VectorClear(relativepoint);
+ r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
+ VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
+ VectorScale(color, r_refdef.lightmapintensity, color);
+ VectorAdd(sample, tempambient, sample);
+ VectorMA(sample , 0.5f , color, sample );
+ VectorMA(sample + 3, relativepoint[0], color, sample + 3);
+ VectorMA(sample + 6, relativepoint[1], color, sample + 6);
+ VectorMA(sample + 9, relativepoint[2], color, sample + 9);
+ // calculate a weighted average light direction as well
+ intensity = VectorLength(color);
+ VectorMA(sample + 12, intensity, relativepoint, sample + 12);
}
+
if (flags & LP_RTWORLD)
{
flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
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)
+ intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
+ if (intensity <= 0.0f)
+ continue;
+ if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
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).fraction == 1)
- VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
+ // scale down intensity to add to both ambient and diffuse
+ //intensity *= 0.5f;
+ VectorNormalize(relativepoint);
+ VectorScale(light->currentcolor, intensity, color);
+ VectorMA(sample , 0.5f , color, sample );
+ VectorMA(sample + 3, relativepoint[0], color, sample + 3);
+ VectorMA(sample + 6, relativepoint[1], color, sample + 6);
+ VectorMA(sample + 9, relativepoint[2], color, sample + 9);
+ // calculate a weighted average light direction as well
+ intensity *= VectorLength(color);
+ VectorMA(sample + 12, intensity, relativepoint, sample + 12);
}
}
+
if (flags & LP_DYNLIGHT)
{
// sample dlights
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)
+ intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
+ if (intensity <= 0.0f)
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).fraction == 1)
- VectorMA(ambientcolor, f, light->color, ambientcolor);
+ if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
+ continue;
+ // scale down intensity to add to both ambient and diffuse
+ //intensity *= 0.5f;
+ VectorNormalize(relativepoint);
+ VectorScale(light->currentcolor, intensity, color);
+ VectorMA(sample , 0.5f , color, sample );
+ VectorMA(sample + 3, relativepoint[0], color, sample + 3);
+ VectorMA(sample + 6, relativepoint[1], color, sample + 6);
+ VectorMA(sample + 9, relativepoint[2], color, sample + 9);
+ // calculate a weighted average light direction as well
+ intensity *= VectorLength(color);
+ VectorMA(sample + 12, intensity, relativepoint, sample + 12);
}
}
+
+ // calculate the direction we'll use to reduce the sample to a directional light source
+ VectorCopy(sample + 12, dir);
+ //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
+ VectorNormalize(dir);
+ // extract the diffuse color along the chosen direction and scale it
+ diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
+ diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
+ diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
+ // subtract some of diffuse from ambient
+ VectorMA(sample, -0.333f, diffuse, ambient);
+ // store the normalized lightdir
+ VectorCopy(dir, lightdir);
}