Skip to content

Commit

Permalink
Added: Smoothing of per-linedef lightlevel angle deltas. Approximated…
Browse files Browse the repository at this point in the history
… rounded surfaces are lit more realistically when using the DOOM lighting model. Added: CVar "rend-light-wall-angle-smooth" 1= Enable wall angle lightlevel delta smoothing (enabled by default). Changed: Default value for "rend-light-wall-angle" is now 1.2f as the new smoothing makes this less noticeable.

Whilst this smoothing algorithm catches 90% of cases where it should occur there is one case that it does not. The case it doesn't handle is the same as the one case that fakeradio ommits (where a single-sided linedef is colinear with a two-sided linedef whose back sector is open). This last case cannot really be solved with the current stratergy and requires a redesign of the seg drawing loop in Rend_RenderSubsector (which I have already begun in the mapcache branch). As such I decided to leave it as is for now.

I have been sitting on this idea for a while. Now that it is clear that a Beta6.9 release is necessary - I decided to quickly implement it for this release.
  • Loading branch information
danij-deng committed Mar 2, 2010
1 parent e5eb601 commit 187d3eb
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 45 deletions.
5 changes: 4 additions & 1 deletion doomsday/engine/data/cphelp.txt
Expand Up @@ -656,7 +656,10 @@ desc = Maximum radius of dynamic lights (default: 128).
desc = Minimum dynamic light radius to convert to BIAS light source.

[rend-light-wall-angle]
desc = Intensity of angle-based wall light.
desc = Intensity of angle-based wall lighting delta.

[rend-light-wall-angle-smooth]
desc = 1=Enable smoothing of angle-based wall lighting.

[rend-light-multitex]
desc = 1=Use multitexturing when rendering dynamic lights.
Expand Down
2 changes: 1 addition & 1 deletion doomsday/engine/portable/include/p_linedef.h
Expand Up @@ -32,7 +32,7 @@
#include "r_data.h"
#include "p_dmu.h"

float Linedef_GetLightLevelDelta(const linedef_t* l);
void Linedef_LightLevelDelta(const linedef_t* lineDef, byte side, float* deltaL, float* deltaR);

boolean Linedef_GetProperty(const linedef_t *lin, setargs_t *args);
boolean Linedef_SetProperty(linedef_t *lin, const setargs_t *args);
Expand Down
3 changes: 2 additions & 1 deletion doomsday/engine/portable/include/r_world.h
Expand Up @@ -47,6 +47,8 @@ typedef struct skyfix_s {
} skyfix_t;

extern int rendSkyLight; // cvar
extern float rendLightWallAngle;
extern byte rendLightWallAngleSmooth;
extern boolean ddMapSetup;
extern skyfix_t skyFix[2]; // [floor, ceiling]

Expand All @@ -63,7 +65,6 @@ void R_SetupSky(ded_sky_t* sky);

const float* R_GetSectorLightColor(const sector_t* sector);
float R_DistAttenuateLightLevel(float distToViewer, float lightLevel);
float R_WallAngleLightLevelDelta(const linedef_t* l, byte side);
float R_ExtraLightDelta(void);
float R_CheckSectorLight(float lightlevel, float min, float max);
boolean R_IsSkySurface(const surface_t* suf);
Expand Down
1 change: 0 additions & 1 deletion doomsday/engine/portable/include/rend_list.h
Expand Up @@ -63,7 +63,6 @@ extern int renderTextures;
extern int renderWireframe;
extern int useMultiTexLights;
extern int useMultiTexDetails;
extern float rendLightWallAngle;
extern float detailFactor, detailScale;
extern int torchAdditive;
extern float torchColor[];
Expand Down
103 changes: 100 additions & 3 deletions doomsday/engine/portable/src/p_linedef.c
Expand Up @@ -32,6 +32,8 @@
#include "de_refresh.h"
#include "de_play.h"

#include "m_bams.h"

// MACROS ------------------------------------------------------------------

// TYPES -------------------------------------------------------------------
Expand All @@ -50,10 +52,105 @@

// CODE --------------------------------------------------------------------

