int r_shadow_prepass_width;
int r_shadow_prepass_height;
rtexture_t *r_shadow_prepassgeometrydepthtexture;
+rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
rtexture_t *r_shadow_prepasslightingdiffusetexture;
rtexture_t *r_shadow_prepasslightingspeculartexture;
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_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_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
+cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
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_RegisterVariable(&r_shadow_bumpscale_basetexture);
Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
+ Cvar_RegisterVariable(&r_shadow_usebihculling);
Cvar_RegisterVariable(&r_shadow_usenormalmap);
Cvar_RegisterVariable(&r_shadow_debuglight);
Cvar_RegisterVariable(&r_shadow_deferred);
Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
+ Cvar_RegisterVariable(&r_shadow_sortsurfaces);
Cvar_RegisterVariable(&r_shadow_polygonfactor);
Cvar_RegisterVariable(&r_shadow_polygonoffset);
Cvar_RegisterVariable(&r_shadow_texture3d);
}
}
-static float testcolor[4] = {0,1,0,1};
void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
{
float nearclip, farclip, bias;
r_viewport_t viewport;
int flipped;
GLuint fbo = 0;
+ float clearcolor[4];
nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
farclip = 1.0f;
bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
break;
case RENDERPATH_D3D9:
+ Vector4Set(clearcolor, 1,1,1,1);
// completely different meaning than in OpenGL path
r_shadow_shadowmap_parameters[1] = 0;
r_shadow_shadowmap_parameters[3] = -bias;
{
GL_ColorMask(0,0,0,0);
if (clear)
- GL_Clear(GL_DEPTH_BUFFER_BIT, testcolor, 1.0f, 0);
+ GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
}
else
{
GL_ColorMask(1,1,1,1);
if (clear)
- GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, testcolor, 1.0f, 0);
+ GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
}
break;
case RENDERPATH_D3D10:
qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
{
- int i, ix1, iy1, ix2, iy2;
- float x1, y1, x2, y2;
- vec4_t v, v2;
- float vertex[20][3];
- int j, k;
- vec4_t plane4f;
- int numvertices;
- float corner[8][4];
- float dist[8];
- int sign[8];
- float f;
-
- r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
- r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
- r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
- r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
-
if (!r_shadow_scissor.integer)
- return false;
-
- // if view is inside the light box, just say yes it's visible
- if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
- return false;
-
- x1 = y1 = x2 = y2 = 0;
-
- // transform all corners that are infront of the nearclip plane
- VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
- plane4f[3] = r_refdef.view.frustum[4].dist;
- numvertices = 0;
- for (i = 0;i < 8;i++)
- {
- Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
- dist[i] = DotProduct4(corner[i], plane4f);
- sign[i] = dist[i] > 0;
- if (!sign[i])
- {
- VectorCopy(corner[i], vertex[numvertices]);
- numvertices++;
- }
- }
- // if some points are behind the nearclip, add clipped edge points to make
- // sure that the scissor boundary is complete
- if (numvertices > 0 && numvertices < 8)
- {
- // add clipped edge points
- for (i = 0;i < 12;i++)
- {
- j = bboxedges[i][0];
- k = bboxedges[i][1];
- if (sign[j] != sign[k])
- {
- f = dist[j] / (dist[j] - dist[k]);
- VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
- numvertices++;
- }
- }
- }
-
- // if we have no points to check, the light is behind the view plane
- if (!numvertices)
- return true;
-
- // if we have some points to transform, check what screen area is covered
- x1 = y1 = x2 = y2 = 0;
- v[3] = 1.0f;
- //Con_Printf("%i vertices to transform...\n", numvertices);
- for (i = 0;i < numvertices;i++)
- {
- VectorCopy(vertex[i], v);
- R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
- //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
- if (i)
- {
- if (x1 > v2[0]) x1 = v2[0];
- if (x2 < v2[0]) x2 = v2[0];
- if (y1 > v2[1]) y1 = v2[1];
- if (y2 < v2[1]) y2 = v2[1];
- }
- else
- {
- x1 = x2 = v2[0];
- y1 = y2 = v2[1];
- }
- }
-
- // now convert the scissor rectangle to integer screen coordinates
- ix1 = (int)(x1 - 1.0f);
- iy1 = vid.height - (int)(y2 - 1.0f);
- ix2 = (int)(x2 + 1.0f);
- iy2 = vid.height - (int)(y1 + 1.0f);
- //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
-
- // clamp it to the screen
- if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
- if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
- if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
- if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
-
- // if it is inside out, it's not visible
- if (ix2 <= ix1 || iy2 <= iy1)
- return true;
-
- // the light area is visible, set up the scissor rectangle
- r_shadow_lightscissor[0] = ix1;
- r_shadow_lightscissor[1] = iy1;
- r_shadow_lightscissor[2] = ix2 - ix1;
- r_shadow_lightscissor[3] = iy2 - iy1;
-
- // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
- switch(vid.renderpath)
{
- case RENDERPATH_D3D9:
- case RENDERPATH_D3D10:
- case RENDERPATH_D3D11:
- r_shadow_lightscissor[1] = vid.height - r_shadow_lightscissor[1] - r_shadow_lightscissor[3];
- break;
- case RENDERPATH_GL11:
- case RENDERPATH_GL13:
- case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
- break;
+ r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
+ r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
+ r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
+ r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
+ return false;
}
-
- r_refdef.stats.lights_scissored++;
+ if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
+ return true; // invisible
+ if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
+ || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
+ || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
+ || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
+ r_refdef.stats.lights_scissored++;
return false;
}
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);
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_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
int surfacelistindex;
msurface_t *surface;
+ // if triangle neighbors are disabled, shadowvolumes are disabled
+ if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
+ return;
+
RSurf_ActiveWorldEntity();
if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist, r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
}
else if (numsurfaces)
+ {
r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
+ }
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
}
R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
r_shadow_prepassgeometrydepthtexture = NULL;
+ if (r_shadow_prepassgeometrydepthcolortexture)
+ R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
+ r_shadow_prepassgeometrydepthcolortexture = NULL;
+
if (r_shadow_prepassgeometrynormalmaptexture)
R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
r_shadow_prepassgeometrynormalmaptexture = NULL;
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_Color(1,1,1,1);
GL_DepthTest(true);
- R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
+ R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
- GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, clearcolor, 1.0f, 0);
+ GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
if (r_timereport_active)
R_TimeReport("prepasscleargeom");
{
lightindex = r_shadow_debuglight.integer;
light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- if (light && (light->flags & flag))
+ if (light && (light->flags & flag) && light->rtlight.draw)
R_Shadow_DrawLight(&light->rtlight);
}
else
for (lightindex = 0;lightindex < range;lightindex++)
{
light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
- if (light && (light->flags & flag))
+ if (light && (light->flags & flag) && light->rtlight.draw)
R_Shadow_DrawLight(&light->rtlight);
}
}
if (r_refdef.scene.rtdlight)
for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
- R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
+ if (r_refdef.scene.lights[lnum]->draw)
+ R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
R_Mesh_ResetRenderTargets();
r_shadow_prepass_width = vid.width;
r_shadow_prepass_height = vid.height;
r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_D3D9:
+ r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
+ break;
+ default:
+ break;
+ }
r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
// set up the geometry pass fbo (depth + normalmap)
r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
- R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
+ R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
// render depth into one texture and normalmap into the other
if (qglDrawBuffersARB)
{
Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL20:
+ case RENDERPATH_CGGL:
+ break;
+ case RENDERPATH_D3D9:
+ case RENDERPATH_D3D10:
+ case RENDERPATH_D3D11:
+#ifdef OPENGL_ORIENTATION
+ r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
+ r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
+ r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
+ r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
+#else
+ r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
+ r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
+ r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
+ r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
+#endif
+ break;
+ }
+
r_shadow_usingshadowmaportho = true;
switch (r_shadow_shadowmode)
{
=============================================================================
*/
-void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
+void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
{
+ int i, numlights, flag;
+ float f, relativepoint[3], dist, dist2, lightradius2;
+ rtlight_t *light;
+ dlight_t *dlight;
+
VectorClear(diffusecolor);
VectorClear(diffusenormal);
- if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
+ if (flags & LP_LIGHTMAP)
{
- ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
- r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
+ 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);
}
- else
- VectorSet(ambientcolor, 1, 1, 1);
-
- if (dynamic)
+ if (flags & LP_RTWORLD)
{
- int i;
- float f, v[3];
- rtlight_t *light;
+ 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).fraction == 1)
+ VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
+ }
+ }
+ if (flags & LP_DYNLIGHT)
+ {
+ // sample dlights
for (i = 0;i < r_refdef.scene.numlights;i++)
{
light = r_refdef.scene.lights[i];
- Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
- f = 1 - VectorLength2(v);
- if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
- VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
+ // 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).fraction == 1)
+ VectorMA(ambientcolor, f, light->color, ambientcolor);
}
}
}