Adding isometric camera mode with orthographic projection to current state of master branch of GZDoom.

This commit is contained in:
Dileep V. Reddy 2024-01-15 17:27:39 -07:00 committed by Rachael Alexanderson
parent 5925a6a8c5
commit 08b03e6b19
10 changed files with 117 additions and 5 deletions

View file

@ -35,6 +35,7 @@
#include <time.h> #include <time.h>
#include <stdexcept> #include <stdexcept>
#include <cstdint>
#include "w_zip.h" #include "w_zip.h"
#include "ancientzip.h" #include "ancientzip.h"
#include "resourcefile.h" #include "resourcefile.h"

View file

@ -54,3 +54,11 @@ EXTERN_CVAR(Int, gl_shadowmap_filter)
EXTERN_CVAR(Bool, gl_brightfog) EXTERN_CVAR(Bool, gl_brightfog)
EXTERN_CVAR(Bool, gl_lightadditivesurfaces) EXTERN_CVAR(Bool, gl_lightadditivesurfaces)
EXTERN_CVAR(Bool, gl_notexturefill) 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)

View file

@ -146,11 +146,27 @@ float VREyeInfo::getShift() const
return vr_swap_eyes ? -res : res; 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; 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))); float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar()); result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar());

View file

@ -27,7 +27,7 @@ struct VREyeInfo
float mShiftFactor; float mShiftFactor;
float mScaleFactor; 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; DVector3 GetViewShift(float yaw) const;
private: private:
float getShift() const; float getShift() const;

View file

@ -324,6 +324,9 @@ public:
// This only represents the thrust that the player applies himself. // This only represents the thrust that the player applies himself.
// This avoids anomalies with such things as Boom ice and conveyors. // This avoids anomalies with such things as Boom ice and conveyors.
DVector2 Vel = { 0,0 }; 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; bool centering = false;
uint8_t turnticks = 0; uint8_t turnticks = 0;

View file

@ -270,6 +270,8 @@ void player_t::CopyFrom(player_t &p, bool copyPSP)
deltaviewheight = p.deltaviewheight; deltaviewheight = p.deltaviewheight;
bob = p.bob; bob = p.bob;
Vel = p.Vel; Vel = p.Vel;
isoviewpoint = p.isoviewpoint;
isoyaw = p.isoyaw;
centering = p.centering; centering = p.centering;
turnticks = p.turnticks; turnticks = p.turnticks;
attackdown = p.attackdown; attackdown = p.attackdown;
@ -1635,6 +1637,8 @@ void player_t::Serialize(FSerializer &arc)
("deltaviewheight", deltaviewheight) ("deltaviewheight", deltaviewheight)
("bob", bob) ("bob", bob)
("vel", Vel) ("vel", Vel)
("isoviewpoint", isoviewpoint)
("isoyaw", isoyaw)
("centering", centering) ("centering", centering)
("health", health) ("health", health)
("inventorytics", inventorytics) ("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, deltaviewheight)
DEFINE_FIELD_X(PlayerInfo, player_t, bob) DEFINE_FIELD_X(PlayerInfo, player_t, bob)
DEFINE_FIELD_X(PlayerInfo, player_t, Vel) 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, centering)
DEFINE_FIELD_X(PlayerInfo, player_t, turnticks) DEFINE_FIELD_X(PlayerInfo, player_t, turnticks)
DEFINE_FIELD_X(PlayerInfo, player_t, attackdown) DEFINE_FIELD_X(PlayerInfo, player_t, attackdown)

View file

@ -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) 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 // Switch viewpoint for isometric camera
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio); 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 // Stereo mode specific viewpoint adjustment
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees()); vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees());
di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false); di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false);

View file

@ -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 // 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 // triangle strip and with direction orthogonal to where the player is looking
// in the x/y plane. // 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()); 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 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; bool mirror = false;
DAngle ang = (thingpos - vp.Pos).Angle(); DAngle ang = (thingpos - vp.Pos).Angle();
if(r_isocam) ang = vp.Angles.Yaw;
FTextureID patch; FTextureID patch;
// [ZZ] add direct picnum override // [ZZ] add direct picnum override
if (isPicnumOverride) if (isPicnumOverride)
@ -1019,6 +1022,20 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
x2 = x - viewvecY*rightfac; x2 = x - viewvecY*rightfac;
y1 = y + viewvecX*leftfac; y1 = y + viewvecX*leftfac;
y2 = y + viewvecX*rightfac; 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; break;
} }
case RF_FLATSPRITE: 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); 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. if (isSpriteShadow) depth += 1.f/65536.f; // always sort shadows behind the sprite.
// light calculation // light calculation

View file

@ -101,6 +101,35 @@ CVAR (Bool, r_deathcamera, false, CVAR_ARCHIVE)
CVAR (Int, r_clearbuffer, 0, 0) CVAR (Int, r_clearbuffer, 0, 0)
CVAR (Bool, r_drawvoxels, true, 0) CVAR (Bool, r_drawvoxels, true, 0)
CVAR (Bool, r_drawplayersprites, true, 0) // [RH] Draw player sprites? 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) CUSTOM_CVAR(Float, r_quakeintensity, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{ {
if (self < 0.f) self = 0.f; if (self < 0.f) self = 0.f;

View file

@ -2744,6 +2744,8 @@ struct PlayerInfo native play // self is what internally is known as player_t
native double deltaviewheight; native double deltaviewheight;
native double bob; native double bob;
native vector2 vel; native vector2 vel;
native int isoviewpoint;
native int isoyaw;
native bool centering; native bool centering;
native uint8 turnticks; native uint8 turnticks;
native bool attackdown; native bool attackdown;