float Linedef_GetLightLevelDelta(const linedef_t* l)
static void calcNormal(const linedef_t* l, byte side, pvec2_t normal)
{
V2_Set(normal, (l->L_vpos(side^1)[VY] - l->L_vpos(side)[VY]) / l->length,
(l->L_vpos(side)[VX] - l->L_vpos(side^1)[VX]) / l->length);
}

static float lightLevelDelta(const pvec2_t normal)
{
return (1.0f / 255) * (normal[VX] * 18) * rendLightWallAngle;
}

static linedef_t* findBlendNeighbor(const linedef_t* l, byte side, byte right,
binangle_t* diff)
{
if(!l->L_backside ||
l->L_backsector->SP_ceilvisheight <= l->L_frontsector->SP_floorvisheight ||
l->L_backsector->SP_floorvisheight >= l->L_frontsector->SP_ceilvisheight)
{
return R_FindSolidLineNeighbor(l->L_sector(side), l, l->L_vo(right^side), right, diff);
}

return R_FindLineNeighbor(l->L_sector(side), l, l->L_vo(right^side), right, diff);
}

/**
* The DOOM lighting model applies a sector light level delta when drawing
* segs based on their 2D world angle.
*
* @param l Linedef to calculate the delta for.
* @param side Side of the linedef we are interested in.
* @param deltaL Light delta for the left edge is written back here.
* @param deltaR Light delta for the right edge is written back here.
*/
void Linedef_LightLevelDelta(const linedef_t* l, byte side, float* deltaL, float* deltaR)
{
return (1.0f / 255) *
((l->L_vpos(1)[VY] - l->L_vpos(0)[VY]) / l->length * 18);
vec2_t normal;
float delta;

// Disabled?
if(!(rendLightWallAngle > 0))
{
*deltaL = *deltaR = 0;
return;
}

calcNormal(l, side, normal);
delta = lightLevelDelta(normal);

// If smoothing is disabled use this delta for left and right edges.
// Must forcibly disable smoothing for polyobj linedefs as they have
// no owner rings.
if(!rendLightWallAngleSmooth || (l->inFlags & LF_POLYOBJ))
{
*deltaL = *deltaR = delta;
return;
}

// Find the left neighbour linedef for which we will calculate the
// lightlevel delta and then blend with this to produce the value for
// the left edge. Blend iff the angle between the two linedefs is less
// than 45 degrees.
{
binangle_t diff = 0;
linedef_t* other = findBlendNeighbor(l, side, 0, &diff);
if(other && INRANGE_OF(diff, BANG_180, BANG_45))
{
vec2_t otherNormal;

calcNormal(other, other->L_v2 != l->L_v(side), otherNormal);

// Average normals.
V2_Sum(otherNormal, otherNormal, normal);
otherNormal[VX] /= 2; otherNormal[VY] /= 2;

*deltaL = lightLevelDelta(otherNormal);
}
else
*deltaL = delta;
}

// Do the same for the right edge but with the right neighbour linedef.
{
binangle_t diff = 0;
linedef_t* other = findBlendNeighbor(l, side, 1, &diff);
if(other && INRANGE_OF(diff, BANG_180, BANG_45))
{
vec2_t otherNormal;

calcNormal(other, other->L_v1 != l->L_v(side^1), otherNormal);

// Average normals.
V2_Sum(otherNormal, otherNormal, normal);
otherNormal[VX] /= 2; otherNormal[VY] /= 2;

*deltaR = lightLevelDelta(otherNormal);
}
else
*deltaR = delta;
}
}

/**
Expand Down
21 changes: 2 additions & 19 deletions doomsday/engine/portable/src/r_world.c
Expand Up @@ -64,7 +64,8 @@
// PUBLIC DATA DEFINITIONS -------------------------------------------------

int rendSkyLight = 1; // cvar.
float rendLightWallAngle = 1; // Intensity of angle-based wall lighting.
float rendLightWallAngle = 1.2f; // Intensity of angle-based wall lighting.
byte rendLightWallAngleSmooth = true;

boolean firstFrameAfterLoad;
boolean ddMapSetup;
Expand Down Expand Up @@ -1937,24 +1938,6 @@ float R_DistAttenuateLightLevel(float distToViewer, float lightLevel)
return lightLevel;
}

/**
* The DOOM lighting model applies a sector light level delta when drawing
* segs based on their 2D world angle.
*
* @param l Linedef to calculate the delta for.
* @param side Side of the linedef we are interested in.
* @return Calculated delta.
*/
float R_WallAngleLightLevelDelta(const linedef_t* l, byte side)
{
if(!(rendLightWallAngle > 0))
return 0;

// Do a lighting adjustment based on orientation.
return Linedef_GetLightLevelDelta(l) * (side? -1 : 1) *
rendLightWallAngle;
}

