Skip to content

Commit

Permalink
Fixed: Fairly frequently, the vertex coordinates generated for fakera…
Browse files Browse the repository at this point in the history
…dio edge shadowpolys would result in "folds" at the inner offset. This was due to us storing two separate offsets for each side of the edge and due to numerical inaccuracies; these would sometimes end up not being equal. This has been fixed by using only one set of offsets for each pair of edges and storing them in a the vertex lineowner ring for easy access.

Todo: This has the shortcoming that all edge pairs need to have a set of shadow offsets allocated for them as opposed to only those that actually receive edge shadows. However, given that we are now using roughly half the memory of the previous schema,this is still a big improvement.
  • Loading branch information
danij committed Mar 9, 2008
1 parent aeaf965 commit 0d7a251
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 51 deletions.
13 changes: 13 additions & 0 deletions doomsday/engine/portable/include/mapdata.hs
Expand Up @@ -9,10 +9,23 @@ internal
#define LO_prev link[0]
#define LO_next link[1]

typedef struct shadowpolyoffset_s {
float offset[2];
} shadowpolyoffset_t;

#define MAX_BEXOFFSETS 8

typedef struct shadowvert_s {
float inner[2];
float extended[2];
shadowpolyoffset_t backExtended[MAX_BEXOFFSETS];
} shadowvert_t;

typedef struct lineowner_s {
struct linedef_s *lineDef;
struct lineowner_s *link[2]; // {prev, next} (i.e. {anticlk, clk}).
binangle_t angle; // between this and next clockwise.
shadowvert_t shadowOffsets;
} lineowner_t;

#define V_pos v.pos
Expand Down
13 changes: 13 additions & 0 deletions doomsday/engine/portable/include/p_maptypes.h
Expand Up @@ -8,10 +8,23 @@
#define LO_prev link[0]
#define LO_next link[1]

typedef struct shadowpolyoffset_s {
float offset[2];
} shadowpolyoffset_t;

#define MAX_BEXOFFSETS 8

typedef struct shadowvert_s {
float inner[2];
float extended[2];
shadowpolyoffset_t backExtended[MAX_BEXOFFSETS];
} shadowvert_t;

typedef struct lineowner_s {
struct linedef_s *lineDef;
struct lineowner_s *link[2]; // {prev, next} (i.e. {anticlk, clk}).
binangle_t angle; // between this and next clockwise.
shadowvert_t shadowOffsets;
} lineowner_t;

