From dbd89c2702987278536bb85c346b54df18a07561 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 4 Mar 2016 14:10:13 +0100 Subject: [PATCH] - refactoring of portal grouping for the renderer, to allow more efficient clipping. --- src/gl/data/gl_data.h | 10 +++++ src/gl/data/gl_portaldata.cpp | 73 ++++++++++++++++++++++++++++++++ src/gl/scene/gl_portal.cpp | 48 +++++++-------------- src/gl/scene/gl_portal.h | 78 +++++++++++++++++++++-------------- src/gl/scene/gl_wall.h | 4 +- src/gl/scene/gl_walls.cpp | 12 ++---- 6 files changed, 151 insertions(+), 74 deletions(-) diff --git a/src/gl/data/gl_data.h b/src/gl/data/gl_data.h index ac2fe0285b..9618a5bef4 100644 --- a/src/gl/data/gl_data.h +++ b/src/gl/data/gl_data.h @@ -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 portals; +extern TArray linePortalToGL; + extern TArray currentmapsection; void gl_InitPortals(); diff --git a/src/gl/data/gl_portaldata.cpp b/src/gl/data/gl_portaldata.cpp index 14a78c7a12..77a93434b6 100644 --- a/src/gl/data/gl_portaldata.cpp +++ b/src/gl/data/gl_portaldata.cpp @@ -87,6 +87,8 @@ typedef TArray FPortalSectors; typedef TMap FPortalMap; TArray portals; +TArray linePortalToGL; +TArray 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 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) diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index 106bf4828f..9dd9edc947 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -100,7 +100,7 @@ bool GLPortal::inskybox; UniqueList UniqueSkies; UniqueList UniqueHorizons; UniqueList UniquePlaneMirrors; -UniqueList UniqueLineToLines; +UniqueList 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;inumlines;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; } +*/ //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- diff --git a/src/gl/scene/gl_portal.h b/src/gl/scene/gl_portal.h index 177c2230e7..6b94e649ca 100644 --- a/src/gl/scene/gl_portal.h +++ b/src/gl/scene/gl_portal.h @@ -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 UniqueSkies; extern UniqueList UniqueHorizons; extern UniqueList UniquePlaneMirrors; -extern UniqueList UniqueLineToLines; +extern UniqueList 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(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: diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 1dc060e660..ce03267a3c 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -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 }; diff --git a/src/gl/scene/gl_walls.cpp b/src/gl/scene/gl_walls.cpp index 985cd13536..1d974205c2 100644 --- a/src/gl/scene/gl_walls.cpp +++ b/src/gl/scene/gl_walls.cpp @@ -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())