diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 86adf047a..66eb3fa4e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -480,7 +480,7 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" ) set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" ) endif() - + set( REL_CXX_FLAGS "-fno-rtti" ) if( NOT PROFILE AND NOT APPLE ) # On OS X frame pointers are required for exception handling, at least with Clang @@ -497,6 +497,30 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers ${CMAKE_CXX_FLAGS}" ) + # Use the highest C++ standard available since VS2015 compiles with C++14 + # but we only require C++11. The recommended way to do this in CMake is to + # probably to use target_compile_features, but I don't feel like maintaining + # a list of features we use. + CHECK_CXX_COMPILER_FLAG( "-std=c++14" CAN_DO_CPP14 ) + if ( CAN_DO_CPP14 ) + set ( CMAKE_CXX_FLAGS "-std=c++14 ${CMAKE_CXX_FLAGS}" ) + else () + CHECK_CXX_COMPILER_FLAG( "-std=c++1y" CAN_DO_CPP1Y ) + if ( CAN_DO_CPP1Y ) + set ( CMAKE_CXX_FLAGS "-std=c++1y ${CMAKE_CXX_FLAGS}" ) + else () + CHECK_CXX_COMPILER_FLAG( "-std=c++11" CAN_DO_CPP11 ) + if ( CAN_DO_CPP11 ) + set ( CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}" ) + else () + CHECK_CXX_COMPILER_FLAG( "-std=c++0x" CAN_DO_CPP0X ) + if ( CAN_DO_CPP0X ) + set ( CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}" ) + endif () + endif () + endif () + endif () + # Remove extra warnings when using the official DirectX headers. # Also, TDM-GCC 4.4.0 no longer accepts glibc-style printf formats as valid, # which is a royal pain. The previous version I had been using was fine with them. diff --git a/src/am_map.cpp b/src/am_map.cpp index 28bd27aff..aac56f1c2 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1695,9 +1695,9 @@ bool AM_clipMline (mline_t *ml, fline_t *fl) TOP =8 }; - register int outcode1 = 0; - register int outcode2 = 0; - register int outside; + int outcode1 = 0; + int outcode2 = 0; + int outside; fpoint_t tmp = { 0, 0 }; int dx; diff --git a/src/doomdef.h b/src/doomdef.h index 3b066f8d8..12a9dbfe9 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -302,7 +302,7 @@ enum }; // [RH] Compatibility flags. -enum +enum : unsigned int { COMPATF_SHORTTEX = 1 << 0, // Use Doom's shortest texture around behavior? COMPATF_STAIRINDEX = 1 << 1, // Don't fix loop index for stair building? diff --git a/src/g_level.h b/src/g_level.h index 6e1768c3a..b6b848674 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -125,7 +125,7 @@ struct FMapOptInfo bool old; }; -enum ELevelFlags +enum ELevelFlags : unsigned int { LEVEL_NOINTERMISSION = 0x00000001, LEVEL_NOINVENTORYBAR = 0x00000002, // This effects Doom only, since it's the only one without a standard inventory bar. diff --git a/src/md5.cpp b/src/md5.cpp index 481774c7a..b81209546 100644 --- a/src/md5.cpp +++ b/src/md5.cpp @@ -166,7 +166,7 @@ void MD5Context::Final(BYTE digest[16]) void MD5Transform(DWORD buf[4], const DWORD in[16]) { - register DWORD a, b, c, d; + DWORD a, b, c, d; a = buf[0]; b = buf[1]; diff --git a/src/p_local.h b/src/p_local.h index 35dbb8b22..7e11010c5 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -243,6 +243,7 @@ extern msecnode_t *sector_list; // phares 3/16/98 struct spechit_t { line_t *line; + fixedvec2 oldrefpos; fixedvec2 refpos; }; diff --git a/src/p_map.cpp b/src/p_map.cpp index 66b4d39e4..7908ce4a9 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -808,6 +808,18 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec if (!ld->backsector) { // One sided line + + // Needed for polyobject portals. Having two-sided lines just for portals on otherwise solid polyobjects is a messy subject. + if ((cres.line->sidedef[0]->Flags & WALLF_POLYOBJ) && cres.line->isLinePortal()) + { + spechit_t spec; + spec.line = ld; + spec.refpos = cres.position; + spec.oldrefpos = tm.thing->PosRelative(ld); + portalhit.Push(spec); + return true; + } + if (((cres.portalflags & FFCF_NOFLOOR) && LineIsAbove(cres.line, tm.thing) != 0) || ((cres.portalflags & FFCF_NOCEILING) && LineIsBelow(cres.line, tm.thing) != 0)) { @@ -969,18 +981,122 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec { spec.line = ld; spec.refpos = cres.position; + spec.oldrefpos = tm.thing->PosRelative(ld); spechit.Push(spec); } - if (ld->portalindex >= 0 && ld->portalindex != UINT_MAX) + if (ld->portalindex != UINT_MAX) { spec.line = ld; spec.refpos = cres.position; + spec.oldrefpos = tm.thing->PosRelative(ld); portalhit.Push(spec); } return true; } +//========================================================================== +// +// +// PIT_CheckPortal +// This checks the destination side of a non-static line portal +// We cannot run a full P_CheckPosition there because it'd set +// multiple fields to values that can cause problems in other +// parts of the code +// +// What this does is starting a separate BlockLinesIterator +// and only taking the absolutely necessary information +// (i.e. floor and ceiling height plus terrain) +// +// +//========================================================================== + +static bool PIT_CheckPortal(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::CheckResult cres, const FBoundingBox &box, FCheckPosition &tm) +{ + // if in another vertical section let's just ignore it. + if (cres.portalflags & (FFCF_NOCEILING | FFCF_NOFLOOR)) return false; + + if (box.Right() <= cres.line->bbox[BOXLEFT] + || box.Left() >= cres.line->bbox[BOXRIGHT] + || box.Top() <= cres.line->bbox[BOXBOTTOM] + || box.Bottom() >= cres.line->bbox[BOXTOP]) + return false; + + if (box.BoxOnLineSide(cres.line) != -1) + return false; + + line_t *lp = cres.line->getPortalDestination(); + fixed_t zofs = 0; + + P_TranslatePortalXY(cres.line, lp, cres.position.x, cres.position.y); + P_TranslatePortalZ(cres.line, lp, zofs); + + // fudge a bit with the portal line so that this gets included in the checks that normally only get run on two-sided lines + sector_t *sec = lp->backsector; + if (lp->backsector == NULL) lp->backsector = lp->frontsector; + tm.thing->AddZ(zofs); + + FBoundingBox pbox(cres.position.x, cres.position.y, tm.thing->radius); + FBlockLinesIterator it(pbox); + bool ret = false; + line_t *ld; + + // Check all lines at the destination + while ((ld = it.Next())) + { + if (pbox.Right() <= ld->bbox[BOXLEFT] + || pbox.Left() >= ld->bbox[BOXRIGHT] + || pbox.Top() <= ld->bbox[BOXBOTTOM] + || pbox.Bottom() >= ld->bbox[BOXTOP]) + continue; + + if (pbox.BoxOnLineSide(ld) != -1) + continue; + + if (ld->backsector == NULL) + continue; + + fixedvec2 ref = FindRefPoint(ld, cres.position); + FLineOpening open; + + P_LineOpening(open, tm.thing, ld, ref.x, ref.y, cres.position.x, cres.position.y, 0); + + // adjust floor / ceiling heights + if (open.top - zofs < tm.ceilingz) + { + tm.ceilingz = open.top - zofs; + tm.ceilingpic = open.ceilingpic; + /* + tm.ceilingsector = open.topsec; + tm.ceilingline = ld; + tm.thing->BlockingLine = ld; + */ + ret = true; + } + + if (open.bottom - zofs > tm.floorz) + { + tm.floorz = open.bottom - zofs; + tm.floorpic = open.floorpic; + tm.floorterrain = open.floorterrain; + /* + tm.floorsector = open.bottomsec; + tm.touchmidtex = open.touchmidtex; + tm.abovemidtex = open.abovemidtex; + tm.thing->BlockingLine = ld; + */ + ret = true; + } + + if (open.lowfloor - zofs < tm.dropoffz) + tm.dropoffz = open.lowfloor - zofs; + } + tm.thing->AddZ(-zofs); + lp->backsector = sec; + + return ret; +} + //========================================================================== // @@ -1526,7 +1642,6 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo tm.touchmidtex = false; tm.abovemidtex = false; validcount++; - spechit.Clear(); if ((thing->flags & MF_NOCLIP) && !(thing->flags & MF_SKULLFLY)) return true; @@ -1610,6 +1725,9 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo if (actorsonly || (thing->flags & MF_NOCLIP)) return (thing->BlockingMobj = thingblocker) == NULL; + spechit.Clear(); + portalhit.Clear(); + FMultiBlockLinesIterator it(pcheck, x, y, thing->Z(), thing->height, thing->radius); FMultiBlockLinesIterator::CheckResult lcres; @@ -1621,7 +1739,22 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo while (it.Next(&lcres)) { - good &= PIT_CheckLine(it, lcres, it.Box(), tm); + bool thisresult = PIT_CheckLine(it, lcres, it.Box(), tm); + good &= thisresult; + if (thisresult) + { + FLinePortal *port = lcres.line->getPortal(); + if (port != NULL && port->mFlags & PORTF_PASSABLE && port->mType != PORTT_LINKED) + { + // Checking the other side of the portal completely is too costly, + // but checking the portal's destination line is necessary to + // retrieve the proper sector heights on the other side. + if (PIT_CheckPortal(it, lcres, it.Box(), tm)) + { + tm.thing->BlockingLine = lcres.line; + } + } + } } if (!good) { @@ -2132,22 +2265,126 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, return false; } - // the move is ok, so link the thing into its new position - thing->UnlinkFromWorld(); - oldpos = thing->Pos(); - oldsector = thing->Sector; - thing->floorz = tm.floorz; - thing->ceilingz = tm.ceilingz; - thing->dropoffz = tm.dropoffz; // killough 11/98: keep track of dropoffs - thing->floorpic = tm.floorpic; - thing->floorterrain = tm.floorterrain; - thing->floorsector = tm.floorsector; - thing->ceilingpic = tm.ceilingpic; - thing->ceilingsector = tm.ceilingsector; - thing->SetXY(x, y); + // Check for crossed portals + bool portalcrossed; + portalcrossed = false; - thing->LinkToWorld(); + while (true) + { + fixed_t bestfrac = FIXED_MAX; + spechit_t besthit; + // find the portal nearest to the crossing actor + for (auto &spec : portalhit) + { + line_t *ld = spec.line; + if (ld->frontsector->PortalGroup != thing->Sector->PortalGroup) continue; // must be in the same group to be considered valid. + + // see if the line was crossed + oldside = P_PointOnLineSide(spec.oldrefpos.x, spec.oldrefpos.y, ld); + side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, ld); + if (oldside == 0 && side == 1) + { + divline_t dl2 = { ld->v1->x, ld->v1->y, ld->dx, ld->dy }; + divline_t dl1 = { spec.oldrefpos.x, spec.oldrefpos.y, spec.refpos.x - spec.oldrefpos.x, spec.refpos.y - spec.oldrefpos.y }; + fixed_t frac = P_InterceptVector(&dl1, &dl2); + if (frac < bestfrac) + { + besthit = spec; + bestfrac = frac; + } + } + } + + if (bestfrac < FIXED_MAX) + { + line_t *ld = besthit.line; + FLinePortal *port = ld->getPortal(); + if (port->mType == PORTT_LINKED) + { + thing->UnlinkFromWorld(); + thing->SetXY(tm.x + port->mXDisplacement, tm.y + port->mYDisplacement); + thing->PrevX += port->mXDisplacement; + thing->PrevY += port->mYDisplacement; + thing->LinkToWorld(); + P_FindFloorCeiling(thing); + portalcrossed = true; + } + else if (!portalcrossed) + { + line_t *out = port->mDestination; + fixedvec3 pos = { tm.x, tm.y, thing->Z() }; + fixedvec3 oldthingpos = thing->Pos(); + fixedvec2 thingpos = oldthingpos; + + P_TranslatePortalXY(ld, out, pos.x, pos.y); + P_TranslatePortalXY(ld, out, thingpos.x, thingpos.y); + P_TranslatePortalZ(ld, out, pos.z); + thing->SetXYZ(thingpos.x, thingpos.y, pos.z); + if (!P_CheckPosition(thing, pos.x, pos.y, true)) // check if some actor blocks us on the other side. (No line checks, because of the mess that'd create.) + { + thing->SetXYZ(oldthingpos); + thing->flags6 &= ~MF6_INTRYMOVE; + return false; + } + thing->UnlinkFromWorld(); + thing->SetXYZ(pos); + P_TranslatePortalVXVY(ld, out, thing->velx, thing->vely); + P_TranslatePortalAngle(ld, out, thing->angle); + thing->LinkToWorld(); + P_FindFloorCeiling(thing); + thing->ClearInterpolation(); + portalcrossed = true; + } + // if this is the current camera we need to store the point where the portal was crossed and the exit + // so that the renderer can properly calculate an interpolated position along the movement path. + if (thing == players[consoleplayer].camera) + { + divline_t dl1 = { besthit.oldrefpos.x,besthit. oldrefpos.y, besthit.refpos.x - besthit.oldrefpos.x, besthit.refpos.y - besthit.oldrefpos.y }; + fixedvec3a hit = { dl1.x + FixedMul(dl1.dx, bestfrac), dl1.y + FixedMul(dl1.dy, bestfrac), 0, 0 }; + line_t *out = port->mDestination; + + R_AddInterpolationPoint(hit); + if (port->mType == PORTT_LINKED) + { + hit.x += port->mXDisplacement; + hit.y += port->mYDisplacement; + } + else + { + P_TranslatePortalXY(ld, out, hit.x, hit.y); + P_TranslatePortalZ(ld, out, hit.z); + players[consoleplayer].viewz += hit.z; // needs to be done here because otherwise the renderer will not catch the change. + P_TranslatePortalAngle(ld, out, hit.angle); + } + R_AddInterpolationPoint(hit); + } + if (port->mType == PORTT_LINKED) continue; + } + break; + } + + + + if (!portalcrossed) + { + // the move is ok, so link the thing into its new position + thing->UnlinkFromWorld(); + + oldpos = thing->Pos(); + oldsector = thing->Sector; + thing->floorz = tm.floorz; + thing->ceilingz = tm.ceilingz; + thing->dropoffz = tm.dropoffz; // killough 11/98: keep track of dropoffs + thing->floorpic = tm.floorpic; + thing->floorterrain = tm.floorterrain; + thing->floorsector = tm.floorsector; + thing->ceilingpic = tm.ceilingpic; + thing->ceilingsector = tm.ceilingsector; + thing->SetXY(x, y); + + thing->LinkToWorld(); + } if (thing->flags2 & MF2_FLOORCLIP) { @@ -2161,10 +2398,9 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, while (spechit.Pop(spec)) { line_t *ld = spec.line; - fixedvec3 oldrelpos = PosRelative(oldpos, ld, oldsector); // see if the line was crossed side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, ld); - oldside = P_PointOnLineSide(oldrelpos.x, oldrelpos.y, ld); + oldside = P_PointOnLineSide(spec.oldrefpos.x, spec.oldrefpos.y, ld); if (side != oldside && ld->special && !(thing->flags6 & MF6_NOTRIGGER)) { if (thing->player && (thing->player->cheats & CF_PREDICTING)) @@ -5344,7 +5580,7 @@ void PIT_FloorDrop(AActor *thing, FChangePosition *cpos) } if (thing->player && thing->player->mo == thing) { - thing->player->viewz += thing->Z() - oldz; + //thing->player->viewz += thing->Z() - oldz; } } diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 67c2303e7..057c4329c 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -152,7 +152,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, sector_t *front, *back; fixed_t fc, ff, bc, bf; - if (linedef->sidedef[1] == NULL) + if (linedef->backsector == NULL) { // single sided line open.range = 0; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index e5da17126..5fdff87e1 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -4045,7 +4045,8 @@ void P_SetupLevel (const char *lumpname, int position) times[16].Clock(); if (reloop) P_LoopSidedefs (false); - PO_Init (); // Initialize the polyobjs + PO_Init (); // Initialize the polyobjs + P_FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them. times[16].Unclock(); assert(sidetemp != NULL); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 0496ed1f5..9252abe1d 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1558,8 +1558,6 @@ void P_SpawnSpecials (void) } // [RH] Start running any open scripts on this map FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); - P_FinalizePortals(); - P_CreateLinkedPortals(); } // killough 2/28/98: @@ -1888,7 +1886,7 @@ static void P_SpawnScrollers(void) switch (special) { - register int s; + int s; case Scroll_Ceiling: { @@ -2420,7 +2418,7 @@ static void P_SpawnPushers () { int i; line_t *l = lines; - register int s; + int s; for (i = 0; i < numlines; i++, l++) { diff --git a/src/p_tick.cpp b/src/p_tick.cpp index 29b2cd4ad..4020bcebe 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -112,6 +112,7 @@ void P_Ticker (void) S_ResumeSound (false); P_ResetSightCounters (false); + R_ClearInterpolationPath(); // Since things will be moving, it's okay to interpolate them in the renderer. r_NoInterpolate = false; diff --git a/src/portal.cpp b/src/portal.cpp index 2a920f74c..cd501513a 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -323,6 +323,12 @@ void P_UpdatePortal(FLinePortal *port) // Portal has no destination: switch it off port->mFlags = 0; } + else if ((port->mOrigin->backsector == NULL && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ)) || + (port->mDestination->backsector == NULL && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ))) + { + // disable teleporting capability if a portal is or links to a one-sided wall (unless part of a polyobject.) + port->mFlags = PORTF_VISIBLE; + } else if (port->mDestination->getPortalDestination() != port->mOrigin) { //portal doesn't link back. This will be a simple teleporter portal. @@ -387,6 +393,7 @@ void P_FinalizePortals() } P_CollectLinkedPortals(); BuildBlockmap(); + P_CreateLinkedPortals(); } //============================================================================ diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm index 498498d94..07e85281b 100644 --- a/src/posix/cocoa/i_system.mm +++ b/src/posix/cocoa/i_system.mm @@ -208,12 +208,12 @@ void I_PrintStr(const char* const message) else if (0x1d == *srcp || 0x1f == *srcp) // Opening and closing bar character { *dstp++ = '-'; - *srcp++; + ++srcp; } else if (0x1e == *srcp) // Middle bar character { *dstp++ = '='; - *srcp++; + ++srcp; } else { diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm index e952d22d6..b990b9b33 100644 --- a/src/posix/cocoa/st_console.mm +++ b/src/posix/cocoa/st_console.mm @@ -213,7 +213,7 @@ void FConsoleWindow::AddText(const char* message) if (TEXTCOLOR_ESCAPE == *message) { const BYTE* colorID = reinterpret_cast(message) + 1; - if ('\0' == colorID) + if ('\0' == *colorID) { break; } diff --git a/src/r_defs.h b/src/r_defs.h index 34ba653e6..088d253d1 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1401,7 +1401,8 @@ inline void AActor::ClearInterpolation() PrevY = Y(); PrevZ = Z(); PrevAngle = angle; - PrevPortalGroup = Sector->PortalGroup; + if (Sector) PrevPortalGroup = Sector->PortalGroup; + else PrevPortalGroup = 0; } diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 628310fce..0c23064af 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -81,6 +81,7 @@ static TArray PastViewers; static FRandom pr_torchflicker ("TorchFlicker"); static FRandom pr_hom; static bool NoInterpolateView; +static TArray InterpolationPath; // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -574,6 +575,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi // frac = tf; if (NoInterpolateView) { + InterpolationPath.Clear(); NoInterpolateView = false; iview->oviewx = iview->nviewx; iview->oviewy = iview->nviewy; @@ -583,10 +585,76 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi } int oldgroup = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector->PortalGroup; int newgroup = R_PointInSubsector(iview->nviewx, iview->nviewy)->sector->PortalGroup; - fixedvec2 disp = Displacements.getOffset(oldgroup, newgroup); - viewx = iview->oviewx + FixedMul (frac, iview->nviewx - iview->oviewx - disp.x); - viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy - disp.y); - viewz = iview->oviewz + FixedMul (frac, iview->nviewz - iview->oviewz); + + fixed_t oviewangle = iview->oviewangle; + fixed_t nviewangle = iview->nviewangle; + if ((iview->oviewx != iview->nviewx || iview->oviewy != iview->nviewy) && InterpolationPath.Size() > 0) + { + viewx = iview->nviewx; + viewy = iview->nviewy; + viewz = iview->nviewz; + + // Interpolating through line portals is a messy affair. + // What needs be done is to store the portal transitions of the camera actor as waypoints + // and then find out on which part of the path the current view lies. + // Needless to say, this doesn't work for chasecam mode. + if (!r_showviewer) + { + fixed_t pathlen = 0; + fixed_t zdiff = 0; + fixed_t totalzdiff = 0; + angle_t adiff = 0; + angle_t totaladiff = 0; + fixed_t oviewz = iview->oviewz; + fixed_t nviewz = iview->nviewz; + fixedvec3a oldpos = { iview->oviewx, iview->oviewy, 0, 0 }; + fixedvec3a newpos = { iview->nviewx, iview->nviewy, 0, 0 }; + InterpolationPath.Push(newpos); // add this to the array to simplify the loops below + + for (unsigned i = 0; i < InterpolationPath.Size(); i += 2) + { + fixedvec3a &start = i == 0 ? oldpos : InterpolationPath[i - 1]; + fixedvec3a &end = InterpolationPath[i]; + pathlen += xs_CRoundToInt(TVector2(end.x - start.x, end.y - start.y).Length()); + totalzdiff += start.z; + totaladiff += start.angle; + } + fixed_t interpolatedlen = FixedMul(frac, pathlen); + + for (unsigned i = 0; i < InterpolationPath.Size(); i += 2) + { + fixedvec3a &start = i == 0 ? oldpos : InterpolationPath[i - 1]; + fixedvec3a &end = InterpolationPath[i]; + fixed_t fraglen = xs_CRoundToInt(TVector2(end.x - start.x, end.y - start.y).Length()); + zdiff += start.z; + adiff += start.angle; + if (fraglen <= interpolatedlen) + { + interpolatedlen -= fraglen; + } + else + { + fixed_t fragfrac = FixedDiv(interpolatedlen, fraglen); + oviewz += zdiff; + nviewz -= totalzdiff - zdiff; + oviewangle += adiff; + nviewangle -= totaladiff - adiff; + viewx = start.x + FixedMul(fragfrac, end.x - start.x); + viewy = start.y + FixedMul(fragfrac, end.y - start.y); + viewz = oviewz + FixedMul(frac, nviewz - oviewz); + break; + } + } + InterpolationPath.Pop(); + } + } + else + { + fixedvec2 disp = Displacements.getOffset(oldgroup, newgroup); + viewx = iview->oviewx + FixedMul(frac, iview->nviewx - iview->oviewx - disp.x); + viewy = iview->oviewy + FixedMul(frac, iview->nviewy - iview->oviewy - disp.y); + viewz = iview->oviewz + FixedMul(frac, iview->nviewz - iview->oviewz); + } if (player != NULL && !(player->cheats & CF_INTERPVIEW) && player - players == consoleplayer && @@ -602,7 +670,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi (!netgame || !cl_noprediction) && !LocalKeyboardTurner) { - viewangle = iview->nviewangle + (LocalViewAngle & 0xFFFF0000); + viewangle = nviewangle + (LocalViewAngle & 0xFFFF0000); fixed_t delta = player->centering ? 0 : -(signed)(LocalViewPitch & 0xFFFF0000); @@ -635,7 +703,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi else { viewpitch = iview->oviewpitch + FixedMul (frac, iview->nviewpitch - iview->oviewpitch); - viewangle = iview->oviewangle + FixedMul (frac, iview->nviewangle - iview->oviewangle); + viewangle = oviewangle + FixedMul (frac, nviewangle - oviewangle); } // Due to interpolation this is not necessarily the same as the sector the camera is in. @@ -678,6 +746,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi void R_ResetViewInterpolation () { + InterpolationPath.Clear(); NoInterpolateView = true; } @@ -718,6 +787,7 @@ static InterpolationViewer *FindPastViewer (AActor *actor) InterpolationViewer iview = { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; iview.ViewActor = actor; iview.otic = -1; + InterpolationPath.Clear(); return &PastViewers[PastViewers.Push (iview)]; } @@ -729,6 +799,7 @@ static InterpolationViewer *FindPastViewer (AActor *actor) void R_FreePastViewers () { + InterpolationPath.Clear(); PastViewers.Clear (); } @@ -742,6 +813,7 @@ void R_FreePastViewers () void R_ClearPastViewer (AActor *actor) { + InterpolationPath.Clear(); for (unsigned int i = 0; i < PastViewers.Size(); ++i) { if (PastViewers[i].ViewActor == actor) @@ -781,6 +853,7 @@ void R_RebuildViewInterpolation(player_t *player) iview->oviewz = iview->nviewz; iview->oviewpitch = iview->nviewpitch; iview->oviewangle = iview->nviewangle; + InterpolationPath.Clear(); } //========================================================================== @@ -794,6 +867,29 @@ bool R_GetViewInterpolationStatus() return NoInterpolateView; } + +//========================================================================== +// +// R_ClearInterpolationPath +// +//========================================================================== + +void R_ClearInterpolationPath() +{ + InterpolationPath.Clear(); +} + +//========================================================================== +// +// R_AddInterpolationPoint +// +//========================================================================== + +void R_AddInterpolationPoint(const fixedvec3a &vec) +{ + InterpolationPath.Push(vec); +} + //========================================================================== // // QuakePower diff --git a/src/r_utility.h b/src/r_utility.h index 10dcf5352..f8f91c1bc 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -63,11 +63,21 @@ inline angle_t R_PointToAnglePrecise (fixed_t viewx, fixed_t viewy, fixed_t x, f return xs_RoundToUInt(atan2(double(y-viewy), double(x-viewx)) * (ANGLE_180/M_PI)); } +// Used for interpolation waypoints. +struct fixedvec3a +{ + fixed_t x, y, z; + angle_t angle; +}; + + subsector_t *R_PointInSubsector (fixed_t x, fixed_t y); fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy); void R_ResetViewInterpolation (); void R_RebuildViewInterpolation(player_t *player); bool R_GetViewInterpolationStatus(); +void R_ClearInterpolationPath(); +void R_AddInterpolationPoint(const fixedvec3a &vec); void R_SetViewSize (int blocks); void R_SetFOV (float fov); float R_GetFOV (); diff --git a/src/tarray.h b/src/tarray.h index d62d75e28..63d693261 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -50,6 +50,23 @@ class FArchive; + +template class TIterator +{ +public: + TIterator(T* ptr = nullptr) { m_ptr = ptr; } + bool operator==(const TIterator& other) const { return (m_ptr == other.m_ptr); } + bool operator!=(const TIterator& other) const { return (m_ptr != other.m_ptr); } + TIterator &operator++() { ++m_ptr; return (*this); } + T &operator*() { return *m_ptr; } + const T &operator*() const { return *m_ptr; } + T* operator->() { return m_ptr; } + +protected: + T* m_ptr; +}; + + // TArray ------------------------------------------------------------------- // Must match TArray's layout. @@ -68,6 +85,32 @@ class TArray template friend FArchive &operator<< (FArchive &arc, TArray &self); public: + + typedef TIterator iterator; + typedef TIterator const_iterator; + + iterator begin() + { + return &Array[0]; + } + + iterator end() + { + return &Array[Count]; + } + + const_iterator cbegin() const + { + return &Array[0]; + } + + const_iterator cend() const + { + return &Array[Count]; + } + + + //////// // This is a dummy constructor that does nothing. The purpose of this // is so you can create a global TArray in the data segment that gets diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 62640e7e1..daa824264 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -841,7 +841,7 @@ class FxFlopFunctionCall : public FxExpression public: - FxFlopFunctionCall(int index, FArgumentList *args, const FScriptPosition &pos); + FxFlopFunctionCall(size_t index, FArgumentList *args, const FScriptPosition &pos); ~FxFlopFunctionCall(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 2ac41f7a8..b5b35a770 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3176,7 +3176,7 @@ FxFunctionCall::~FxFunctionCall() FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) { - for (int i = 0; i < countof(FxFlops); ++i) + for (size_t i = 0; i < countof(FxFlops); ++i) { if (MethodName == FxFlops[i].Name) { @@ -3514,10 +3514,10 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) // //========================================================================== -FxFlopFunctionCall::FxFlopFunctionCall(int index, FArgumentList *args, const FScriptPosition &pos) +FxFlopFunctionCall::FxFlopFunctionCall(size_t index, FArgumentList *args, const FScriptPosition &pos) : FxExpression(pos) { - assert(index >= 0 && index < countof(FxFlops) && "FLOP index out of range"); + assert(index < countof(FxFlops) && "FLOP index out of range"); Index = index; ArgList = args; }