#define V_pos v.pos
Expand Down
13 changes: 0 additions & 13 deletions doomsday/engine/portable/include/r_data.h
Expand Up @@ -176,25 +176,12 @@ typedef struct linkmobj_s {
// Shadowpoly flags.
#define SHPF_FRONTSIDE 0x1

typedef struct shadowpolyoffset_s {
float offset[2];
} shadowpolyoffset_t;

#define MAX_BEXOFFSETS 8

typedef struct shadowvert_s {
float inOffset[2]; // Inner offset from 'outer.'
float extOffset[2]; // Extended: offset from 'outer.'
shadowpolyoffset_t bExtOffset[MAX_BEXOFFSETS]; // Back-extended: offset frmo 'outer.'
} shadowvert_t;

typedef struct shadowpoly_s {
struct seg_s *seg;
struct subsector_s *ssec;
short flags;
ushort visFrame; // Last visible frame (for rendering).
struct vertex_s *verts[2]; // Left and right.
shadowvert_t vertOffsets[2];
} shadowpoly_t;

typedef struct shadowlink_s {
Expand Down
68 changes: 39 additions & 29 deletions doomsday/engine/portable/src/r_shadow.c
Expand Up @@ -209,27 +209,30 @@ float R_ShadowEdgeWidth(const pvec2_t edge)
*/
void R_ShadowEdges(shadowpoly_t *poly)
{
vec2_t left, right;
int edge, side = !(poly->flags & SHPF_FRONTSIDE);
uint i, count;
linedef_t *line = poly->seg->lineDef;
lineowner_t *base, *p, *boundryOwner = NULL;
boolean done;
vec2_t left, right;
int edge, side = !(poly->flags & SHPF_FRONTSIDE);
uint i, count;
linedef_t *line = poly->seg->lineDef;
lineowner_t *base, *p, *boundryOwner = NULL;
boolean done;
lineowner_t *vo;

for(edge = 0; edge < 2; ++edge) // left and right
{
vo = poly->seg->lineDef->L_vo(edge^side);

// The inside corner:
if(R_ShadowCornerDeltas(left, right, poly, edge == 0))
{
R_CornerNormalPoint(left, R_ShadowEdgeWidth(left), right,
R_ShadowEdgeWidth(right), poly->vertOffsets[edge].inOffset,
edge == 0 ? poly->vertOffsets[edge].extOffset : NULL,
edge == 1 ? poly->vertOffsets[edge].extOffset : NULL);
R_ShadowEdgeWidth(right), vo->shadowOffsets.inner,
edge == 0 ? vo->shadowOffsets.extended : NULL,
edge == 1 ? vo->shadowOffsets.extended : NULL);
}
else
{ // An error in the map. Set the inside corner to the extoffset.
V2_Copy(poly->vertOffsets[edge].inOffset,
poly->vertOffsets[edge].extOffset);
V2_Copy(vo->shadowOffsets.inner,
vo->shadowOffsets.extended);
}

// The back extended offset(s):
Expand Down Expand Up @@ -263,8 +266,8 @@ void R_ShadowEdges(shadowpoly_t *poly)
if(count == 0)
{
// No back-extended, just use the plain extended offset.
V2_Copy(poly->vertOffsets[edge].bExtOffset[0].offset,
poly->vertOffsets[edge].extOffset);
V2_Copy(vo->shadowOffsets.backExtended[0].offset,
vo->shadowOffsets.extended);
}
else
{
Expand Down Expand Up @@ -324,7 +327,7 @@ void R_ShadowEdges(shadowpoly_t *poly)

R_CornerNormalPoint(left, R_ShadowEdgeWidth(left),
right, R_ShadowEdgeWidth(right),
poly->vertOffsets[edge].bExtOffset[i].offset,
vo->shadowOffsets.backExtended[i].offset,
NULL, NULL);

// Update orientSec ready for the next iteration?
Expand Down Expand Up @@ -516,13 +519,15 @@ void R_ResolveOverlaps(shadowpoly_t *polys, uint count, sector_t *sector)
// Calculate the boundaries.
for(i = 0, bound = boundaries; i < count; ++i, bound++)
{
V2_Set(bound->left, polys[i].verts[0]->V_pos[VX],
polys[i].verts[0]->V_pos[VY]);
V2_Sum(bound->a, polys[i].vertOffsets[0].inOffset, bound->left);
shadowpoly_t *poly = &polys[i];

V2_Set(bound->right, polys[i].verts[1]->V_pos[VX],
polys[i].verts[1]->V_pos[VY]);
V2_Sum(bound->b, polys[i].vertOffsets[1].inOffset, bound->right);
V2_Set(bound->left, poly->verts[0]->V_pos[VX],
poly->verts[0]->V_pos[VY]);
V2_Sum(bound->a, poly->seg->lineDef->L_vo(!(poly->flags & SHPF_FRONTSIDE))->shadowOffsets.inner, bound->left);

V2_Set(bound->right, poly->verts[1]->V_pos[VX],
poly->verts[1]->V_pos[VY]);
V2_Sum(bound->b, poly->seg->lineDef->L_vo(poly->flags & SHPF_FRONTSIDE)->shadowOffsets.inner, bound->right);
}
memset(overlaps, 0, count);

Expand Down Expand Up @@ -559,17 +564,19 @@ void R_ResolveOverlaps(shadowpoly_t *polys, uint count, sector_t *sector)
// Adjust the overlapping inner points.
for(i = 0, bound = boundaries; i < count; ++i, bound++)
{
shadowpoly_t *poly = &polys[i];

if(overlaps[i] & OVERLAP_LEFT)
{
if(R_ResolveStep(bound->left, bound->a,
polys[i].vertOffsets[0].inOffset))
poly->seg->lineDef->L_vo(!(poly->flags & SHPF_FRONTSIDE))->shadowOffsets.inner))
done = false;
}

if(overlaps[i] & OVERLAP_RIGHT)
{
if(R_ResolveStep(bound->right, bound->b,
polys[i].vertOffsets[1].inOffset))
poly->seg->lineDef->L_vo(poly->flags & SHPF_FRONTSIDE)->shadowOffsets.inner))
done = false;
}
}
Expand Down Expand Up @@ -620,7 +627,7 @@ uint R_MakeShadowEdges(shadowpoly_t *storage)
seg_t *seg = *segp;

