diff --git a/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp b/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp index 9d4b834a4b..4534829aba 100644 --- a/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp +++ b/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp @@ -146,16 +146,16 @@ float VREyeInfo::getShift() const return vr_swap_eyes ? -res : res; } -VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio, bool isocam) const +VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const { VSMatrix result; - if (isocam) // Orthographic projection for isometric viewpoint + if (iso_ortho) // Orthographic projection for isometric viewpoint { double zNear = -1.0; // screen->GetZNear(); double zFar = screen->GetZFar(); - double fH = r_iso_dist * tan(DEG2RAD(fov) / 2) / fovRatio; + double fH = tan(DEG2RAD(fov) / 2) / fovRatio; double fW = fH * aspectRatio * mScaleFactor; double left = -fW; double right = fW; diff --git a/src/common/rendering/hwrenderer/data/hw_vrmodes.h b/src/common/rendering/hwrenderer/data/hw_vrmodes.h index f490a7593a..9892815201 100644 --- a/src/common/rendering/hwrenderer/data/hw_vrmodes.h +++ b/src/common/rendering/hwrenderer/data/hw_vrmodes.h @@ -27,7 +27,7 @@ struct VREyeInfo float mShiftFactor; float mScaleFactor; - VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio, bool isocam) const; + VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const; DVector3 GetViewShift(float yaw) const; private: float getShift() const; diff --git a/src/g_level.cpp b/src/g_level.cpp index ff42656dac..cad0a9f867 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1803,6 +1803,8 @@ void FLevelLocals::Init() flags3 = 0; ImpactDecalCount = 0; frozenstate = 0; + isocam_pitch = 30.f; + iso_dist = 300.f; info = FindLevelInfo (MapName.GetChars()); @@ -1833,6 +1835,12 @@ void FLevelLocals::Init() if (info->gravity == DBL_MAX) gravity = 0; else gravity = info->gravity * 35/TICRATE; } + if (info->isocam_pitch < 0.f) isocam_pitch = 0.f; + else if (info->isocam_pitch > 89.f) isocam_pitch = 89.f; + else isocam_pitch = info->isocam_pitch; + if (info->iso_dist < 1.f) iso_dist = 1.f; + if (info->iso_dist > 1000.f) iso_dist = 1000.f; + else iso_dist = info->iso_dist; if (info->aircontrol != 0.f) { aircontrol = info->aircontrol; diff --git a/src/g_levellocals.h b/src/g_levellocals.h index cf63f81b2d..799915d4cc 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -664,6 +664,8 @@ public: double airfriction; int airsupply; int DefaultEnvironment; // Default sound environment. + float isocam_pitch; + float iso_dist; DSeqNode *SequenceListHead; @@ -753,6 +755,17 @@ public: return !(flags & LEVEL_FREELOOK_NO); } + //========================================================================== + // + // + //========================================================================== + + bool IsIsometricMode() const + { + return (flags3 & LEVEL3_ISOMETRICMODE); + // What to do about multiplayer flags? Add a dmflags3 bit? + } + node_t *HeadNode() const { return nodes.Size() == 0 ? nullptr : &nodes[nodes.Size() - 1]; diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index dfe90b2c95..f79f0a5dbb 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -295,6 +295,8 @@ void level_info_t::Reset() outsidefogdensity = 0; skyfog = 0; pixelstretch = 1.2f; + isocam_pitch = 30.f; + iso_dist = 300.f; specialactions.Clear(); DefaultEnvironment = 0; @@ -1216,6 +1218,20 @@ DEFINE_MAP_OPTION(gravity, true) info->gravity = parse.sc.Float; } +DEFINE_MAP_OPTION(isocam_pitch, true) +{ + parse.ParseAssign(); + parse.sc.MustGetFloat(); + info->isocam_pitch = parse.sc.Float; +} + +DEFINE_MAP_OPTION(iso_dist, true) +{ + parse.ParseAssign(); + parse.sc.MustGetFloat(); + info->iso_dist = parse.sc.Float; +} + DEFINE_MAP_OPTION(nogravity, true) { info->gravity = DBL_MAX; @@ -1819,6 +1835,9 @@ MapFlagHandlers[] = { "disableskyboxao", MITYPE_CLRFLAG3, LEVEL3_SKYBOXAO, 0 }, { "avoidmelee", MITYPE_SETFLAG3, LEVEL3_AVOIDMELEE, 0 }, { "attenuatelights", MITYPE_SETFLAG3, LEVEL3_ATTENUATE, 0 }, + { "isometricmode", MITYPE_SETFLAG3, LEVEL3_ISOMETRICMODE, 0 }, + { "orthographic", MITYPE_SETFLAG3, LEVEL3_ORTHOGRAPHIC, 0 }, + { "isometricsprites", MITYPE_SETFLAG3, LEVEL3_ISOMETRICSPRITES, 0 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "nopassover", MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ, 0 }, { "passover", MITYPE_CLRCOMPATFLAG, COMPATF_NO_PASSMOBJ, 0 }, diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index b56d3b6329..1bd379b173 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -270,6 +270,10 @@ enum ELevelFlags : unsigned int LEVEL3_AVOIDMELEE = 0x00020000, // global flag needed for proper MBF support. LEVEL3_NOJUMPDOWN = 0x00040000, // only for MBF21. Inverse of MBF's dog_jumping flag. LEVEL3_LIGHTCREATED = 0x00080000, // a light had been created in the last frame + + LEVEL3_ISOMETRICMODE = 0x00100000, // render map in isometric camera mode + LEVEL3_ORTHOGRAPHIC = 0x00200000, // render with orthographic projection (only in isometric camera mode) + LEVEL3_ISOMETRICSPRITES = 0x00400000, // displace isometrically drawn sprites towards isometric camera }; @@ -376,6 +380,9 @@ struct level_info_t int skyfog; float pixelstretch; + float isocam_pitch; + float iso_dist; + // Redirection: If any player is carrying the specified item, then // you go to the RedirectMap instead of this one. FName RedirectType; diff --git a/src/playsim/d_player.h b/src/playsim/d_player.h index 02432ba6f3..e7c703ad19 100644 --- a/src/playsim/d_player.h +++ b/src/playsim/d_player.h @@ -324,8 +324,7 @@ public: // This only represents the thrust that the player applies himself. // This avoids anomalies with such things as Boom ice and conveyors. DVector2 Vel = { 0,0 }; - // Used by isometric camera (% 8 cardinal directions) (See RenderViewpoint() in src/rendering/hwrenderer/hw_entrypoint.cpp) - int isoviewpoint = 1; + // Used by isometric camera (See RenderViewpoint() in src/rendering/hwrenderer/hw_entrypoint.cpp) int isoyaw = 225; // degrees bool centering = false; diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 7730ef1400..121db3f643 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -270,7 +270,6 @@ void player_t::CopyFrom(player_t &p, bool copyPSP) deltaviewheight = p.deltaviewheight; bob = p.bob; Vel = p.Vel; - isoviewpoint = p.isoviewpoint; isoyaw = p.isoyaw; centering = p.centering; turnticks = p.turnticks; @@ -1637,7 +1636,6 @@ void player_t::Serialize(FSerializer &arc) ("deltaviewheight", deltaviewheight) ("bob", bob) ("vel", Vel) - ("isoviewpoint", isoviewpoint) ("isoyaw", isoyaw) ("centering", centering) ("health", health) @@ -1746,7 +1744,6 @@ DEFINE_FIELD_X(PlayerInfo, player_t, viewheight) DEFINE_FIELD_X(PlayerInfo, player_t, deltaviewheight) DEFINE_FIELD_X(PlayerInfo, player_t, bob) DEFINE_FIELD_X(PlayerInfo, player_t, Vel) -DEFINE_FIELD_X(PlayerInfo, player_t, isoviewpoint) DEFINE_FIELD_X(PlayerInfo, player_t, isoyaw) DEFINE_FIELD_X(PlayerInfo, player_t, centering) DEFINE_FIELD_X(PlayerInfo, player_t, turnticks) diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp index 71a897b047..f11c34f787 100644 --- a/src/rendering/hwrenderer/hw_entrypoint.cpp +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -163,28 +163,29 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou di->Viewpoint.FieldOfView = DAngle::fromDeg(fov); // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint) // Switch viewpoint for isometric camera - if(r_isocam && camera->player != NULL) + if((r_isocam || (camera->Level->flags3 & LEVEL3_ISOMETRICMODE)) && camera->player != NULL) { - float camdist = r_iso_dist; - if (r_orthographic) camdist = r_iso_camdist; - float camheight = camdist*FAngle::fromDeg(r_iso_pitch).Tan(); - camheight -= 0.5*camera->player->viewheight; - int myisoviewpoint = 1; - if (r_isoviewpoint > 0 && r_isoviewpoint < 9) myisoviewpoint = r_isoviewpoint - 1; - else myisoviewpoint = camera->player->isoviewpoint % 8; - if (myisoviewpoint < 0) myisoviewpoint = 0; - if (r_isoviewpoint < 9) camera->player->isoyaw = 45.0 * myisoviewpoint; // The eight cardinal directions + float camdist = camera->Level->iso_dist; + float isocam_pitch = camera->Level->isocam_pitch; + if (r_isoviewpoint > 0) + { + isocam_pitch = r_iso_pitch; + camdist = r_iso_dist; + camera->player->isoyaw = 45.0 * (r_isoviewpoint - 1); // The eight cardinal directions + } + float inv_iso_dist = 1.0f/camdist; // camdist can change in next line + if (r_orthographic || (camera->Level->flags3 & LEVEL3_ORTHOGRAPHIC)) camdist = r_iso_camdist; vp.Pos.X -= camdist * DAngle::fromDeg(camera->player->isoyaw).Cos(); vp.Pos.Y -= camdist * DAngle::fromDeg(camera->player->isoyaw).Sin(); - vp.Pos.Z += camheight; - vp.HWAngles.Pitch = FAngle::fromDeg(r_iso_pitch); - vp.Angles.Pitch = DAngle::fromDeg(r_iso_pitch); + vp.Pos.Z += camdist * FAngle::fromDeg(isocam_pitch).Tan() - 0.5 * camera->player->viewheight; + vp.HWAngles.Pitch = FAngle::fromDeg(isocam_pitch); + vp.Angles.Pitch = DAngle::fromDeg(isocam_pitch); vp.Angles.Yaw = DAngle::fromDeg(camera->player->isoyaw); vp.Angles.Roll = DAngle::fromDeg(0); vp.showviewer = true; // Draw player sprite r_drawplayersprites = false; // Don't draw first-person hands/weapons // Stereo mode specific perspective projection - di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio, r_orthographic); + di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio * inv_iso_dist, r_orthographic || (camera->Level->flags3 & LEVEL3_ORTHOGRAPHIC)); } else // Regular first-person viewpoint { diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index d2a29fb68b..2885a6231f 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -477,9 +477,9 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) // Rotate the sprite about the vector starting at the center of the sprite // triangle strip and with direction orthogonal to where the player is looking // in the x/y plane. - if(r_isocam) mat.Translate(0.0, z2 - zcenter, 0.0); + if(r_isocam || (di->Level->flags3 & LEVEL3_ISOMETRICMODE)) mat.Translate(0.0, z2 - zcenter, 0.0); mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees()); - if(r_isocam) mat.Translate(0.0, zcenter - z2, 0.0); + if(r_isocam || (di->Level->flags3 & LEVEL3_ISOMETRICMODE)) mat.Translate(0.0, zcenter - z2, 0.0); } mat.Translate(-center.X, -center.Z, -center.Y); // retreat from sprite center @@ -902,7 +902,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t { bool mirror = false; DAngle ang = (thingpos - vp.Pos).Angle(); - if(r_isocam) ang = vp.Angles.Yaw; + if(r_isocam || (di->Level->flags3 & LEVEL3_ISOMETRICMODE)) ang = vp.Angles.Yaw; FTextureID patch; // [ZZ] add direct picnum override if (isPicnumOverride) @@ -1022,7 +1022,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t x2 = x - viewvecY*rightfac; y1 = y + viewvecX*leftfac; y2 = y + viewvecX*rightfac; - if(thing->radius > 0 && r_isocam) // If sprites are drawn from an isometric perspective + if(di->Level->flags3 & LEVEL3_ISOMETRICSPRITES && (r_isocam || (di->Level->flags3 & LEVEL3_ISOMETRICMODE))) // If sprites are drawn from an isometric perspective { float signX = 1.0; float signY = 1.0; @@ -1076,7 +1076,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t } depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin); - if(r_isocam) depth = depth * vp.Angles.Pitch.Cos() - vp.Angles.Pitch.Sin() * z2; // Helps with stacking actors with small xy offsets + if(r_isocam || (di->Level->flags3 & LEVEL3_ISOMETRICMODE)) depth = depth * vp.PitchCos - vp.PitchSin * z2; // Helps with stacking actors with small xy offsets if (isSpriteShadow) depth += 1.f/65536.f; // always sort shadows behind the sprite. // light calculation diff --git a/src/rendering/r_utility.cpp b/src/rendering/r_utility.cpp index 7df9280bdd..216500feb4 100644 --- a/src/rendering/r_utility.cpp +++ b/src/rendering/r_utility.cpp @@ -103,7 +103,7 @@ CVAR (Bool, r_drawvoxels, true, 0) CVAR (Bool, r_drawplayersprites, true, 0) // [RH] Draw player sprites? CVARD (Bool, r_isocam, false, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "render from isometric viewpoint.") CVARD (Bool, r_orthographic, true, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "render orthographic projection. Only used with r_isocam") -CUSTOM_CVARD(Float, r_iso_pitch, 30.0f, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "pitch for isometric camera: 0 to 89 degrees.") +CUSTOM_CVARD(Float, r_iso_pitch, 30.0f, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "pitch for isometric camera: 0 to 89 degrees. Used only if r_isoviewpoint > 0.") { if (self < 0.f) self = 0.f; @@ -116,14 +116,14 @@ CUSTOM_CVAR(Float, r_iso_camdist, 1000.0f, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR if (self < 1000.f) self = 1000.f; } -CUSTOM_CVARD(Int, r_isoviewpoint, 0, CVAR_ARCHIVE, "Isometric viewpoint angle. 1 to 8 for cardinal directions. 0 for ignore and use player->isoviewpoint. 9 for continuous use player->isoyaw.") +CUSTOM_CVARD(Int, r_isoviewpoint, 0, CVAR_ARCHIVE, "Isometric viewpoint angle. 1 to 8 for cardinal directions using r_iso_pitch and r_iso_dist. 0 for ignore and use player->isoyaw, level->isocam_pitch and level->iso_dist (from mapinfo).") { if (self < 0) self = 0; - else if (self > 9) - self = 9; + else if (self > 8) + self = 8; } -CUSTOM_CVARD(Float, r_iso_dist, 300.0, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "how far the isometric camera (r_isocam) is in the XY plane") +CUSTOM_CVARD(Float, r_iso_dist, 300.0, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "how far the isometric camera (r_isocam) is in the XY plane. Used only if r_isoviewpoint > 0.") { if (self < 0.f) self = 0.f; @@ -182,6 +182,8 @@ FRenderViewpoint::FRenderViewpoint() Sin = 0.0; TanCos = 0.0; TanSin = 0.0; + PitchCos = 0.0; + PitchSin = 0.0; camera = nullptr; sector = nullptr; FieldOfView = DAngle::fromDeg(90.); // Angles in the SCREENWIDTH wide window @@ -659,6 +661,9 @@ void FRenderViewpoint::SetViewAngle (const FViewWindow &viewwindow) TanSin = viewwindow.FocalTangent * Sin; TanCos = viewwindow.FocalTangent * Cos; + PitchSin = Angles.Pitch.Sin(); + PitchCos = Angles.Pitch.Cos(); + DVector2 v = Angles.Yaw.ToVector(); ViewVector.X = v.X; ViewVector.Y = v.Y; diff --git a/src/rendering/r_utility.h b/src/rendering/r_utility.h index 7ba6e738cf..c5f87eef53 100644 --- a/src/rendering/r_utility.h +++ b/src/rendering/r_utility.h @@ -33,6 +33,8 @@ struct FRenderViewpoint double Sin; // sin(Angles.Yaw) double TanCos; // FocalTangent * cos(Angles.Yaw) double TanSin; // FocalTangent * sin(Angles.Yaw) + double PitchCos; // cos(Angles.Pitch) + double PitchSin; // sin(Angles.Pitch) AActor *camera; // camera actor sector_t *sector; // [RH] keep track of sector viewing from diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index 450d4552a7..6a43dde5aa 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -1694,6 +1694,22 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) ACTION_RETURN_BOOL(self->IsFreelookAllowed()); } + //========================================================================== + // + // + //========================================================================== + + static int IsIsometricMode(FLevelLocals *self) + { + return self->IsIsometricMode(); + } + + DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, IsIsometricMode, IsIsometricMode) + { + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + ACTION_RETURN_BOOL(self->IsIsometricMode()); + } + //========================================================================== // // ZScript counterpart to ACS ChangeSky, uses TextureIDs diff --git a/wadsrc/static/zscript/actors/player/player.zs b/wadsrc/static/zscript/actors/player/player.zs index b010643ebb..6c687210bc 100644 --- a/wadsrc/static/zscript/actors/player/player.zs +++ b/wadsrc/static/zscript/actors/player/player.zs @@ -2744,7 +2744,6 @@ struct PlayerInfo native play // self is what internally is known as player_t native double deltaviewheight; native double bob; native vector2 vel; - native int isoviewpoint; native int isoyaw; native bool centering; native uint8 turnticks; diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs index 5a99de9e62..d2bd8a21ac 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -490,6 +490,7 @@ struct LevelLocals native native bool IsJumpingAllowed() const; native bool IsCrouchingAllowed() const; native bool IsFreelookAllowed() const; + native bool IsIsometricMode() const; native void StartIntermission(Name type, int state) const; native play SpotState GetSpotState(bool create = true); native int FindUniqueTid(int start = 0, int limit = 0);