/**
* The DOOM lighting model applies a light level delta to everything when
* e.g. the player shoots.
Expand Down
79 changes: 60 additions & 19 deletions doomsday/engine/portable/src/rend_main.c
Expand Up @@ -132,6 +132,7 @@ void Rend_Register(void)
C_VAR_INT2("rend-light-ambient", &ambientLight, 0, 0, 255, Rend_CalcLightModRange);
C_VAR_INT2("rend-light-sky", &rendSkyLight, 0, 0, 1, LG_MarkAllForUpdate);
C_VAR_FLOAT("rend-light-wall-angle", &rendLightWallAngle, CVF_NO_MAX, 0, 0);
C_VAR_BYTE("rend-light-wall-angle-smooth", &rendLightWallAngleSmooth, 0, 0, 1);
C_VAR_FLOAT("rend-light-attenuation", &rendLightDistanceAttentuation, CVF_NO_MAX, 0, 0);

C_VAR_INT("rend-dev-sky", &devRendSkyMode, CVF_NO_ARCHIVE, 0, 2);
Expand Down Expand Up @@ -1363,7 +1364,8 @@ typedef struct {
const float* normal; // Surface normal.
float alpha;
const float* sectorLightLevel;
float surfaceLightLevelDelta;
float surfaceLightLevelDL;
float surfaceLightLevelDR;
const float* sectorLightColor;
const float* surfaceColor;

Expand Down Expand Up @@ -1562,46 +1564,72 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices,
}
else
{
uint i;
float ll = *p->sectorLightLevel +
p->surfaceLightLevelDelta;
uint i;


// Calculate the color for each vertex, blended with plane color?
if(p->surfaceColor[0] < 1 || p->surfaceColor[1] < 1 ||
p->surfaceColor[2] < 1)
{
float vColor[4];
float vColor[4];

// Blend sector light+color+surfacecolor
vColor[CR] = p->surfaceColor[CR] * p->sectorLightColor[CR];
vColor[CG] = p->surfaceColor[CG] * p->sectorLightColor[CG];
vColor[CB] = p->surfaceColor[CB] * p->sectorLightColor[CB];
vColor[CA] = 1;

for(i = 0; i < numVertices; ++i)
lightVertex(&rcolors[i], &rvertices[i], ll, vColor);
if(p->isWall)
{
float llL = *p->sectorLightLevel + p->surfaceLightLevelDL;
float llR = *p->sectorLightLevel + p->surfaceLightLevelDR;

lightVertex(&rcolors[0], &rvertices[0], llL, vColor);
lightVertex(&rcolors[1], &rvertices[1], llL, vColor);
lightVertex(&rcolors[2], &rvertices[2], llR, vColor);
lightVertex(&rcolors[3], &rvertices[3], llR, vColor);
}
else
{
float ll = *p->sectorLightLevel + p->surfaceLightLevelDL;
for(i = 0; i < numVertices; ++i)
lightVertex(&rcolors[i], &rvertices[i], ll, vColor);
}
}
else
{
// Use sector light+color only
for(i = 0; i < numVertices; ++i)
lightVertex(&rcolors[i], &rvertices[i], ll,
p->sectorLightColor);
{ // Use sector light+color only.
if(p->isWall)
{
float llL = *p->sectorLightLevel + p->surfaceLightLevelDL;
float llR = *p->sectorLightLevel + p->surfaceLightLevelDR;

lightVertex(&rcolors[0], &rvertices[0], llL, p->sectorLightColor);
lightVertex(&rcolors[1], &rvertices[1], llL, p->sectorLightColor);
lightVertex(&rcolors[2], &rvertices[2], llR, p->sectorLightColor);
lightVertex(&rcolors[3], &rvertices[3], llR, p->sectorLightColor);
}
else
{
float ll = *p->sectorLightLevel + p->surfaceLightLevelDL;
for(i = 0; i < numVertices; ++i)
lightVertex(&rcolors[i], &rvertices[i], ll,
p->sectorLightColor);
}
}

// Bottom color (if different from top)?
if(p->isWall && p->surfaceColor2)
{
float vColor[4];
float vColor[4];

// Blend sector light+color+surfacecolor
vColor[CR] = p->surfaceColor2[CR] * p->sectorLightColor[CR];
vColor[CG] = p->surfaceColor2[CG] * p->sectorLightColor[CG];
vColor[CB] = p->surfaceColor2[CB] * p->sectorLightColor[CB];
vColor[CA] = 1;

lightVertex(&rcolors[0], &rvertices[0], ll, vColor);
lightVertex(&rcolors[2], &rvertices[2], ll, vColor);
lightVertex(&rcolors[0], &rvertices[0], *p->sectorLightLevel + p->surfaceLightLevelDL, vColor);
lightVertex(&rcolors[2], &rvertices[2], *p->sectorLightLevel + p->surfaceLightLevelDR, vColor);
}
}

Expand Down Expand Up @@ -1820,7 +1848,8 @@ static boolean doRenderSeg(seg_t* seg,
const fvertex_t* from, const fvertex_t* to,
float bottom, float top, const pvec3_t normal,
float alpha,
const float* lightLevel, float lightLevelDelta,
const float* lightLevel, float lightLevelDL,
float lightLevelDR,
const float* lightColor,
uint lightListIdx,
const walldiv_t* divs,
Expand Down Expand Up @@ -1855,7 +1884,8 @@ static boolean doRenderSeg(seg_t* seg,
params.texTL = texTL;
params.texBR = texBR;
params.sectorLightLevel = lightLevel;
params.surfaceLightLevelDelta = lightLevelDelta;
params.surfaceLightLevelDL = lightLevelDL;
params.surfaceLightLevelDR = lightLevelDR;
params.sectorLightColor = lightColor;
params.surfaceColor = color;
params.surfaceColor2 = color2;
Expand Down Expand Up @@ -1979,7 +2009,7 @@ static void renderPlane(subsector_t* ssec, planetype_t type,
params.texBR = texBR;
params.sectorLightLevel = &sec->lightLevel;
params.sectorLightColor = R_GetSectorLightColor(sec);
params.surfaceLightLevelDelta = 0;
params.surfaceLightLevelDL = params.surfaceLightLevelDR = 0;
params.surfaceColor = sufColor;
params.texOffset = texOffset;
params.texScale = texScale;
Expand Down Expand Up @@ -2326,11 +2356,21 @@ static boolean rendSegSection(subsector_t* ssec, seg_t* seg,
applyWallHeightDivision(divs, seg, frontsec, bottom, top);
}

{
float deltaL, deltaR, diff;

Linedef_LightLevelDelta(seg->lineDef, seg->side, &deltaL, &deltaR);

// Linear interpolation of the linedef light deltas to the edges of the seg.
diff = deltaR - deltaL;
deltaR = deltaL + ((seg->offset + seg->length) / seg->lineDef->length) * diff;
deltaL += (seg->offset / seg->lineDef->length) * diff;

solidSeg = doRenderSeg(seg,
from, to, bottom, top,
surface->normal, (forceOpaque? -1 : alpha),
&frontsec->lightLevel,
R_WallAngleLightLevelDelta(seg->lineDef, seg->side),
deltaL, deltaR,
R_GetSectorLightColor(frontsec),
lightListIdx,
(divs[0].num > 0 || divs[1].num > 0)? divs : NULL,
Expand All @@ -2342,6 +2382,7 @@ static boolean rendSegSection(subsector_t* ssec, seg_t* seg,
color, color2,
seg->bsuf[section], (uint) section,
&msA, inter, blended? &msB : NULL);
}
}

return solidSeg;
Expand Down

0 comments on commit 187d3eb

Please sign in to comment.