mirror of https://github.com/AxioDL/metaforce.git
397 lines
14 KiB
C++
397 lines
14 KiB
C++
#pragma once
|
|
|
|
#include "Runtime/ConsoleVariables/CVar.hpp"
|
|
#include "Runtime/Graphics/CLight.hpp"
|
|
#include "Runtime/Graphics/CTevCombiners.hpp"
|
|
#include "Runtime/Graphics/GX.hpp"
|
|
#include "Runtime/RetroTypes.hpp"
|
|
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <vector>
|
|
|
|
#include <zeus/CColor.hpp>
|
|
#include <zeus/CTransform.hpp>
|
|
#include <zeus/CVector2f.hpp>
|
|
#include <zeus/CVector2i.hpp>
|
|
|
|
#include <aurora/gfx.hpp>
|
|
#include <optick.h>
|
|
|
|
using frame_clock = std::chrono::high_resolution_clock;
|
|
|
|
namespace metaforce {
|
|
class CTexture;
|
|
extern CVar* g_disableLighting;
|
|
class CTimeProvider;
|
|
|
|
enum class ERglCullMode : std::underlying_type_t<GX::CullMode> {
|
|
None = GX::CULL_NONE,
|
|
Front = GX::CULL_FRONT,
|
|
Back = GX::CULL_BACK,
|
|
All = GX::CULL_ALL,
|
|
};
|
|
|
|
enum class ERglBlendMode : std::underlying_type_t<GX::BlendMode> {
|
|
None = GX::BM_NONE,
|
|
Blend = GX::BM_BLEND,
|
|
Logic = GX::BM_LOGIC,
|
|
Subtract = GX::BM_SUBTRACT,
|
|
Max = GX::MAX_BLENDMODE,
|
|
};
|
|
|
|
enum class ERglBlendFactor : std::underlying_type_t<GX::BlendFactor> {
|
|
Zero = GX::BL_ZERO,
|
|
One = GX::BL_ONE,
|
|
SrcColor = GX::BL_SRCCLR,
|
|
InvSrcColor = GX::BL_INVSRCCLR,
|
|
SrcAlpha = GX::BL_SRCALPHA,
|
|
InvSrcAlpha = GX::BL_INVSRCALPHA,
|
|
DstAlpha = GX::BL_DSTALPHA,
|
|
InvDstAlpha = GX::BL_INVDSTALPHA,
|
|
DstColor = GX::BL_DSTCLR,
|
|
InvDstColor = GX::BL_INVDSTCLR,
|
|
};
|
|
|
|
enum class ERglLogicOp : std::underlying_type_t<GX::LogicOp> {
|
|
Clear = GX::LO_CLEAR,
|
|
And = GX::LO_AND,
|
|
RevAnd = GX::LO_REVAND,
|
|
Copy = GX::LO_COPY,
|
|
InvAnd = GX::LO_INVAND,
|
|
NoOp = GX::LO_NOOP,
|
|
Xor = GX::LO_XOR,
|
|
Or = GX::LO_OR,
|
|
Nor = GX::LO_NOR,
|
|
Equiv = GX::LO_EQUIV,
|
|
Inv = GX::LO_INV,
|
|
RevOr = GX::LO_REVOR,
|
|
InvCopy = GX::LO_INVCOPY,
|
|
InvOr = GX::LO_INVOR,
|
|
NAnd = GX::LO_NAND,
|
|
Set = GX::LO_SET,
|
|
};
|
|
|
|
enum class ERglAlphaFunc : std::underlying_type_t<GX::Compare> {
|
|
Never = GX::NEVER,
|
|
Less = GX::LESS,
|
|
Equal = GX::EQUAL,
|
|
LEqual = GX::LEQUAL,
|
|
Greater = GX::GREATER,
|
|
NEqual = GX::NEQUAL,
|
|
GEqual = GX::GEQUAL,
|
|
Always = GX::ALWAYS,
|
|
};
|
|
|
|
enum class ERglAlphaOp : std::underlying_type_t<GX::AlphaOp> {
|
|
And = GX::AOP_AND,
|
|
Or = GX::AOP_OR,
|
|
Xor = GX::AOP_XOR,
|
|
XNor = GX::AOP_XNOR,
|
|
Max = GX::MAX_ALPHAOP,
|
|
};
|
|
|
|
enum class ERglEnum : std::underlying_type_t<GX::Compare> {
|
|
Never = GX::NEVER,
|
|
Less = GX::LESS,
|
|
Equal = GX::EQUAL,
|
|
LEqual = GX::LEQUAL,
|
|
Greater = GX::GREATER,
|
|
NEqual = GX::NEQUAL,
|
|
GEqual = GX::GEQUAL,
|
|
Always = GX::ALWAYS,
|
|
};
|
|
|
|
using ERglLight = u8;
|
|
|
|
enum class ERglTexOffset : std::underlying_type_t<GX::TexOffset> {
|
|
Zero = GX::TO_ZERO,
|
|
Sixteenth = GX::TO_SIXTEENTH,
|
|
Eighth = GX::TO_EIGHTH,
|
|
Fourth = GX::TO_FOURTH,
|
|
Half = GX::TO_HALF,
|
|
One = GX::TO_ONE,
|
|
};
|
|
|
|
enum class ERglFogMode : std::underlying_type_t<GX::FogType> {
|
|
None = GX::FOG_NONE,
|
|
|
|
PerspLin = GX::FOG_PERSP_LIN,
|
|
PerspExp = GX::FOG_PERSP_EXP,
|
|
PerspExp2 = GX::FOG_ORTHO_EXP2,
|
|
PerspRevExp = GX::FOG_PERSP_REVEXP,
|
|
PerspRevExp2 = GX::FOG_PERSP_REVEXP2,
|
|
|
|
OrthoLin = GX::FOG_ORTHO_LIN,
|
|
OrthoExp = GX::FOG_ORTHO_EXP,
|
|
OrthoExp2 = GX::FOG_ORTHO_EXP2,
|
|
OrthoRevExp = GX::FOG_ORTHO_REVEXP,
|
|
OrthoRevExp2 = GX::FOG_ORTHO_REVEXP2,
|
|
};
|
|
|
|
struct SViewport {
|
|
u32 x0_left;
|
|
u32 x4_top;
|
|
u32 x8_width;
|
|
u32 xc_height;
|
|
float x10_halfWidth;
|
|
float x14_halfHeight;
|
|
float aspect;
|
|
};
|
|
|
|
struct SClipScreenRect {
|
|
bool x0_valid = false;
|
|
int x4_left = 0;
|
|
int x8_top = 0;
|
|
int xc_width = 0;
|
|
int x10_height = 0;
|
|
int x14_dstWidth = 0;
|
|
float x18_uvXMin = 0.f;
|
|
float x1c_uvXMax = 0.f;
|
|
float x20_uvYMin = 0.f;
|
|
float x24_uvYMax = 0.f;
|
|
|
|
SClipScreenRect() = default;
|
|
SClipScreenRect(bool valid, int left, int top, int width, int height, int dstWidth, float uvXMin, float uvXMax,
|
|
float uvYMin, float uvYMax)
|
|
: x0_valid(valid)
|
|
, x4_left(left)
|
|
, x8_top(top)
|
|
, xc_width(width)
|
|
, x10_height(height)
|
|
, x14_dstWidth(dstWidth)
|
|
, x18_uvXMin(uvXMin)
|
|
, x1c_uvXMax(uvXMax)
|
|
, x20_uvYMin(uvYMin)
|
|
, x24_uvYMax(uvYMax) {}
|
|
|
|
SClipScreenRect(const aurora::gfx::ClipRect& rect) {
|
|
x4_left = rect.x;
|
|
x8_top = rect.y;
|
|
xc_width = rect.width;
|
|
x10_height = rect.height;
|
|
x14_dstWidth = rect.width;
|
|
}
|
|
|
|
SClipScreenRect(const SViewport& vp) {
|
|
x4_left = vp.x0_left;
|
|
x8_top = vp.x4_top;
|
|
xc_width = vp.x8_width;
|
|
x10_height = vp.xc_height;
|
|
}
|
|
};
|
|
|
|
#define DEPTH_FAR 1.f
|
|
#define DEPTH_SKY 0.999f
|
|
#define DEPTH_TARGET_MANAGER 0.12500012f
|
|
#define DEPTH_WORLD (1.f / 8.f)
|
|
#define DEPTH_GUN (1.f / 32.f)
|
|
#define DEPTH_SCREEN_ACTORS (1.f / 64.f)
|
|
#define DEPTH_HUD (1.f / 512.f)
|
|
#define DEPTH_NEAR 0.f
|
|
#define CUBEMAP_RES 256
|
|
#define CUBEMAP_MIPS 6
|
|
|
|
class CGraphics {
|
|
public:
|
|
struct CProjectionState {
|
|
bool x0_persp;
|
|
float x4_left;
|
|
float x8_right;
|
|
float xc_top;
|
|
float x10_bottom;
|
|
float x14_near;
|
|
float x18_far;
|
|
};
|
|
|
|
static CProjectionState g_Proj;
|
|
static zeus::CVector2f g_CachedDepthRange;
|
|
// static CFogState g_Fog;
|
|
static SViewport g_Viewport;
|
|
static float g_ProjAspect;
|
|
static u32 g_NumBreakpointsWaiting;
|
|
static u32 g_FlippingState;
|
|
static bool g_LastFrameUsedAbove;
|
|
static bool g_InterruptLastFrameUsedAbove;
|
|
static GX::LightMask g_LightActive;
|
|
static std::array<GX::LightObj, GX::MaxLights> g_LightObjs;
|
|
static std::array<ELightType, GX::MaxLights> g_LightTypes;
|
|
static zeus::CTransform g_GXModelView;
|
|
static zeus::CTransform g_GXModelViewInvXpose;
|
|
static zeus::CTransform g_GXModelMatrix;
|
|
static zeus::CTransform g_ViewMatrix;
|
|
static zeus::CVector3f g_ViewPoint;
|
|
static zeus::CTransform g_GXViewPointMatrix;
|
|
static zeus::CTransform g_CameraMatrix;
|
|
static SClipScreenRect g_CroppedViewport;
|
|
static bool g_IsGXModelMatrixIdentity;
|
|
static zeus::CColor g_ClearColor;
|
|
static float g_ClearDepthValue; // Was a 24bit value, we use a float range from [0,1]
|
|
static bool g_IsBeginSceneClearFb;
|
|
|
|
static ERglEnum g_depthFunc;
|
|
static ERglCullMode g_cullMode;
|
|
|
|
static void Startup();
|
|
static void InitGraphicsVariables();
|
|
static void InitGraphicsDefaults();
|
|
static void SetDefaultVtxAttrFmt();
|
|
static void DisableAllLights();
|
|
static void LoadLight(ERglLight light, const CLight& info);
|
|
static void EnableLight(ERglLight light);
|
|
static void SetLightState(GX::LightMask lightState);
|
|
static void SetAmbientColor(const zeus::CColor& col);
|
|
static void SetFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color);
|
|
static void SetDepthWriteMode(bool test, ERglEnum comp, bool write);
|
|
static void SetBlendMode(ERglBlendMode, ERglBlendFactor, ERglBlendFactor, ERglLogicOp);
|
|
static void SetCullMode(ERglCullMode);
|
|
static void BeginScene();
|
|
static void EndScene();
|
|
static void Render2D(CTexture& tex, u32 x, u32 y, u32 w, u32 h, const zeus::CColor& col);
|
|
static bool BeginRender2D(const CTexture& tex);
|
|
static void DoRender2D(const CTexture& tex, s32 x, s32 y, s32 w1, s32 w2, s32 w3, s32 w4, s32 w5,
|
|
const zeus::CColor& col);
|
|
static void EndRender2D(bool v);
|
|
static void SetAlphaCompare(ERglAlphaFunc comp0, u8 ref0, ERglAlphaOp op, ERglAlphaFunc comp1, u8 ref1);
|
|
static void SetViewPointMatrix(const zeus::CTransform& xf);
|
|
static void SetViewMatrix();
|
|
static void SetModelMatrix(const zeus::CTransform& xf);
|
|
static zeus::CMatrix4f CalculatePerspectiveMatrix(float fovy, float aspect, float znear, float zfar);
|
|
static zeus::CMatrix4f GetPerspectiveProjectionMatrix();
|
|
static const CProjectionState& GetProjectionState();
|
|
static void SetProjectionState(const CProjectionState&);
|
|
static void SetPerspective(float fovy, float aspect, float znear, float zfar);
|
|
static void SetOrtho(float left, float right, float top, float bottom, float znear, float zfar);
|
|
static void FlushProjection();
|
|
static zeus::CVector2i ProjectPoint(const zeus::CVector3f& point);
|
|
static SClipScreenRect ClipScreenRectFromMS(const zeus::CVector3f& p1, const zeus::CVector3f& p2);
|
|
static SClipScreenRect ClipScreenRectFromVS(const zeus::CVector3f& p1, const zeus::CVector3f& p2);
|
|
|
|
static void SetViewportResolution(const zeus::CVector2i& res);
|
|
static void SetViewport(int leftOff, int bottomOff, int width, int height);
|
|
static void SetScissor(int leftOff, int bottomOff, int width, int height);
|
|
static void SetDepthRange(float near, float far);
|
|
|
|
static CTimeProvider* g_ExternalTimeProvider;
|
|
static float g_DefaultSeconds;
|
|
static u32 g_RenderTimings;
|
|
static void SetExternalTimeProvider(CTimeProvider* provider) { g_ExternalTimeProvider = provider; }
|
|
static float GetSecondsMod900();
|
|
static void TickRenderTimings();
|
|
static u32 g_FrameCounter;
|
|
static u32 g_Framerate;
|
|
static u32 g_FramesPast;
|
|
static frame_clock::time_point g_FrameStartTime;
|
|
static u32 GetFrameCounter() { return g_FrameCounter; }
|
|
static u32 GetFPS() { return g_Framerate; }
|
|
static void UpdateFPSCounter();
|
|
static void SetUseVideoFilter(bool);
|
|
static void SetClearColor(const zeus::CColor& color);
|
|
static void SetCopyClear(const zeus::CColor& color, float depth);
|
|
static void SetIsBeginSceneClearFb(bool clear);
|
|
static u32 GetViewportLeft() { return g_Viewport.x0_left; }
|
|
static u32 GetViewportTop() { return g_Viewport.x4_top; }
|
|
static u32 GetViewportWidth() { return g_Viewport.x8_width; }
|
|
static u32 GetViewportHeight() { return g_Viewport.xc_height; }
|
|
static float GetViewportHalfWidth() { return g_Viewport.x10_halfWidth; }
|
|
static float GetViewportHalfHeight() { return g_Viewport.x14_halfHeight; }
|
|
static float GetViewportAspect() { return g_Viewport.aspect; }
|
|
static bool IsCroppedViewportValid() { return g_CroppedViewport.x0_valid; }
|
|
static int GetCroppedViewportLeft() { return g_CroppedViewport.x4_left; }
|
|
static int GetCroppedViewportTop() { return g_CroppedViewport.x8_top; }
|
|
static int GetCroppedViewportWidth() { return g_CroppedViewport.xc_width; }
|
|
static int GetCroppedViewportHeight() { return g_CroppedViewport.x10_height; }
|
|
static float GetCroppedViewportDstWidth() { return g_CroppedViewport.x14_dstWidth; }
|
|
static float GetCroppedViewportUVXMin() { return g_CroppedViewport.x18_uvXMin; }
|
|
static float GetCroppedViewportUVXMax() { return g_CroppedViewport.x1c_uvXMax; }
|
|
static float GetCroppedViewportUVYMin() { return g_CroppedViewport.x20_uvYMin; }
|
|
static float GetCroppedViewportUVYMax() { return g_CroppedViewport.x24_uvYMax; }
|
|
|
|
static const std::array<zeus::CMatrix3f, 6> skCubeBasisMats;
|
|
|
|
static void ResolveSpareTexture(const SClipScreenRect& rect, int bindIdx, GX::TextureFormat format,
|
|
bool clearDepth = false) {
|
|
aurora::gfx::resolve_color({rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}, bindIdx, format,
|
|
clearDepth);
|
|
}
|
|
static void LoadDolphinSpareTexture(int bindIdx, GX::TextureFormat format, GX::TexMapID id) {
|
|
GXTexObj obj;
|
|
GXInitTexObjResolved(&obj, bindIdx, format, GX_CLAMP, GX_CLAMP, GX_TLUT0);
|
|
GXInitTexObjLOD(&obj, GX_NEAR, GX_NEAR, 0.f, 0.f, 0.f, false, false, GX_ANISO_1);
|
|
GXLoadTexObj(&obj, id);
|
|
}
|
|
static void LoadDolphinSpareTexture(int bindIdx, GXCITexFmt format, GXTlut tlut, GX::TexMapID id) {
|
|
GXTexObj obj;
|
|
GXInitTexObjResolved(&obj, bindIdx, static_cast<GX::TextureFormat>(format), GX_CLAMP, GX_CLAMP, tlut);
|
|
GXInitTexObjLOD(&obj, GX_NEAR, GX_NEAR, 0.f, 0.f, 0.f, false, false, GX_ANISO_1);
|
|
GXLoadTexObj(&obj, id);
|
|
}
|
|
static void ResolveSpareDepth(const SClipScreenRect& rect, int bindIdx = 0) {
|
|
// aurora::gfx::resolve_depth({rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}, bindIdx);
|
|
}
|
|
|
|
static void ResetGfxStates() noexcept;
|
|
static void SetTevStates(EStreamFlags flags) noexcept;
|
|
static void SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass);
|
|
static void StreamBegin(GX::Primitive primitive);
|
|
static void StreamNormal(const zeus::CVector3f& nrm);
|
|
static void StreamColor(const zeus::CColor& color);
|
|
static inline void StreamColor(float r, float g, float b, float a) { StreamColor({r, g, b, a}); }
|
|
static void StreamTexcoord(const zeus::CVector2f& uv);
|
|
static inline void StreamTexcoord(float x, float y) { StreamTexcoord({x, y}); }
|
|
static void StreamVertex(const zeus::CVector3f& pos);
|
|
static inline void StreamVertex(float xyz) { StreamVertex({xyz, xyz, xyz}); }
|
|
static inline void StreamVertex(float x, float y, float z) { StreamVertex({x, y, z}); }
|
|
static void StreamEnd();
|
|
static void UpdateVertexDataStream();
|
|
static void ResetVertexDataStream(bool end);
|
|
static void FlushStream();
|
|
static void FullRender();
|
|
static void DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* pos, const zeus::CVector3f& normal,
|
|
const zeus::CColor& col, s32 numVerts);
|
|
static void SetLineWidth(float width, ERglTexOffset offs);
|
|
};
|
|
|
|
template <class VTX>
|
|
class TriFanToStrip {
|
|
std::vector<VTX>& m_vec;
|
|
size_t m_start;
|
|
size_t m_added = 0;
|
|
|
|
public:
|
|
explicit TriFanToStrip(std::vector<VTX>& vec) : m_vec(vec), m_start(vec.size()) {}
|
|
|
|
void AddVert(const VTX& vert) {
|
|
++m_added;
|
|
if (m_added > 3 && (m_added & 1) == 0) {
|
|
m_vec.reserve(m_vec.size() + 3);
|
|
m_vec.push_back(m_vec.back());
|
|
m_vec.push_back(m_vec[m_start]);
|
|
}
|
|
m_vec.push_back(vert);
|
|
}
|
|
|
|
template <class... _Args>
|
|
void EmplaceVert(_Args&&... args) {
|
|
++m_added;
|
|
if (m_added > 3 && (m_added & 1) == 0) {
|
|
m_vec.reserve(m_vec.size() + 3);
|
|
m_vec.push_back(m_vec.back());
|
|
m_vec.push_back(m_vec[m_start]);
|
|
}
|
|
m_vec.emplace_back(std::forward<_Args>(args)...);
|
|
}
|
|
|
|
// void Draw() const { CGraphics::DrawArray(m_start, m_vec.size() - m_start); }
|
|
};
|
|
|
|
#ifdef AURORA_GFX_DEBUG_GROUPS
|
|
#define SCOPED_GRAPHICS_DEBUG_GROUP(name, ...) \
|
|
OPTICK_EVENT_DYNAMIC(name); \
|
|
aurora::gfx::ScopedDebugGroup _GfxDbg_{name}
|
|
#else
|
|
#define SCOPED_GRAPHICS_DEBUG_GROUP(name, ...) OPTICK_EVENT_DYNAMIC(name)
|
|
#endif
|
|
|
|
} // namespace metaforce
|