diff --git a/src/common/filesystem/source/file_zip.cpp b/src/common/filesystem/source/file_zip.cpp index 9f10d00a730..8351b714648 100644 --- a/src/common/filesystem/source/file_zip.cpp +++ b/src/common/filesystem/source/file_zip.cpp @@ -35,6 +35,7 @@ #include #include +#include #include "w_zip.h" #include "ancientzip.h" #include "resourcefile.h" diff --git a/src/common/rendering/hwrenderer/data/hw_cvars.h b/src/common/rendering/hwrenderer/data/hw_cvars.h index cf23649799c..2f90807eb7e 100644 --- a/src/common/rendering/hwrenderer/data/hw_cvars.h +++ b/src/common/rendering/hwrenderer/data/hw_cvars.h @@ -54,3 +54,11 @@ EXTERN_CVAR(Int, gl_shadowmap_filter) EXTERN_CVAR(Bool, gl_brightfog) EXTERN_CVAR(Bool, gl_lightadditivesurfaces) EXTERN_CVAR(Bool, gl_notexturefill) + +EXTERN_CVAR(Bool, r_isocam) +EXTERN_CVAR(Int, r_isoviewpoint) +EXTERN_CVAR(Float, r_iso_camdist) +EXTERN_CVAR(Float, r_iso_dist) +EXTERN_CVAR(Float, r_iso_pitch) +EXTERN_CVAR(Bool, r_drawplayersprites) +EXTERN_CVAR(Bool, r_orthographic) diff --git a/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp b/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp index c51ce2ee901..9d4b834a4ba 100644 --- a/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp +++ b/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp @@ -146,11 +146,27 @@ float VREyeInfo::getShift() const return vr_swap_eyes ? -res : res; } -VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio) const +VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio, bool isocam) const { VSMatrix result; - if (mShiftFactor == 0) + if (isocam) // 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 fW = fH * aspectRatio * mScaleFactor; + double left = -fW; + double right = fW; + double bottom = -fH; + double top = fH; + + VSMatrix fmat(1); + fmat.ortho((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar); + return fmat; + } + else if (mShiftFactor == 0) { float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio))); result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar()); diff --git a/src/common/rendering/hwrenderer/data/hw_vrmodes.h b/src/common/rendering/hwrenderer/data/hw_vrmodes.h index 26c9fd211ee..f490a7593ae 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) const; + VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio, bool isocam) const; DVector3 GetViewShift(float yaw) const; private: float getShift() const; diff --git a/src/playsim/d_player.h b/src/playsim/d_player.h index 675813873e6..02432ba6f3d 100644 --- a/src/playsim/d_player.h +++ b/src/playsim/d_player.h @@ -324,6 +324,9 @@ class player_t // 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; + int isoyaw = 225; // degrees bool centering = false; uint8_t turnticks = 0; diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index a4e2c648569..7730ef14002 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -270,6 +270,8 @@ 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; attackdown = p.attackdown; @@ -1635,6 +1637,8 @@ void player_t::Serialize(FSerializer &arc) ("deltaviewheight", deltaviewheight) ("bob", bob) ("vel", Vel) + ("isoviewpoint", isoviewpoint) + ("isoyaw", isoyaw) ("centering", centering) ("health", health) ("inventorytics", inventorytics) @@ -1742,6 +1746,8 @@ 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) DEFINE_FIELD_X(PlayerInfo, player_t, attackdown) diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp index e80d7ef669a..71a897b0473 100644 --- a/src/rendering/hwrenderer/hw_entrypoint.cpp +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -162,8 +162,37 @@ 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) - // Stereo mode specific perspective projection - di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio); + // Switch viewpoint for isometric camera + if(r_isocam && 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 + 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.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); + } + else // Regular first-person viewpoint + { + vp.showviewer = false; + r_drawplayersprites = true; // Restore first-person hands/weapons + // Stereo mode specific perspective projection + di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio, false); + } // Stereo mode specific viewpoint adjustment vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees()); di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false); diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 09db1101d1b..d2a29fb68b8 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -477,7 +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); mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees()); + if(r_isocam) mat.Translate(0.0, zcenter - z2, 0.0); } mat.Translate(-center.X, -center.Z, -center.Y); // retreat from sprite center @@ -900,6 +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; FTextureID patch; // [ZZ] add direct picnum override if (isPicnumOverride) @@ -1019,6 +1022,20 @@ 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 + { + float signX = 1.0; + float signY = 1.0; + if(viewvecX < 0) signX = -1.0; + if(viewvecY < 0) signY = -1.0; + if(viewvecX == 0) signX = 0.0; + if(viewvecY == 0) signY = 0.0; + + x1 -= signX * thing->radius; + x2 -= signX * thing->radius; + y1 -= signY * thing->radius; + y2 -= signY * thing->radius; + } break; } case RF_FLATSPRITE: @@ -1059,6 +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 (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 4daf7af7cc2..7df9280bdde 100644 --- a/src/rendering/r_utility.cpp +++ b/src/rendering/r_utility.cpp @@ -101,6 +101,35 @@ CVAR (Bool, r_deathcamera, false, CVAR_ARCHIVE) CVAR (Int, r_clearbuffer, 0, 0) 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.") +{ + if (self < 0.f) + self = 0.f; + else if (self > 89.f) + self = 89.f; +} +CUSTOM_CVAR(Float, r_iso_camdist, 1000.0f, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT) +{ + // Keep this large to avoid texture clipping, not used if r_orthographic is false + 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.") +{ + if (self < 0) + self = 0; + else if (self > 9) + self = 9; +} +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") +{ + if (self < 0.f) + self = 0.f; + else if (self > 1000.f) + self = 1000.f; +} CUSTOM_CVAR(Float, r_quakeintensity, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (self < 0.f) self = 0.f; diff --git a/wadsrc/static/zscript/actors/player/player.zs b/wadsrc/static/zscript/actors/player/player.zs index 235b97c8daa..b010643ebb5 100644 --- a/wadsrc/static/zscript/actors/player/player.zs +++ b/wadsrc/static/zscript/actors/player/player.zs @@ -2744,6 +2744,8 @@ 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; native bool attackdown;