- refactoring of portal grouping for the renderer, to allow more efficient clipping.

This commit is contained in:
Christoph Oelckers 2016-03-04 14:10:13 +01:00
parent af1b70376b
commit dbd89c2702
6 changed files with 151 additions and 74 deletions

View file

@ -54,7 +54,17 @@ struct FPortal
GLSectorStackPortal *GetGLPortal();
};
struct FGLLinePortal
{
// defines the complete span of this portal
vertex_t *v1, *v2; // vertices, from v1 to v2
fixed_t dx, dy; // precalculated v2 - v1 for side checking
FLinePortal *reference; // one of the associated line portals, for retrieving translation info etc.
};
extern TArray<FPortal *> portals;
extern TArray<FGLLinePortal*> linePortalToGL;
extern TArray<BYTE> currentmapsection;
void gl_InitPortals();

View file

@ -87,6 +87,8 @@ typedef TArray<FPortalSector> FPortalSectors;
typedef TMap<FPortalID, FPortalSectors> FPortalMap;
TArray<FPortal *> portals;
TArray<FGLLinePortal*> linePortalToGL;
TArray<FGLLinePortal> glLinePortals;
//==========================================================================
//
@ -426,6 +428,77 @@ void gl_InitPortals()
}
}
}
// Now group the line portals (each group must be a continuous set of colinear linedefs with no gaps)
glLinePortals.Clear();
linePortalToGL.Clear();
TArray<int> tempindex;
tempindex.Reserve(linePortals.Size());
memset(&tempindex[0], -1, linePortals.Size() * sizeof(int));
for (unsigned i = 0; i < linePortals.Size(); i++)
{
auto port = linePortals[i];
bool gotsome;
if (tempindex[i] == -1)
{
tempindex[i] = glLinePortals.Size();
line_t *pSrcLine = linePortals[i].mOrigin;
line_t *pLine = linePortals[i].mDestination;
FGLLinePortal glport = { pLine->v1, pLine->v2, 0, 0, &linePortals[i] };
glLinePortals.Push(glport);
// We cannot do this grouping for non-linked portals because they can be changed at run time.
if (linePortals[i].mType == PORTT_LINKED)
do
{
// now collect all other colinear lines connected to this one. We run this loop as long as it still finds a match
gotsome = false;
for (unsigned j = 0; j < linePortals.Size(); j++)
{
if (tempindex[j] == -1)
{
line_t *pSrcLine2 = linePortals[j].mOrigin;
line_t *pLine2 = linePortals[j].mDestination;
// angular precision is intentionally reduced to 32 bit BAM to account for precision problems (otherwise many not perfectly horizontal or vertical portals aren't found here.)
angle_t srcang = RAD2ANGLE(atan2(pSrcLine->dy, pSrcLine->dx));
angle_t dstang = RAD2ANGLE(atan2(pLine->dy, pLine->dx));
if ((pSrcLine->v2 == pSrcLine2->v1 && pLine->v1 == pLine2->v2) ||
(pSrcLine->v1 == pSrcLine2->v2 && pLine->v2 == pLine2->v1))
{
// The line connects, now check the translation
fixed_t srcang2 = RAD2ANGLE(atan2(pSrcLine2->dy, pSrcLine2->dx));
fixed_t dstang2 = RAD2ANGLE(atan2(pLine2->dy, pLine2->dx));
if (srcang == srcang2 && dstang == dstang2)
{
// The lines connect and both source and destination are colinear, so this is a match
gotsome = true;
tempindex[j] = tempindex[i];
if (pLine->v1 == pLine2->v2) glLinePortals[tempindex[i]].v1 = pLine2->v1;
else glLinePortals[tempindex[i]].v2 = pLine2->v2;
}
}
}
}
} while (gotsome);
}
}
for (auto glport : glLinePortals)
{
glport.dx = glport.v2->x - glport.v1->x;
glport.dy = glport.v2->y - glport.v1->y;
}
linePortalToGL.Resize(linePortals.Size());
for (unsigned i = 0; i < linePortals.Size(); i++)
{
linePortalToGL[i] = &glLinePortals[tempindex[i]];
/*
Printf("portal at line %d translates to GL portal %d, range = %f,%f to %f,%f\n",
int(linePortals[i].mOrigin - lines), tempindex[i], linePortalToGL[i]->v1->x / 65536., linePortalToGL[i]->v1->y / 65536., linePortalToGL[i]->v2->x / 65536., linePortalToGL[i]->v2->y / 65536.);
*/
}
}
CCMD(dumpportals)

View file