// Minisegs don't get shadows, even then, only one.
if(seg->lineDef &&
if(seg->lineDef && seg->side == 0 &&
!((seg->lineDef->validCount == validCount) ||
LINE_SELFREF(seg->lineDef)))
{
Expand Down Expand Up @@ -692,11 +699,12 @@ uint R_MakeShadowEdges(shadowpoly_t *storage)
*/
void R_InitSectorShadows(void)
{
uint startTime = Sys_GetRealTime();
uint startTime = Sys_GetRealTime();

uint i, maxCount;
shadowpoly_t *shadows, *poly;
vec2_t bounds[2], point;
uint i, maxCount;
shadowpoly_t *shadows, *poly;
vec2_t bounds[2], point;
byte side;

// Find out the number of shadowpolys we'll require.
maxCount = R_MakeShadowEdges(NULL);
Expand Down Expand Up @@ -724,17 +732,19 @@ void R_InitSectorShadows(void)

for(i = 0, poly = shadows; i < maxCount; ++i, poly++)
{
side = (poly->flags & SHPF_FRONTSIDE)? 0 : 1;

V2_Set(point, poly->verts[0]->V_pos[VX], poly->verts[0]->V_pos[VY]);
V2_InitBox(bounds, point);

// Use the extended points, they are wider than inoffsets.
V2_Sum(point, point, poly->vertOffsets[0].extOffset);
V2_Sum(point, point, poly->seg->lineDef->L_vo(side)->shadowOffsets.extended);
V2_AddToBox(bounds, point);

V2_Set(point, poly->verts[1]->V_pos[VX], poly->verts[1]->V_pos[VY]);
V2_AddToBox(bounds, point);

V2_Sum(point, point, poly->vertOffsets[1].extOffset);
V2_Sum(point, point, poly->seg->lineDef->L_vo(side^1)->shadowOffsets.extended);
V2_AddToBox(bounds, point);

P_SubsectorsBoxIteratorv(bounds, R_GetShadowSector(poly, 0, false),
Expand Down
16 changes: 7 additions & 9 deletions doomsday/engine/portable/src/rend_fakeradio.c
Expand Up @@ -1418,14 +1418,12 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR );
{
float pos = sideOpen[i];

if(pos < 1) // Nearly closed.
if(pos < 1) // Nearly closed.
{
/*V2_Lerp(inner[i], shadow->inOffset[i],
shadow->bExtOffset[i], pos);*/
V2_Sum(inner[i], shadow->verts[i]->V_pos,
shadow->vertOffsets[i].inOffset);
shadow->seg->lineDef->L_vo(i^side)->shadowOffsets.inner);
}
else if(pos == 1) // Same height on both sides.
else if(pos == 1) // Same height on both sides.
{ // We need to use a back extended offset but which one?

/**
Expand All @@ -1443,7 +1441,7 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR );
// back neighbor at which plane heights differ.
lineowner_t *base, *p;
vertex_t *vtx =
shadow->seg->lineDef->L_v(i^!(shadow->flags & SHPF_FRONTSIDE));
shadow->seg->lineDef->L_v(i^side);
uint id;
boolean found;

Expand Down Expand Up @@ -1510,12 +1508,12 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR );
{
// id is now the index + 1 into the side's bextoffset array.
V2_Sum(inner[i], shadow->verts[i]->V_pos,
shadow->vertOffsets[i].bExtOffset[id-1].offset);
shadow->seg->lineDef->L_vo(i^side)->shadowOffsets.backExtended[id-1].offset);
}
else // Its an open edge.
{
V2_Sum(inner[i], shadow->verts[i]->V_pos,
shadow->vertOffsets[i].extOffset);
shadow->seg->lineDef->L_vo(i^side)->shadowOffsets.extended);
}
}
else // Fully, unquestionably open.
Expand All @@ -1524,7 +1522,7 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR );
pos = 2;

V2_Sum(inner[i], shadow->verts[i]->V_pos,
shadow->vertOffsets[i].extOffset);
shadow->seg->lineDef->L_vo(i^side)->shadowOffsets.extended);
}
}

Expand Down

0 comments on commit 0d7a251

Please sign in to comment.