@ -100,7 +100,7 @@ bool GLPortal::inskybox;
UniqueList<GLSkyInfo> UniqueSkies;
UniqueList<GLHorizonInfo> UniqueHorizons;
UniqueList<secplane_t> UniquePlaneMirrors;
UniqueList<GLLineToLineInfo> UniqueLineToLines;
UniqueList<FGLLinePortal> UniqueLineToLines;
@ -950,24 +950,24 @@ void GLMirrorPortal::DrawContents()
}
int GLMirrorPortal::ClipSeg(seg_t *seg)
int GLLinePortal::ClipSeg(seg_t *seg)
{
return P_ClipLineToPortal(seg->linedef, linedef, viewx, viewy) ? PClip_InFront : PClip_Inside;
return PClip_Inside;// P_ClipLineToPortal(seg->linedef, line(), viewx, viewy) ? PClip_InFront : PClip_Inside;
}
int GLMirrorPortal::ClipSubsector(subsector_t *sub)
int GLLinePortal::ClipSubsector(subsector_t *sub)
{
// this seg is completely behind the mirror!
for(unsigned int i=0;i<sub->numlines;i++)
{
if (P_PointOnLineSidePrecise(sub->firstline[i].v1->x, sub->firstline[i].v1->y, linedef) == 0) return PClip_Inside;
if (P_PointOnLineSidePrecise(sub->firstline[i].v1->x, sub->firstline[i].v1->y, line()) == 0) return PClip_Inside;
}
return PClip_InFront;
}
int GLMirrorPortal::ClipPoint(fixed_t x, fixed_t y)
int GLLinePortal::ClipPoint(fixed_t x, fixed_t y)
{
if (P_PointOnLineSidePrecise(x, y, linedef))
if (P_PointOnLineSidePrecise(x, y, line()))
{
return PClip_InFront;
}
@ -985,29 +985,6 @@ int GLMirrorPortal::ClipPoint(fixed_t x, fixed_t y)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GLLineToLineInfo::init(line_t *line)
{
static const divline_t divlx = { 0, 0, 128 * FRACUNIT, 0 };
static const divline_t divly = { 0, 0, 0, 128 * FRACUNIT };
// store some info about the portal line
divline_t divl;
P_MakeDivline(line, &divl);
x0 = P_InterceptVector(&divlx, &divl);
y0 = P_InterceptVector(&divly, &divl);
lineangle = R_PointToAnglePrecise(line->v1->x, line->v1->y, line->v2->x, line->v2->y);
// and some info about the viewpoint translation
viewx = ::viewx;
viewy = ::viewy;
viewz = ::viewz;
viewangle = ::viewangle;
P_TranslatePortalXY(line, viewx, viewy);
P_TranslatePortalAngle(line, viewangle);
P_TranslatePortalZ(line, viewz);
}
//-----------------------------------------------------------------------------
//
//
@ -1024,10 +1001,11 @@ void GLLineToLinePortal::DrawContents()
GLRenderer->mCurrentPortal = this;
viewx = l2l->viewx;
viewy = l2l->viewy;
viewz = l2l->viewz;
viewangle = l2l->viewangle;
line_t *origin = glport->reference->mOrigin;
P_TranslatePortalXY(origin, viewx, viewy);
P_TranslatePortalAngle(origin, viewangle);
P_TranslatePortalZ(origin, viewz);
SaveMapSection();
for (unsigned i = 0; i < lines.Size(); i++)
@ -1051,6 +1029,7 @@ void GLLineToLinePortal::DrawContents()
}
/*
int GLLineToLinePortal::ClipSeg(seg_t *seg)
{
line_t *linedef = lines[0].seg->linedef->getPortalDestination();
@ -1086,6 +1065,7 @@ int GLLineToLinePortal::ClipPoint(fixed_t x, fixed_t y)
}
return PClip_Inside;
}
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

View file

@ -41,9 +41,11 @@
#include "gl/renderer/gl_renderer.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/utility/gl_templates.h"
#include "gl/data/gl_data.h"
class ASkyViewpoint;
struct GLHorizonInfo
{
GLSectorPlane plane;
@ -51,18 +53,6 @@ struct GLHorizonInfo
FColormap colormap;
};
struct GLLineToLineInfo
{
angle_t viewangle;
fixed_t viewx;
fixed_t viewy;
fixed_t viewz;
fixed_t x0, y0;
angle_t lineangle;
void init(line_t *line);
};
struct GLSkyInfo
{
float x_offset[2];
@ -88,7 +78,7 @@ struct GLSkyInfo
extern UniqueList<GLSkyInfo> UniqueSkies;
extern UniqueList<GLHorizonInfo> UniqueHorizons;
extern UniqueList<secplane_t> UniquePlaneMirrors;
extern UniqueList<GLLineToLineInfo> UniqueLineToLines;
extern UniqueList<FGLLinePortal> UniqueLineToLines;
struct GLEEHorizonPortal;
class GLPortal
@ -184,8 +174,44 @@ public:
static GLPortal * FindPortal(const void * src);
};
struct GLLinePortal : public GLPortal
{
// this must be the same as at the start of line_t, so that we can pass in this structure directly to P_ClipLineToPortal.
vertex_t *v1, *v2; // vertices, from v1 to v2
fixed_t dx, dy; // precalculated v2 - v1 for side checking
struct GLMirrorPortal : public GLPortal
angle_t angv1, angv2; // for quick comparisons with a line or subsector
GLLinePortal(line_t *line)
{
v1 = line->v1;
v2 = line->v2;
dx = line->dx;
dy = line->dy;
}
GLLinePortal(FGLLinePortal *line)
{
v1 = line->v1;
v2 = line->v2;
dx = line->dx;
dy = line->dy;
}
line_t *line()
{
vertex_t **pv = &v1;
return reinterpret_cast<line_t*>(pv);
}
virtual int ClipSeg(seg_t *seg);
virtual int ClipSubsector(subsector_t *sub);
virtual int ClipPoint(fixed_t x, fixed_t y);
virtual bool NeedCap() { return false; }
};
struct GLMirrorPortal : public GLLinePortal
{
// mirror portals always consist of single linedefs!
line_t * linedef;
@ -198,36 +224,28 @@ protected:
public:
GLMirrorPortal(line_t * line)
: GLLinePortal(line)
{
linedef=line;
}
virtual bool NeedCap() { return false; }
virtual int ClipSeg(seg_t *seg);
virtual int ClipSubsector(subsector_t *sub);
virtual int ClipPoint(fixed_t x, fixed_t y);
};
struct GLLineToLinePortal : public GLPortal
struct GLLineToLinePortal : public GLLinePortal
{
GLLineToLineInfo *l2l;
FGLLinePortal *glport;
protected:
virtual void DrawContents();
virtual void * GetSource() const { return l2l; }
virtual void * GetSource() const { return glport; }
virtual const char *GetName();
public:
GLLineToLinePortal(GLLineToLineInfo *ll)
GLLineToLinePortal(FGLLinePortal *ll)
: GLLinePortal(ll)
{
l2l=ll;
glport = ll;
}
virtual bool NeedCap() { return false; }
virtual int ClipSeg(seg_t *seg);
virtual int ClipSubsector(subsector_t *sub);
virtual int ClipPoint(fixed_t x, fixed_t y);
};
@ -238,7 +256,7 @@ struct GLSkyboxPortal : public GLPortal
protected:
virtual void DrawContents();
virtual void * GetSource() const { return origin; }
virtual bool IsSky() { return true; } // later!
virtual bool IsSky() { return true; }
virtual const char *GetName();
public:

View file

@ -21,7 +21,7 @@ struct GLSkyInfo;
struct FTexCoordInfo;
struct FPortal;
struct FFlatVertex;
struct GLLineToLineInfo;
struct FGLLinePortal;
enum WallTypes
@ -149,7 +149,7 @@ public:
GLHorizonInfo * horizon; // for horizon information
FPortal * portal; // stacked sector portals
secplane_t * planemirror; // for plane mirrors
GLLineToLineInfo *l2l; // line-to-line portals
FGLLinePortal *lineportal; // line-to-line portals
};

View file

@ -214,8 +214,8 @@ void GLWall::PutPortal(int ptype)
break;
case PORTALTYPE_LINETOLINE:
portal=GLPortal::FindPortal(l2l);
if (!portal) portal=new GLLineToLinePortal(l2l);
portal=GLPortal::FindPortal(lineportal);
if (!portal) portal=new GLLineToLinePortal(lineportal);
portal->AddLine(this);
break;
@ -1493,13 +1493,11 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
if (seg->linedef->isVisualPortal())
{
GLLineToLineInfo llinfo;
lineportal = linePortalToGL[seg->linedef->portalindex];
ztop[0] = zceil[0];
ztop[1] = zceil[1];
zbottom[0] = zfloor[0];
zbottom[1] = zfloor[1];
llinfo.init(seg->linedef);
l2l = UniqueLineToLines.Get(&llinfo);
PutPortal(PORTALTYPE_LINETOLINE);
}
else if (seg->linedef->skybox == NULL && !seg->linedef->isVisualPortal())
@ -1617,13 +1615,11 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
if (seg->linedef->isVisualPortal() && seg->sidedef == seg->linedef->sidedef[0])
{
GLLineToLineInfo llinfo;
lineportal = linePortalToGL[seg->linedef->portalindex];
ztop[0] = FIXED2FLOAT(bch1);
ztop[1] = FIXED2FLOAT(bch2);
zbottom[0] = FIXED2FLOAT(bfh1);
zbottom[1] = FIXED2FLOAT(bfh2);
llinfo.init(seg->linedef);
l2l = UniqueLineToLines.Get(&llinfo);
PutPortal(PORTALTYPE_LINETOLINE);
}
else if (backsector->e->XFloor.ffloors.Size() || frontsector->e->XFloor.ffloors.Size())