From cc15b2263a1358e78b9301ae7ad0cbf6caa41c9b Mon Sep 17 00:00:00 2001 From: Esras Date: Sun, 27 Jul 2025 17:55:47 -0700 Subject: [PATCH 01/22] Fix the header declaration of the Matrix44::setRow function. --- include/math/seadMatrix.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/math/seadMatrix.hpp b/include/math/seadMatrix.hpp index 858f1555..fd3dfa07 100644 --- a/include/math/seadMatrix.hpp +++ b/include/math/seadMatrix.hpp @@ -801,7 +801,7 @@ inline void Matrix44::setCol(s32 axis, const Vec4& v) template inline void Matrix44::setRow(s32 row, const Vec4& v) { - Matrix44CalcCommon::setRow(*this, row, v); + Matrix44CalcCommon::setRow(*this, v, row); } template From 41ce93d1630c3de59423dd5ac2a91ce75bd10d4a Mon Sep 17 00:00:00 2001 From: Esras Date: Sun, 27 Jul 2025 18:36:30 -0700 Subject: [PATCH 02/22] Try 2 at the Projection libraries. Copying over from the prior PR (#129) and organizing. --- CMakeLists.txt | 10 + include/gfx/seadCamera.h | 8 +- include/gfx/seadGraphics.h | 8 + include/gfx/seadGraphicsContext.h | 272 ++++++++++++++ include/gfx/seadProjection.h | 212 +++++++---- include/gfx/seadViewport.h | 26 +- include/math/seadGeometry.h | 28 ++ modules/src/gfx/seadCamera.cpp | 83 ++++- modules/src/gfx/seadGraphics.cpp | 14 + modules/src/gfx/seadGraphicsContext.cpp | 193 ++++++++++ modules/src/gfx/seadProjection.cpp | 455 +++++++++++++++++++++++- modules/src/gfx/seadViewport.cpp | 207 +++++++++++ modules/src/math/seadGeometry.cpp | 25 ++ 13 files changed, 1447 insertions(+), 94 deletions(-) create mode 100644 include/gfx/seadGraphicsContext.h create mode 100644 include/math/seadGeometry.h create mode 100644 modules/src/gfx/seadGraphics.cpp create mode 100644 modules/src/gfx/seadGraphicsContext.cpp create mode 100644 modules/src/gfx/seadViewport.cpp create mode 100644 modules/src/math/seadGeometry.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index edbe2783..3740802f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,9 @@ add_library(sead OBJECT include/gfx/seadDrawContext.h include/gfx/seadDrawLockContext.h include/gfx/seadFrameBuffer.h + include/gfx/seadGraphics.h + include/gfx/seadGraphicsContext.h + include/gfx/seadViewport.h include/gfx/seadPrimitiveRenderer.h include/gfx/seadPrimitiveRendererUtil.h include/gfx/seadProjection.h @@ -112,6 +115,9 @@ add_library(sead OBJECT modules/src/gfx/seadColor.cpp modules/src/gfx/seadDrawLockContext.cpp modules/src/gfx/seadFrameBuffer.cpp + modules/src/gfx/seadGraphics.cpp + modules/src/gfx/seadGraphicsContext.cpp + modules/src/gfx/seadViewport.cpp # modules/src/gfx/seadPrimitiveRenderer.cpp # modules/src/gfx/seadPrimitiveRendererUtil.cpp modules/src/gfx/seadProjection.cpp @@ -131,6 +137,7 @@ add_library(sead OBJECT include/math/seadBoundBox.h include/math/seadBoundBox.hpp + include/math/seadGeometry.h include/math/seadMathBase.h include/math/seadMathCalcCommon.h include/math/seadMathCalcCommon.hpp @@ -150,11 +157,14 @@ add_library(sead OBJECT include/math/seadVectorCalcCommon.hpp include/math/seadVectorFwd.h modules/src/math/seadBoundBox.cpp + modules/src/math/seadGeometry.cpp modules/src/math/seadMathCalcCommon.cpp modules/src/math/seadMatrix.cpp modules/src/math/seadQuat.cpp modules/src/math/seadVector.cpp + include/geom/seadLine.h + include/mc/seadCoreInfo.h include/mc/seadJob.h include/mc/seadJobQueue.h diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index 731ce1c9..4c89cbd6 100644 --- a/include/gfx/seadCamera.h +++ b/include/gfx/seadCamera.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -9,15 +10,13 @@ namespace sead class OrthoProjection; class Projection; class Viewport; -template -class Ray; class Camera { SEAD_RTTI_BASE(Camera) public: - Camera() = default; + Camera(); virtual ~Camera(); virtual void doUpdateMatrix(Matrix34f* dst) const = 0; @@ -32,7 +31,7 @@ class Camera void projectByMatrix(Vector2f* dst, const Vector3f& world_pos, const Projection& projection, const Viewport& viewport) const; - void unprojectRayByMatrix(Ray* dst, const Vector3f& camera_pos) const; + void unprojectRayByMatrix(Ray3f* dst, const Vector3f& camera_pos) const; Matrix34f& getMatrix() { return mMatrix; } const Matrix34f& getMatrix() const { return mMatrix; } @@ -75,6 +74,7 @@ class DirectCamera : public Camera { SEAD_RTTI_OVERRIDE(DirectCamera, Camera) public: + DirectCamera() = default; ~DirectCamera() override; void doUpdateMatrix(Matrix34f* dst) const override; diff --git a/include/gfx/seadGraphics.h b/include/gfx/seadGraphics.h index 8613705c..1dab79d3 100644 --- a/include/gfx/seadGraphics.h +++ b/include/gfx/seadGraphics.h @@ -71,6 +71,14 @@ class Graphics : public IDisposer virtual void setPolygonOffsetEnableImpl(bool, bool, bool) = 0; static Graphics* instance() { return sInstance; } + + static DevicePosture getDefaultDevicePosture() { return sDefaultDevicePosture; } + static f32 getDefaultDeviceZScale() { return sDefaultDeviceZScale; } + static f32 getDefaultDeviceZOffset() { return sDefaultDeviceZOffset; } + + void setViewportRealPosition(f32 x, f32 y, f32 w, f32 h) { setViewportImpl(x, y, w, h); } + void setScissorRealPosition(f32 x, f32 y, f32 w, f32 h) { setScissorImpl(x, y, w, h); } + static DevicePosture sDefaultDevicePosture; static f32 sDefaultDeviceZScale; static f32 sDefaultDeviceZOffset; diff --git a/include/gfx/seadGraphicsContext.h b/include/gfx/seadGraphicsContext.h new file mode 100644 index 00000000..705674a1 --- /dev/null +++ b/include/gfx/seadGraphicsContext.h @@ -0,0 +1,272 @@ +#pragma once + +#include +#include + +namespace sead +{ + +class GraphicsContext +{ +public: + GraphicsContext(); + virtual ~GraphicsContext() {} + + void apply() const; + void applyAlphaTest() const; + void applyDepthAndStencilTest() const; + void applyColorMask() const; + void applyBlendAndFastZ() const; + void applyBlendConstantColor() const; + void applyCullingAndPolygonModeAndPolygonOffset() const; + + void setDepthEnable(bool test_enable, bool write_enable) + { + setDepthTestEnable(test_enable); + setDepthWriteEnable(write_enable); + } + + void setDepthTestEnable(bool test_enable) { mDepthTestEnable = test_enable; } + + void setDepthWriteEnable(bool write_enable) { mDepthWriteEnable = write_enable; } + + void setDepthFunc(Graphics::DepthFunc func) { mDepthFunc = func; } + + void setCullingMode(Graphics::CullingMode mode) { mCullingMode = mode; } + + void setBlendEnable(bool blend) { mBlendEnable = blend; } + + void setBlendFactor(Graphics::BlendFactor src_factor, Graphics::BlendFactor dst_factor) + { + setBlendFactorSrc(src_factor); + setBlendFactorDst(dst_factor); + } + + void setBlendFactorSeparate(Graphics::BlendFactor src_factor_rgb, + Graphics::BlendFactor dst_factor_rgb, + Graphics::BlendFactor src_factor_a, + Graphics::BlendFactor dst_factor_a) + { + setBlendFactorSrcRGB(src_factor_rgb); + setBlendFactorDstRGB(dst_factor_rgb); + setBlendFactorSrcAlpha(src_factor_a); + setBlendFactorDstAlpha(dst_factor_a); + } + + void setBlendFactorSrc(Graphics::BlendFactor factor) + { + setBlendFactorSrcRGB(factor); + setBlendFactorSrcAlpha(factor); + } + + void setBlendFactorDst(Graphics::BlendFactor factor) + { + setBlendFactorDstRGB(factor); + setBlendFactorDstAlpha(factor); + } + + void setBlendFactorSrcRGB(Graphics::BlendFactor factor) { mBlendFactorSrcRGB = factor; } + + void setBlendFactorSrcAlpha(Graphics::BlendFactor factor) { mBlendFactorSrcA = factor; } + + void setBlendFactorDstRGB(Graphics::BlendFactor factor) { mBlendFactorDstRGB = factor; } + + void setBlendFactorDstAlpha(Graphics::BlendFactor factor) { mBlendFactorDstA = factor; } + + void setBlendEquation(Graphics::BlendEquation equation) + { + setBlendEquationRGB(equation); + setBlendEquationAlpha(equation); + } + + void setBlendEquationSeparate(Graphics::BlendEquation equation_rgb, + Graphics::BlendEquation equation_a) + { + setBlendEquationRGB(equation_rgb); + setBlendEquationAlpha(equation_a); + } + + void setBlendEquationRGB(Graphics::BlendEquation equation) { mBlendEquationRGB = equation; } + + void setBlendEquationAlpha(Graphics::BlendEquation equation) { mBlendEquationA = equation; } + + void setBlendConstantColor(const Color4f& color) { mBlendConstantColor = color; } + + void setAlphaTestEnable(bool enable) { mAlphaTestEnable = enable; } + + void setAlphaTestFunc(Graphics::AlphaFunc func, f32 ref) + { + mAlphaTestFunc = func; + mAlphaTestRef = ref; + } + + void setColorMask(bool r, bool g, bool b, bool a) + { + mColorMaskR = r; + mColorMaskG = g; + mColorMaskB = b; + mColorMaskA = a; + } + + void setStencilTestEnable(bool enable) { mStencilTestEnable = enable; } + + void setStencilTestFunc(Graphics::StencilFunc func, s32 ref, u32 mask) + { + mStencilTestFunc = func; + mStencilTestRef = ref; + mStencilTestMask = mask; + } + + void setStencilTestOp(Graphics::StencilOp fail, Graphics::StencilOp zfail, + Graphics::StencilOp zpass) + { + mStencilOpFail = fail; + mStencilOpZFail = zfail; + mStencilOpZPass = zpass; + } + + void setPolygonMode(Graphics::PolygonMode front, Graphics::PolygonMode back) + { +#ifdef cafe + mPolygonModeFront = front; + mPolygonModeBack = back; +#endif // cafe + } + + void setPolygonOffsetEnable(bool fill_front_enable, bool fill_back_enable, + bool point_line_enable) + { +#ifdef cafe + mPolygonOffsetFrontEnable = fill_front_enable; + mPolygonOffsetBackEnable = fill_back_enable; + mPolygonOffsetPointLineEnable = point_line_enable; +#endif // cafe + } + + bool getDepthTestEnable() const { return mDepthTestEnable; } + + bool getDepthWriteEnable() const { return mDepthWriteEnable; } + + Graphics::DepthFunc getDepthFunc() const { return mDepthFunc; } + + Graphics::CullingMode getCullingMode() const { return mCullingMode; } + + bool getBlendEnable() const { return mBlendEnable; } + + Graphics::BlendFactor getBlendFactorSrcRGB() const { return mBlendFactorSrcRGB; } + + Graphics::BlendFactor getBlendFactorSrcAlpha() const { return mBlendFactorSrcA; } + + Graphics::BlendFactor getBlendFactorDstRGB() const { return mBlendFactorDstRGB; } + + Graphics::BlendFactor getBlendFactorDstAlpha() const { return mBlendFactorDstA; } + + Graphics::BlendEquation getBlendEquationRGB() const { return mBlendEquationRGB; } + + Graphics::BlendEquation getBlendEquationAlpha() const { return mBlendEquationA; } + + const Color4f& getBlendConstantColor() const { return mBlendConstantColor; } + + bool getAlphaTestEnable() const { return mAlphaTestEnable; } + + Graphics::AlphaFunc getAlphaTestFunc() const { return mAlphaTestFunc; } + + f32 getAlphaTestRef() const { return mAlphaTestRef; } + + bool getColorMaskR() const { return mColorMaskR; } + + bool getColorMaskG() const { return mColorMaskG; } + + bool getColorMaskB() const { return mColorMaskB; } + + bool getColorMaskA() const { return mColorMaskA; } + + bool getStencilTestEnable() const { return mStencilTestEnable; } + + Graphics::StencilFunc getStencilTestFunc() const { return mStencilTestFunc; } + + s32 getStencilTestRef() const { return mStencilTestRef; } + + u32 getStencilTestMask() const { return mStencilTestMask; } + + Graphics::StencilOp getStencilTestOpFail() const { return mStencilOpFail; } + + Graphics::StencilOp getStencilTestOpZFail() const { return mStencilOpZFail; } + + Graphics::StencilOp getStencilTestOpZPass() const { return mStencilOpZPass; } + + Graphics::PolygonMode getPolygonModeFront() const + { +#ifdef cafe + return mPolygonModeFront; +#endif // cafe + } + + Graphics::PolygonMode getPolygonModeBack() const + { +#ifdef cafe + return mPolygonModeBack; +#endif // cafe + } + + bool getPolygonOffsetFrontEnable() const + { +#ifdef cafe + return mPolygonOffsetFrontEnable; +#endif // cafe + } + + bool getPolygonOffsetBackEnable() const + { +#ifdef cafe + return mPolygonOffsetBackEnable; +#endif // cafe + } + + bool getPolygonOffsetPointLineEnable() const + { +#ifdef cafe + return mPolygonOffsetPointLineEnable; +#endif // cafe + } + +private: + bool mDepthTestEnable; + bool mDepthWriteEnable; + Graphics::DepthFunc mDepthFunc; + Graphics::CullingMode mCullingMode; + bool mBlendEnable; + Graphics::BlendFactor mBlendFactorSrcRGB; + Graphics::BlendFactor mBlendFactorSrcA; + Graphics::BlendFactor mBlendFactorDstRGB; + Graphics::BlendFactor mBlendFactorDstA; + Graphics::BlendEquation mBlendEquationRGB; + Graphics::BlendEquation mBlendEquationA; + Color4f mBlendConstantColor; + bool mAlphaTestEnable; + Graphics::AlphaFunc mAlphaTestFunc; + f32 mAlphaTestRef; + bool mColorMaskR; + bool mColorMaskG; + bool mColorMaskB; + bool mColorMaskA; + bool mStencilTestEnable; + Graphics::StencilFunc mStencilTestFunc; + s32 mStencilTestRef; + u32 mStencilTestMask; + Graphics::StencilOp mStencilOpFail; + Graphics::StencilOp mStencilOpZFail; + Graphics::StencilOp mStencilOpZPass; +#ifdef cafe + Graphics::PolygonMode mPolygonModeFront; + Graphics::PolygonMode mPolygonModeBack; + bool mPolygonOffsetFrontEnable; + bool mPolygonOffsetBackEnable; + bool mPolygonOffsetPointLineEnable; +#endif // cafe +}; +#ifdef cafe +static_assert(sizeof(GraphicsContext) == 0x74, "sead::GraphicsContext size mismatch"); +#endif // cafe + +} // namespace sead diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index f3d64fa7..25625615 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -1,7 +1,7 @@ -#ifndef SEAD_PROJECTION_H_ -#define SEAD_PROJECTION_H_ +#pragma once #include +#include #include #include #include @@ -20,6 +20,12 @@ class Projection SEAD_RTTI_BASE(Projection) public: + enum Type + { + cType_Perspective = 0, + cType_Ortho = 1, + cType_Undefined = 2 + }; Projection(); virtual ~Projection() = default; @@ -29,14 +35,13 @@ class Projection virtual f32 getAspect() const = 0; virtual void getOffset(Vector2f* offset) const = 0; virtual void updateAttributesForDirectProjection(); - virtual u32 getProjectionType() const = 0; + virtual Type getProjectionType() const = 0; virtual void doUpdateMatrix(Matrix44f* mtx) const = 0; virtual void doUpdateDeviceMatrix(Matrix44f*, const Matrix44f&, Graphics::DevicePosture) const; virtual void doScreenPosToCameraPosTo(Vector3f* camera_pos, const Vector3f& screen_pos) const = 0; const Matrix44f& getProjectionMatrix() const; - void updateMatrixImpl_() const; Matrix44f* getProjectionMatrixMutable(); const Matrix44f& getDeviceProjectionMatrix() const; void cameraPosToScreenPos(Vector3f* screen_pos, const Vector3f& camera_pos) const; @@ -56,6 +61,8 @@ class Projection } private: + void updateMatrixImpl_() const; + mutable bool mDirty = true; mutable bool mDeviceDirty = true; Matrix44f mMatrix; @@ -72,25 +79,9 @@ class PerspectiveProjection : public Projection public: PerspectiveProjection(); PerspectiveProjection(f32 near, f32 far, f32 fovy_rad, f32 aspect); - ~PerspectiveProjection() override; - - f32 getNear() const override; - f32 getFar() const override; - f32 getFovy() const override; - f32 getAspect() const override; - void getOffset(Vector2f* offset) const override; - void doScreenPosToCameraPosTo(Vector3f* cameraPos, const Vector3f& screenPos) const override; - u32 getProjectionType() const override; + ~PerspectiveProjection() override = default; - void set(f32 near, f32 far, f32 fovy_rad, f32 aspect); - void doUpdateMatrix(Matrix44f* mtx) const override; - void setFovx(f32); - void createDividedProjection(PerspectiveProjection* projection, s32, s32, s32, s32); - f32 getTop() const; - f32 getBottom() const; - f32 getLeft() const; - f32 getRight() const; - void setTBLR(f32 top, f32 bottom, f32 left, f32 right); + void set(f32 _near, f32 _far, f32 fovy_rad, f32 aspect); void setNear(f32 near) { @@ -102,6 +93,8 @@ class PerspectiveProjection : public Projection mFar = far; setDirty(); } + void setFovx(f32 fovx); + void setFovy(f32 fovy) { setFovy_(fovy); } void setAspect(f32 aspect) { mAspect = aspect; @@ -113,41 +106,82 @@ class PerspectiveProjection : public Projection setDirty(); } + void createDividedProjection(PerspectiveProjection* dst, s32 partno_x, s32 partno_y, + s32 divnum_x, s32 divnum_y) const; + + f32 getNear() const override { return mNear; } + f32 getFar() const override { return mFar; } + f32 getFovy() const override { return mAngle; } + f32 getAspect() const override { return mAspect; } + void getOffset(Vector2f* offset) const override { offset->set(mOffset); } + + f32 getTop() const; + f32 getBottom() const; + f32 getLeft() const; + f32 getRight() const; + + void setTBLR(f32 top, f32 bottom, f32 left, f32 right); + + Type getProjectionType() const override { return Projection::cType_Perspective; } + void doUpdateMatrix(Matrix44f* dst) const override; + void doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const override; + private: - f32 mNear; - f32 mFar; - f32 mFovyRad; + void setFovy_(f32 fovy); + + f32 calcNearClipHeight_() const { return mNear * 2 * mFovyTan; } + f32 calcNearClipWidth_() const { return calcNearClipHeight_() * mAspect; } + + f32 mNear = 1.0f; + f32 mFar = 10000.0f; + f32 mAngle = numbers::pi / 2.0f; f32 mFovySin; f32 mFovyCos; f32 mFovyTan; - f32 mAspect; - Vector2f mOffset; + f32 mAspect = 1.333333f; + Vector2f mOffset = Vector2f::zero; }; +#ifdef cafe +static_assert(sizeof(PerspectiveProjection) == 0xB8, "sead::PerspectiveProjection size mismatch"); +#endif // cafe class OrthoProjection : public Projection { - SEAD_RTTI_OVERRIDE(OrthoProjection, Projection); + SEAD_RTTI_OVERRIDE(OrthoProjection, Projection) public: OrthoProjection(); - OrthoProjection(f32 near, f32 far, f32 top, f32 bottom, f32 left, f32 right); - OrthoProjection(f32 near, f32 far, const BoundBox2f& boundBox); - OrthoProjection(f32 near, f32 far, const Viewport& viewport); - ~OrthoProjection() override; + OrthoProjection(f32 _near, f32 _far, f32 top, f32 bottom, f32 left, f32 right); + OrthoProjection(f32 _near, f32 _far, const BoundBox2f& box); + OrthoProjection(f32 _near, f32 _far, const Viewport& vp); + ~OrthoProjection() override = default; - f32 getNear() const override; - f32 getFar() const override; - f32 getFovy() const override; + void setNear(f32 near); + void setFar(f32 far); + void setTop(f32 top); + void setBottom(f32 bottom); + void setLeft(f32 left); + void setRight(f32 right); + void setTBLR(f32 top, f32 bottom, f32 left, f32 right); + void setByViewport(const Viewport& vp); + void setBoundBox(const BoundBox2f& box); + + void createDividedProjection(OrthoProjection* dst, s32 partno_x, s32 partno_y, s32 divnum_x, + s32 divnum_y) const; + + f32 getNear() const override { return mNear; } + f32 getFar() const override { return mFar; } + f32 getFovy() const override { return 0; } + f32 getTop() const { return mTop; } + f32 getBottom() const { return mBottom; } + f32 getLeft() const { return mLeft; } + f32 getRight() const { return mRight; } f32 getAspect() const override; void getOffset(Vector2f* offset) const override; - u32 getProjectionType() const override; - void doUpdateMatrix(Matrix44f* mtx) const override; - void doScreenPosToCameraPosTo(Vector3f* cameraPos, const Vector3f& screenPos) const override; - void createDividedProjection(OrthoProjection*, s32, s32, s32, s32) const; - void setBoundBox(const BoundBox2f& boundBox); - void setByViewport(const Viewport& viewport); - void setTBLR(f32 top, f32 bottom, f32 left, f32 right); + Type getProjectionType() const override { return Projection::cType_Ortho; } + void doUpdateMatrix(Matrix44f* dst) const override; + void doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const override; private: f32 mNear; @@ -156,32 +190,51 @@ class OrthoProjection : public Projection f32 mBottom; f32 mLeft; f32 mRight; + Vector2f mOffset; }; +#ifdef cafe +static_assert(sizeof(OrthoProjection) == 0xAC, "sead::OrthoProjection size mismatch"); +#endif // cafe class FrustumProjection : public Projection { SEAD_RTTI_OVERRIDE(FrustumProjection, Projection) public: - FrustumProjection(); - FrustumProjection(f32 near, f32 far, f32 top, f32 bottom, f32 left, f32 right); - FrustumProjection(f32 near, f32 far, const BoundBox2f& boundBox); - ~FrustumProjection() override; + FrustumProjection() = default; + FrustumProjection(f32 _near, f32 _far, f32 top, f32 bottom, f32 left, f32 right); + FrustumProjection(f32 _near, f32 _far, const BoundBox2f& box); + ~FrustumProjection() override = default; + + Type getProjectionType() const override { return Projection::cType_Perspective; } + void doUpdateMatrix(Matrix44f* dst) const override; + void doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const override; + + void setNear(f32 near); + void setFar(f32 far); + void setTop(f32 top); + void setBottom(f32 bottom); + void setLeft(f32 left); + void setRight(f32 right); + + void setTBLR(f32 top, f32 bottom, f32 left, f32 right); + + void setBoundBox(const BoundBox2f& box); + + void createDividedProjection(FrustumProjection* dst, s32 partno_x, s32 partno_y, s32 divnum_x, + s32 divnum_y) const; + + f32 getNear() const override { return mNear; } + f32 getFar() const override { return mFar; } + f32 getTop() const { return mTop; } + f32 getBottom() const { return mBottom; } + f32 getLeft() const { return mLeft; } + f32 getRight() const { return mRight; } - f32 getNear() const override; - f32 getFar() const override; f32 getFovy() const override; f32 getAspect() const override; - void getOffset(Vector2f* offset) const override; - f32 getOffsetX() const; - f32 getOffsetY() const; - u32 getProjectionType() const override; + void getOffset(Vector2f* dst) const override; - void doUpdateMatrix(Matrix44f* mtx) const override; - void doScreenPosToCameraPosTo(Vector3f* cameraPos, const Vector3f& screenPos) const override; - void setTBLR(f32 top, f32 bottom, f32 left, f32 right); - void setBoundBox(BoundBox2f& boundBox); - void createDividedProjection(FrustumProjection* out, s32, s32, s32, s32) const; void setFovyAspectOffset(f32 fovy, f32 aspect, const Vector2f& offset); private: @@ -199,30 +252,35 @@ class DirectProjection : public Projection public: DirectProjection(); - DirectProjection(const Matrix44f& mtx, Graphics::DevicePosture posture); - ~DirectProjection() override; + DirectProjection(const Matrix44f* mtx, Graphics::DevicePosture posture); + ~DirectProjection() override = default; - void setProjectionMatrix(const Matrix44f& mtx, Graphics::DevicePosture posture); - f32 getNear() const override; - f32 getFar() const override; - f32 getFovy() const override; - f32 getAspect() const override; - void getOffset(Vector2f* offset) const override; void updateAttributesForDirectProjection() override; - void doUpdateMatrix(Matrix44f* mtx) const override; - void doScreenPosToCameraPosTo(Vector3f* cameraPos, const Vector3f& screenPos) const override; - u32 getProjectionType() const override; + Type getProjectionType() const override { return cType_Undefined; } + void doUpdateMatrix(Matrix44f* dst) const override; + + void setDirectProjectionMatrix(const Matrix44f* mtx, Graphics::DevicePosture posture); + + f32 getNear() const override { return mNear; } + f32 getFar() const override { return mFar; } + f32 getFovy() const override { return mFovy; } + + f32 getAspect() const override { return mAspect; } + void getOffset(Vector2f* offset) const override { *offset = mOffset; } + + void doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const override; private: - Matrix44f mProjectionMatrix; - f32 mNear; - f32 mFar; - f32 mFovy; - f32 mAspect; - Vector2f mOffset; - bool _f0; + Matrix44f mDirectMatrix = Matrix44f::ident; + f32 mNear = 0.0; + f32 mFar = 0.0; + f32 mFovy = 0.0; + f32 mAspect = 0.0; + Vector2f mOffset = Vector2f::zero; + bool someBool = true; }; +#ifdef cafe +static_assert(sizeof(FrustumProjection) == 0xAC, "sead::FrustumProjection size mismatch"); +#endif // cafe } // namespace sead - -#endif // SEAD_PROJECTION_H_ diff --git a/include/gfx/seadViewport.h b/include/gfx/seadViewport.h index 566aaf7c..a3601420 100644 --- a/include/gfx/seadViewport.h +++ b/include/gfx/seadViewport.h @@ -1,20 +1,18 @@ #pragma once +#include +#include #include -#include -#include +#include namespace sead { -template -class Ray; -class DrawContext; -class LogicalFrameBuffer; -class Projection; class Camera; +class Projection; class Viewport : public BoundBox2f { + SEAD_RTTI_BASE(Viewport) public: Viewport(); Viewport(float left, float top, float right, float bottom); @@ -23,17 +21,25 @@ class Viewport : public BoundBox2f virtual ~Viewport() = default; void setByFrameBuffer(const LogicalFrameBuffer& buffer); - void apply(DrawContext*, const LogicalFrameBuffer& buffer) const; + void getOnFrameBufferPos(Vector2f* out, const LogicalFrameBuffer& buffer) const; void getOnFrameBufferSize(Vector2f* out, const LogicalFrameBuffer& buffer) const; + + void apply(DrawContext*, const LogicalFrameBuffer& buffer) const; void applyViewport(DrawContext* context, const LogicalFrameBuffer& buffer) const; void applyScissor(DrawContext* context, const LogicalFrameBuffer& buffer) const; + void project(Vector2f*, const Vector3f&) const; void project(Vector2f*, const Vector2f&) const; void unproject(Vector3f*, const Vector2f&, const Projection&, const Camera&) const; - void unproject(Ray*, const Vector2f&, const Projection&, const Camera&) const; + void unprojectRay(Ray3f*, const Vector2f&, const Projection&, const Camera&) const; private: - Graphics::DevicePosture mDevicePosture; + Graphics::DevicePosture mDevicePosture = Graphics::getDefaultDevicePosture(); + Vector2f mDepthBounds = Vector2f(0.0f, 1.0f); }; +#ifdef cafe +static_assert(sizeof(Viewport) == 0x18, "sead::Viewport size mismatch"); +#endif // cafe + } // namespace sead diff --git a/include/math/seadGeometry.h b/include/math/seadGeometry.h new file mode 100644 index 00000000..1ae70d93 --- /dev/null +++ b/include/math/seadGeometry.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace sead +{ + +template +struct Ray +{ + Ray(); + + T position; + T direction; +}; + +namespace Geometry +{ +float calcSquaredDistancePointToRay(Vector2* point, Ray>* ray, float* scalar); +// float calcSquaredDistancePointToLine(Vector2* const, Line>* const, +// float*); float calcSquaredDistancePointToSegment(Vector3* const, Segment>* +// const, float*); float calcSquaredDistancePointToSegment(); +// float calcSquaredDistanceSegmentToSegment(Segment>* const, +// Segment>* const, float*, float*); +// float calcSquaredDistanceRayToSegment(Ray> const&, Segment>* const, +// float*, float*); +} // namespace Geometry +} // namespace sead diff --git a/modules/src/gfx/seadCamera.cpp b/modules/src/gfx/seadCamera.cpp index ae58e851..85a399a1 100644 --- a/modules/src/gfx/seadCamera.cpp +++ b/modules/src/gfx/seadCamera.cpp @@ -1,10 +1,87 @@ #include "gfx/seadCamera.h" +#include +#include #include "basis/seadRawPrint.h" +#include "math/seadMatrixCalcCommon.h" namespace sead { +Camera::Camera() = default; + Camera::~Camera() = default; +void Camera::getWorldPosByMatrix(Vector3f* dst) const +{ + f32 x = (-mMatrix(0, 0) * mMatrix(0, 3) - mMatrix(1, 0) * mMatrix(1, 3)) - + mMatrix(2, 0) * mMatrix(2, 3); + f32 y = (-mMatrix(0, 1) * mMatrix(0, 3) - mMatrix(1, 1) * mMatrix(1, 3)) - + mMatrix(2, 1) * mMatrix(2, 3); + f32 z = (-mMatrix(0, 2) * mMatrix(0, 3) - mMatrix(1, 2) * mMatrix(1, 3)) - + mMatrix(2, 2) * mMatrix(2, 3); + dst->set(x, y, z); +} + +void Camera::getLookVectorByMatrix(Vector3f* dst) const +{ + // Also known as the forward vector + auto vec = mMatrix.getRow(2); + dst->set(vec.x, vec.y, vec.z); +}; + +void Camera::getRightVectorByMatrix(Vector3f* dst) const +{ + auto vec = mMatrix.getRow(0); + dst->set(vec.x, vec.y, vec.z); +} + +void Camera::getUpVectorByMatrix(Vector3f* dst) const +{ + auto vec = mMatrix.getRow(1); + dst->set(vec.x, vec.y, vec.z); +}; + +void Camera::worldPosToCameraPosByMatrix(Vector3f* dst, const Vector3f& world_pos) const +{ + *dst = mMatrix * world_pos; +} + +void Camera::cameraPosToWorldPosByMatrix(Vector3f* dst, const Vector3f& camera_pos) const +{ + dst->x = mMatrix(0, 0) * camera_pos.x + mMatrix(1, 0) * camera_pos.y + + ((-(mMatrix(0, 3) * mMatrix(0, 0)) - mMatrix(1, 3) * mMatrix(1, 1)) - + mMatrix(2, 3) * mMatrix(2, 0)); + dst->y = mMatrix(0, 1) * camera_pos.x + mMatrix(1, 1) * camera_pos.y + + ((-(mMatrix(0, 3) * mMatrix(0, 1)) - mMatrix(1, 3) * mMatrix(1, 2)) - + mMatrix(2, 3) * mMatrix(2, 1)); + dst->z = mMatrix(0, 2) * camera_pos.x + mMatrix(1, 2) * camera_pos.y + + ((-(mMatrix(0, 3) * mMatrix(0, 2)) - mMatrix(1, 3) * mMatrix(1, 3)) - + mMatrix(2, 3) * mMatrix(2, 2)); +} + +void Camera::projectByMatrix(Vector2f* dst, const Vector3f& world_pos, const Projection& projection, + const Viewport& viewport) const +{ + auto temp = mMatrix * world_pos; + temp += mMatrix.getBase(3); + projection.project(dst, temp, viewport); +} + +void Camera::unprojectRayByMatrix(Ray* dst, const Vector3f& camera_pos) const +{ + dst->direction.x = mMatrix.getBase(0).dot(camera_pos); + dst->direction.y = mMatrix.getBase(1).dot(camera_pos); + dst->direction.z = mMatrix.getBase(2).dot(camera_pos); + dst->direction.normalize(); + + dst->position.x = ((-mMatrix(0, 0) * mMatrix(0, 3)) - mMatrix(1, 0) * mMatrix(1, 3)) - + mMatrix(2, 0) * mMatrix(2, 3); + dst->position.y = ((-mMatrix(0, 1) * mMatrix(0, 3)) - mMatrix(1, 1) * mMatrix(1, 3)) - + mMatrix(2, 1) * mMatrix(2, 3); + dst->position.z = ((-mMatrix(0, 2) * mMatrix(0, 3)) - mMatrix(1, 2) * mMatrix(1, 3)) - + mMatrix(2, 2) * mMatrix(2, 3); + dst->position *= -1.0f; +} + LookAtCamera::~LookAtCamera() = default; LookAtCamera::LookAtCamera(const Vector3f& pos, const Vector3f& at, const Vector3f& up) @@ -14,8 +91,12 @@ LookAtCamera::LookAtCamera(const Vector3f& pos, const Vector3f& at, const Vector mUp.normalize(); } -OrthoCamera::~OrthoCamera() = default; +void LookAtCamera::doUpdateMatrix(Matrix34f* dst) const {} DirectCamera::~DirectCamera() = default; +OrthoCamera::OrthoCamera() = default; + +OrthoCamera::~OrthoCamera() = default; + } // namespace sead diff --git a/modules/src/gfx/seadGraphics.cpp b/modules/src/gfx/seadGraphics.cpp new file mode 100644 index 00000000..49a3e132 --- /dev/null +++ b/modules/src/gfx/seadGraphics.cpp @@ -0,0 +1,14 @@ +#include + +namespace sead +{ + +Graphics* Graphics::sInstance = nullptr; + +Graphics::DevicePosture Graphics::sDefaultDevicePosture = Graphics::cDevicePosture_Same; +f32 Graphics::sDefaultDeviceZScale = 1.0f; +f32 Graphics::sDefaultDeviceZOffset = 0.0f; + +// TODO: lockDrawContext/unlockDrawContext unimpl'd; WiiU refcount lock design doesn't fit master's DrawLockContext. + +} // namespace sead diff --git a/modules/src/gfx/seadGraphicsContext.cpp b/modules/src/gfx/seadGraphicsContext.cpp new file mode 100644 index 00000000..745a15fb --- /dev/null +++ b/modules/src/gfx/seadGraphicsContext.cpp @@ -0,0 +1,193 @@ +#include + +namespace sead +{ + +GraphicsContext::GraphicsContext() +#ifdef cafe + + : + + mDepthTestEnable(true), mDepthWriteEnable(true), mDepthFunc(Graphics::cDepthFunc_LessEqual), + mCullingMode(Graphics::cCullingMode_Back) + + , + mBlendEnable(true), mBlendFactorSrcRGB(Graphics::cBlendFactor_SrcAlpha), + mBlendFactorSrcA(Graphics::cBlendFactor_SrcAlpha), + mBlendFactorDstRGB(Graphics::cBlendFactor_InvSrcAlpha), + mBlendFactorDstA(Graphics::cBlendFactor_InvSrcAlpha), + mBlendEquationRGB(Graphics::cBlendEquation_Add), + mBlendEquationA(Graphics::cBlendEquation_Add), mBlendConstantColor(1.0f, 1.0f, 1.0f, 1.0f) + + , + mAlphaTestEnable(false), mAlphaTestFunc(Graphics::cAlphaFunc_Greater), mAlphaTestRef(0.0f) + + , + mColorMaskR(true), mColorMaskG(true), mColorMaskB(true), mColorMaskA(true) + + , + mStencilTestEnable(false), mStencilTestFunc(Graphics::cStencilFunc_Never), mStencilTestRef(0), + mStencilTestMask(0xFFFFFFFF), mStencilOpFail(Graphics::cStencilOp_Keep), + mStencilOpZFail(Graphics::cStencilOp_Keep), mStencilOpZPass(Graphics::cStencilOp_Keep) + + , + mPolygonModeFront(Graphics::cPolygonMode_Fill), mPolygonModeBack(Graphics::cPolygonMode_Fill), + mPolygonOffsetFrontEnable(false), mPolygonOffsetBackEnable(false), + mPolygonOffsetPointLineEnable(false) +#endif // cafe +{ +} + +void GraphicsContext::apply() const +{ +#ifdef cafe + GX2SetDepthStencilControl( + static_cast(mDepthTestEnable), static_cast(mDepthWriteEnable), + static_cast(mDepthFunc), static_cast(mStencilTestEnable), + static_cast(mStencilTestEnable), + static_cast(mStencilTestFunc), + static_cast(mStencilOpZPass), + static_cast(mStencilOpZFail), + static_cast(mStencilOpFail), + static_cast(mStencilTestFunc), + static_cast(mStencilOpZPass), + static_cast(mStencilOpZFail), + static_cast(mStencilOpFail)); + + GX2SetStencilMask(mStencilTestMask, mStencilTestRef, + mStencilTestRef, // Bug: ref in place of write mask + mStencilTestMask, mStencilTestRef, mStencilTestRef); // ^^^ + + { + static const GX2Boolean cCullSettings[4][2] = {{GX2_ENABLE, GX2_DISABLE}, + {GX2_DISABLE, GX2_ENABLE}, + {GX2_DISABLE, GX2_DISABLE}, + {GX2_ENABLE, GX2_ENABLE}}; + const GX2Boolean* const& settings = cCullSettings[mCullingMode]; + + GX2SetPolygonControl( + GX2_FRONT_FACE_CCW, settings[0], settings[1], + static_cast(mPolygonModeFront != Graphics::cPolygonMode_Fill || + mPolygonModeBack != Graphics::cPolygonMode_Fill), + static_cast(mPolygonModeFront), + static_cast(mPolygonModeBack), + static_cast(mPolygonOffsetFrontEnable), + static_cast(mPolygonOffsetBackEnable), + static_cast(mPolygonOffsetPointLineEnable)); + } + + GX2SetColorControl( + GX2_LOGIC_OP_NONE, mBlendEnable ? 0xFF : 0, GX2_DISABLE, + static_cast(mColorMaskR || mColorMaskG || mColorMaskB || mColorMaskA)); + + GX2SetBlendControl(GX2_RENDER_TARGET_0, static_cast(mBlendFactorSrcRGB), + static_cast(mBlendFactorDstRGB), + static_cast(mBlendEquationRGB), GX2_ENABLE, + static_cast(mBlendFactorSrcA), + static_cast(mBlendFactorDstA), + static_cast(mBlendEquationA)); + + GX2SetBlendConstantColor(mBlendConstantColor.r, mBlendConstantColor.g, mBlendConstantColor.b, + mBlendConstantColor.a); + + GX2SetAlphaTest(static_cast(mAlphaTestEnable), + static_cast(mAlphaTestFunc), mAlphaTestRef); + + GX2SetTargetChannelMasks( + static_cast( + mColorMaskR * GX2_CHANNEL_MASK_R + mColorMaskG * GX2_CHANNEL_MASK_G + + mColorMaskB * GX2_CHANNEL_MASK_B + mColorMaskA * GX2_CHANNEL_MASK_A), + GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, + GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE); + + GX2SetAlphaToMask(GX2_DISABLE, GX2_ALPHA_TO_MASK_0); +#endif // cafe +} + +void GraphicsContext::applyAlphaTest() const +{ +#ifdef cafe + GX2SetAlphaTest(static_cast(mAlphaTestEnable), + static_cast(mAlphaTestFunc), mAlphaTestRef); +#endif // cafe +} + +void GraphicsContext::applyDepthAndStencilTest() const +{ +#ifdef cafe + GX2SetDepthStencilControl( + static_cast(mDepthTestEnable), static_cast(mDepthWriteEnable), + static_cast(mDepthFunc), static_cast(mStencilTestEnable), + static_cast(mStencilTestEnable), + static_cast(mStencilTestFunc), + static_cast(mStencilOpZPass), + static_cast(mStencilOpZFail), + static_cast(mStencilOpFail), + static_cast(mStencilTestFunc), + static_cast(mStencilOpZPass), + static_cast(mStencilOpZFail), + static_cast(mStencilOpFail)); + + GX2SetStencilMask(mStencilTestMask, mStencilTestRef, + mStencilTestRef, // Bug: ref in place of write mask + mStencilTestMask, mStencilTestRef, mStencilTestRef); // ^^^ +#endif // cafe +} + +void GraphicsContext::applyColorMask() const +{ +#ifdef cafe + GX2SetTargetChannelMasks( + static_cast( + mColorMaskR * GX2_CHANNEL_MASK_R + mColorMaskG * GX2_CHANNEL_MASK_G + + mColorMaskB * GX2_CHANNEL_MASK_B + mColorMaskA * GX2_CHANNEL_MASK_A), + GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, + GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE); +#endif // cafe +} + +void GraphicsContext::applyBlendAndFastZ() const +{ +#ifdef cafe + GX2SetColorControl( + GX2_LOGIC_OP_NONE, mBlendEnable ? 0xFF : 0, GX2_DISABLE, + static_cast(mColorMaskR || mColorMaskG || mColorMaskB || mColorMaskA)); + + GX2SetBlendControl(GX2_RENDER_TARGET_0, static_cast(mBlendFactorSrcRGB), + static_cast(mBlendFactorDstRGB), + static_cast(mBlendEquationRGB), GX2_ENABLE, + static_cast(mBlendFactorSrcA), + static_cast(mBlendFactorDstA), + static_cast(mBlendEquationA)); +#endif // cafe +} + +void GraphicsContext::applyBlendConstantColor() const +{ +#ifdef cafe + GX2SetBlendConstantColor(mBlendConstantColor.r, mBlendConstantColor.g, mBlendConstantColor.b, + mBlendConstantColor.a); +#endif // cafe +} + +void GraphicsContext::applyCullingAndPolygonModeAndPolygonOffset() const +{ +#ifdef cafe + static const GX2Boolean cCullSettings[4][2] = {{GX2_ENABLE, GX2_DISABLE}, + {GX2_DISABLE, GX2_ENABLE}, + {GX2_DISABLE, GX2_DISABLE}, + {GX2_ENABLE, GX2_ENABLE}}; + const GX2Boolean* const& settings = cCullSettings[mCullingMode]; + + GX2SetPolygonControl(GX2_FRONT_FACE_CCW, settings[0], settings[1], + static_cast(mPolygonModeFront != Graphics::cPolygonMode_Fill || + mPolygonModeBack != Graphics::cPolygonMode_Fill), + static_cast(mPolygonModeFront), + static_cast(mPolygonModeBack), + static_cast(mPolygonOffsetFrontEnable), + static_cast(mPolygonOffsetBackEnable), + static_cast(mPolygonOffsetPointLineEnable)); +#endif // cafe +} + +} // namespace sead diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 9cd07d2d..73908632 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -1,7 +1,8 @@ -#include - #include +#include #include +#include "math/seadMatrixCalcCommon.h" +#include "math/seadVectorCalcCommon.h" namespace sead { @@ -86,4 +87,454 @@ void Projection::unprojectRay(Ray* dst, const Vector3f& screen_pos, camera.unprojectRayByMatrix(dst, camera_pos); } +void Projection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const +{ + updateMatrixImpl_(); + f32 scale = 1.0f / (mMatrix(3, 3) + screen_pos.x * mMatrix(3, 0) + + screen_pos.y * mMatrix(3, 1) + screen_pos.z * mMatrix(3, 2)); + *dst = static_cast(mMatrix) * screen_pos; + *dst *= scale; +} + +namespace +{ + +void swapMatrixXY(Matrix44f* tgt) +{ + Vector4f x; + Vector4f y; + tgt->getRow(x, 0); + tgt->getRow(y, 1); + tgt->setRow(0, y); + tgt->setRow(1, x); +} + +} // namespace + +void Projection::doUpdateDeviceMatrix(Matrix44f* dst, const Matrix44f& src, + Graphics::DevicePosture pose) const +{ + *dst = src; + + switch (pose) + { + case Graphics::cDevicePosture_Same: + break; + case Graphics::cDevicePosture_RotateRight: + (*dst)(0, 0) *= -1; + (*dst)(0, 1) *= -1; + (*dst)(0, 2) *= -1; + (*dst)(0, 3) *= -1; + swapMatrixXY(dst); + break; + case Graphics::cDevicePosture_RotateLeft: + (*dst)(1, 0) *= -1; + (*dst)(1, 1) *= -1; + (*dst)(1, 2) *= -1; + (*dst)(1, 3) *= -1; + swapMatrixXY(dst); + break; + case Graphics::cDevicePosture_RotateHalfAround: + (*dst)(0, 0) *= -1; + (*dst)(0, 1) *= -1; + (*dst)(0, 2) *= -1; + (*dst)(0, 3) *= -1; + (*dst)(1, 0) *= -1; + (*dst)(1, 1) *= -1; + (*dst)(1, 2) *= -1; + (*dst)(1, 3) *= -1; + break; + case Graphics::cDevicePosture_FlipX: + (*dst)(0, 0) *= -1; + (*dst)(0, 1) *= -1; + (*dst)(0, 2) *= -1; + (*dst)(0, 3) *= -1; + break; + case Graphics::cDevicePosture_FlipY: + (*dst)(1, 0) *= -1; + (*dst)(1, 1) *= -1; + (*dst)(1, 2) *= -1; + (*dst)(1, 3) *= -1; + break; + default:; + // SEAD_ASSERTMSG(false, "Invalid DevicePosture(%d).", s32(pose)); + } + + (*dst)(2, 0) = (*dst)(2, 0) * mDeviceZScale; + (*dst)(2, 1) = (*dst)(2, 1) * mDeviceZScale; + + (*dst)(2, 2) = ((*dst)(2, 2) + (*dst)(3, 2) * mDeviceZOffset) * mDeviceZScale; + (*dst)(2, 3) = (*dst)(2, 3) * mDeviceZScale + (*dst)(3, 3) * mDeviceZOffset; +} + +PerspectiveProjection::PerspectiveProjection() +{ + setFovy_(mAngle); // 45 degrees +} + +PerspectiveProjection::PerspectiveProjection(f32 near, f32 far, f32 fovy_rad, f32 aspect) + : mNear(near), mFar(far), mAspect(aspect), mOffset(Vector2f::zero) +{ + setFovy_(fovy_rad); +} + +void PerspectiveProjection::set(f32 _near, f32 _far, f32 fovy_rad, f32 aspect) +{ + setNear(_near); + setFar(_far); + setFovy_(fovy_rad); + setAspect(aspect); +} + +void PerspectiveProjection::setFovy_(f32 fovy) +{ + mAngle = fovy; + + fovy *= 0.5f; + mFovySin = Mathf::sin(fovy); + mFovyCos = Mathf::cos(fovy); + mFovyTan = Mathf::tan(fovy); + + setDirty(); +} + +f32 PerspectiveProjection::getTop() const +{ + f32 clip_height = calcNearClipHeight_(); + f32 center_y = mOffset.y * clip_height; + return clip_height * 0.5f + center_y; +} + +f32 PerspectiveProjection::getBottom() const +{ + f32 clip_height = calcNearClipHeight_(); + f32 center_y = mOffset.y * clip_height; + return -clip_height * 0.5f + center_y; +} + +f32 PerspectiveProjection::getLeft() const +{ + f32 clip_width = calcNearClipWidth_(); + f32 center_x = mOffset.x * clip_width; + return -clip_width * 0.5f + center_x; +} + +f32 PerspectiveProjection::getRight() const +{ + f32 clip_width = calcNearClipWidth_(); + f32 center_x = mOffset.x * clip_width; + return clip_width * 0.5f + center_x; +} + +void PerspectiveProjection::doUpdateMatrix(Matrix44f* dst) const +{ + f32 clip_height = calcNearClipHeight_(); + f32 clip_width = calcNearClipWidth_(); + + f32 center_x = clip_width * mOffset.x; + f32 center_y = clip_height * mOffset.y; + + clip_height *= 0.5f; + clip_width *= 0.5f; + + f32 top = clip_height + center_y; + f32 bottom = -clip_height + center_y; + + f32 left = -clip_width + center_x; + f32 right = clip_width + center_x; + + f32 inv_size = 1.0f / (right - left); + + (*dst)(0, 0) = mNear * 2 * inv_size; + (*dst)(0, 1) = 0.0f; + (*dst)(0, 2) = (right + left) * inv_size; + (*dst)(0, 3) = 0.0f; + + inv_size = 1.0f / (top - bottom); + + (*dst)(1, 0) = 0.0f; + (*dst)(1, 1) = mNear * 2 * inv_size; + (*dst)(1, 2) = (top + bottom) * inv_size; + (*dst)(1, 3) = 0.0f; + + inv_size = 1.0f / (mFar - mNear); + + (*dst)(2, 0) = 0.0f; + (*dst)(2, 1) = 0.0f; + (*dst)(2, 2) = -(mFar + mNear) * inv_size; + (*dst)(2, 3) = -(mFar * 2 * mNear) * inv_size; + + (*dst)(3, 0) = 0.0f; + (*dst)(3, 1) = 0.0f; + (*dst)(3, 2) = -1.0f; + (*dst)(3, 3) = 0.0f; +} + +void PerspectiveProjection::doScreenPosToCameraPosTo(Vector3f* dst, + const Vector3f& screen_pos) const +{ + dst->set(0.0f, 0.0f, -mNear); + + dst->y = (calcNearClipHeight_() / 2) * (screen_pos.y + mOffset.y * 2); + dst->x = (calcNearClipWidth_() / 2) * (screen_pos.x + mOffset.x * 2); +} + +OrthoProjection::OrthoProjection() + : mNear(0.0), mFar(1.0), mTop(0.5), mBottom(-0.5), mLeft(-0.5), mRight(0.5) +{ +} + +OrthoProjection::OrthoProjection(f32 _near, f32 _far, f32 top, f32 bottom, f32 left, f32 right) + : mNear(_near), mFar(_far), mTop(top), mBottom(bottom), mLeft(left), mRight(right) +{ + setDirty(); +} + +OrthoProjection::OrthoProjection(f32 _near, f32 _far, const Viewport& vp) : mNear(_near), mFar(_far) +{ + setByViewport(vp); + setDirty(); +} + +f32 OrthoProjection::getAspect() const +{ + return (mRight - mLeft) / (mTop - mBottom); +} + +void OrthoProjection::getOffset(Vector2f* offset) const +{ + offset->x = ((float)0.5 * (mLeft + mRight)) / (mRight - mLeft); + offset->y = ((float)0.5 * (mTop + mBottom)) / (mTop - mBottom); +} + +void OrthoProjection::setNear(f32 near) +{ + mNear = near; + setDirty(); +} + +void OrthoProjection::setFar(f32 far) +{ + mFar = far; + setDirty(); +} + +void OrthoProjection::setTop(f32 top) +{ + mTop = top; + setDirty(); +} + +void OrthoProjection::setBottom(f32 bottom) +{ + mBottom = bottom; + setDirty(); +} + +void OrthoProjection::setLeft(f32 left) +{ + mLeft = left; + setDirty(); +} + +void OrthoProjection::setRight(f32 right) +{ + mRight = right; + setDirty(); +} + +void OrthoProjection::setTBLR(float top, float bottom, float left, float right) +{ + mTop = top; + mBottom = bottom; + mLeft = left; + mRight = right; + setDirty(); + // this->projectionType = ProjectionType::cOrthoProjection; +} + +void OrthoProjection::doUpdateMatrix(Matrix44f* dst) const +{ + f32 inv_size = (mRight - mLeft) * 0.5f; + + (*dst)(0, 0) = 1.0f / inv_size; + (*dst)(0, 1) = 0.0f; + (*dst)(0, 2) = 0.0f; + (*dst)(0, 3) = -0.5f * (mLeft + mRight) / inv_size; + + inv_size = 0.5f * (mTop - mBottom); + + (*dst)(1, 0) = 0; + (*dst)(1, 1) = 1.0f / inv_size; + (*dst)(1, 2) = 0; + (*dst)(1, 3) = -0.5f * (mTop + mBottom) / inv_size; + + inv_size = 0.5f * (mFar - mNear); + + (*dst)(2, 0) = 0; + (*dst)(2, 1) = 0; + (*dst)(2, 2) = -1.0f / inv_size; + (*dst)(2, 3) = -0.5f * (mNear * mFar) / inv_size; + + (*dst)(3, 0) = 0; + (*dst)(3, 1) = 0; + (*dst)(3, 2) = 0; + (*dst)(3, 3) = -1.0f; +} + +// NON-MATCHING: Adds an additional register for a multiplication +void OrthoProjection::setByViewport(const Viewport& vp) +{ + f32 halfY = vp.getHalfSizeY(); + f32 halfX = vp.getHalfSizeX(); + mTop = halfY; + mBottom = -halfY; + mLeft = -halfX; + mRight = halfX; + setDirty(); +} + +void OrthoProjection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const +{ + dst->x = 0.5f * ((mRight + mLeft) + screen_pos.x * (mRight - mLeft)); + dst->y = 0.5f * ((mTop + mBottom) + (screen_pos.y * (mTop - mBottom))); + dst->z = mNear; +} + +FrustumProjection::FrustumProjection(f32 _near, f32 _far, f32 top, f32 bottom, f32 left, f32 right) + : mNear(_near), mFar(_far), mTop(top), mBottom(bottom), mLeft(left), mRight(right) +{ + setDirty(); +} + +FrustumProjection::FrustumProjection(f32 _near, f32 _far, const BoundBox2f& box) + : mNear(_near), mFar(_far) +{ +} + +void FrustumProjection::doUpdateMatrix(Matrix44f* dst) const +{ + f32 inv_size = 1.0f / (mRight - mLeft); + + (*dst)(0, 0) = mNear * 2 * inv_size; + (*dst)(0, 1) = 0.0f; + (*dst)(0, 2) = (mLeft + mRight) * inv_size; + (*dst)(0, 3) = 0.0f; + + inv_size = 1.0f / (mTop - mBottom); + + (*dst)(1, 0) = 0.0f; + (*dst)(1, 1) = mNear * 2 * inv_size; + (*dst)(1, 2) = (mTop + mBottom) * inv_size; + (*dst)(1, 3) = 0.0f; + + inv_size = 1.0f / (mFar - mNear); + + (*dst)(2, 0) = 0.0f; + (*dst)(2, 1) = 0.0f; + (*dst)(2, 2) = -(mFar + mNear) * inv_size; + (*dst)(2, 3) = -(mFar * 2 * mNear) * inv_size; + + (*dst)(3, 0) = 0.0f; + (*dst)(3, 1) = 0.0f; + (*dst)(3, 2) = -1.0f; + (*dst)(3, 3) = 0.0f; +} + +void FrustumProjection::setNear(f32 near) +{ + mNear = near; + setDirty(); +} + +void FrustumProjection::setFar(f32 far) +{ + mFar = far; + setDirty(); +} + +void FrustumProjection::setTop(f32 top) +{ + mTop = top; + setDirty(); +} + +void FrustumProjection::setBottom(f32 bottom) +{ + mBottom = bottom; + setDirty(); +} + +void FrustumProjection::setLeft(f32 left) +{ + mLeft = left; + setDirty(); +} + +void FrustumProjection::setRight(f32 right) +{ + mRight = right; + setDirty(); +} + +f32 FrustumProjection::getFovy() const +{ + return 2 * Mathf::atan2(0.5f * (mTop - mBottom), getNear()); +} + +f32 FrustumProjection::getAspect() const +{ + return (mRight - mLeft) / (mTop - mBottom); +} + +void FrustumProjection::getOffset(Vector2f* dst) const +{ + float denom = mRight - mLeft; + dst->x = (float)0.5 * (mRight + mLeft) / denom; + + denom = mTop - mBottom; + dst->y = (float)0.5 * (mTop + mBottom) / denom; +} + +DirectProjection::DirectProjection() +{ + setDirty(); +} + +DirectProjection::DirectProjection(const Matrix44f* mtx, Graphics::DevicePosture posture) +{ + setDirectProjectionMatrix(mtx, posture); +} + +void DirectProjection::updateAttributesForDirectProjection() +{ + Matrix44f newMatrix; + newMatrix.setInverse(mDirectMatrix); +} + +void DirectProjection::doUpdateMatrix(Matrix44f* dst) const +{ + *dst = mDirectMatrix; +} + +void DirectProjection::setDirectProjectionMatrix(const Matrix44f* mtx, + Graphics::DevicePosture posture) +{ + mDirectMatrix = (*mtx); +} + +void DirectProjection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const +{ + Matrix44f inverseDirect; + inverseDirect.setInverse(mDirectMatrix); + f32 scale = 1.0f / (inverseDirect(3, 3) + screen_pos.x * inverseDirect(3, 0) + + screen_pos.y * inverseDirect(3, 1) + screen_pos.z * inverseDirect(3, 2)); + dst->x = scale * (inverseDirect(0, 3) + screen_pos.x * inverseDirect(0, 0) + + screen_pos.y * inverseDirect(0, 1) + screen_pos.z * inverseDirect(0, 2)); + dst->y = scale * (inverseDirect(1, 3) + screen_pos.x * inverseDirect(1, 0) + + screen_pos.y * inverseDirect(1, 1) + screen_pos.z * inverseDirect(1, 2)); + dst->z = scale * (inverseDirect(2, 3) + screen_pos.x * inverseDirect(2, 0) + + screen_pos.y * inverseDirect(2, 1) + screen_pos.z * inverseDirect(2, 2)); +} + } // namespace sead diff --git a/modules/src/gfx/seadViewport.cpp b/modules/src/gfx/seadViewport.cpp new file mode 100644 index 00000000..9de7d6e0 --- /dev/null +++ b/modules/src/gfx/seadViewport.cpp @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include "math/seadBoundBox.h" +#include "nn/gfx/gfx_StateInfo.h" + +namespace sead +{ + +Viewport::Viewport() +{ + setUndef(); +} + +Viewport::Viewport(f32 left, f32 top, f32 sizeX, f32 sizeY) + : BoundBox2f(left, top, left + sizeX, top + sizeY) +{ +} +Viewport::Viewport(const LogicalFrameBuffer& frame_buffer) +{ + setByFrameBuffer(frame_buffer); +} + +void Viewport::setByFrameBuffer(const LogicalFrameBuffer& frame_buffer) +{ + switch (mDevicePosture) + { + case Graphics::cDevicePosture_Same: + case Graphics::cDevicePosture_FlipX: + case Graphics::cDevicePosture_FlipY: + case Graphics::cDevicePosture_FlipXY: + set(0.0f, 0.0f, frame_buffer.getVirtualSize().x, frame_buffer.getVirtualSize().y); + break; + case Graphics::cDevicePosture_RotateRight: + case Graphics::cDevicePosture_RotateLeft: + set(0.0f, 0.0f, frame_buffer.getVirtualSize().y, frame_buffer.getVirtualSize().x); + break; + default:; + // SEAD_ASSERT_MSG(false, "Undefined DevicePosture(%d)", s32(mDevicePos)); + } +} + +void Viewport::getOnFrameBufferPos(Vector2f* dst, const LogicalFrameBuffer& fb) const +{ + *dst = getMin(); + + switch (mDevicePosture) + { + case Graphics::cDevicePosture_Same: + break; + case Graphics::cDevicePosture_RotateRight: + { + f32 y = (fb.getVirtualSize().y - getSizeX()) - dst->x; + dst->set(dst->y, y); + } + break; + case Graphics::cDevicePosture_RotateLeft: + { + f32 x = (fb.getVirtualSize().x - getSizeY()) - dst->y; + dst->set(x, dst->x); + } + break; + case Graphics::cDevicePosture_FlipXY: + { + f32 x = (fb.getVirtualSize().x - getSizeX()) - dst->x; + f32 y = (fb.getVirtualSize().y - getSizeY()) - dst->y; + dst->set(x, y); + } + break; + case Graphics::cDevicePosture_FlipX: + { + f32 x = (fb.getVirtualSize().x - getSizeX()) - dst->x; + dst->set(x, dst->y); + } + break; + case Graphics::cDevicePosture_FlipY: + { + f32 y = (fb.getVirtualSize().y - getSizeY()) - dst->y; + dst->set(dst->x, y); + } + break; + default:; + // SEAD_ASSERT_MSG(false, "Undefined DevicePosture(%d)", s32(mDevicePos)); + } + + dst->x /= fb.getVirtualSize().x; + dst->y /= fb.getVirtualSize().y; + dst->x *= fb.getPhysicalArea().getSizeX(); + dst->y *= fb.getPhysicalArea().getSizeY(); + dst->x = dst->x + fb.getPhysicalArea().getMin().x; + dst->y = dst->y + fb.getPhysicalArea().getMin().y; +} + +void Viewport::getOnFrameBufferSize(Vector2f* dst, const LogicalFrameBuffer& fb) const +{ + dst->set(getSizeX(), getSizeY()); + + switch (mDevicePosture) + { + case Graphics::cDevicePosture_Same: + case Graphics::cDevicePosture_FlipX: + case Graphics::cDevicePosture_FlipY: + case Graphics::cDevicePosture_FlipXY: + break; + case Graphics::cDevicePosture_RotateRight: + case Graphics::cDevicePosture_RotateLeft: + dst->set(dst->y, dst->x); + break; + default:; + // SEAD_ASSERT_MSG(false, "Undefined DevicePosture(%d)", s32(mDevicePos)); + } + + dst->x /= fb.getVirtualSize().x; + dst->y /= fb.getVirtualSize().y; + dst->x *= fb.getPhysicalArea().getSizeX(); + dst->y *= fb.getPhysicalArea().getSizeY(); +} + +void Viewport::apply(DrawContext* context, const LogicalFrameBuffer& buffer) const +{ + sead::Vector2f real_pos; + getOnFrameBufferPos(&real_pos, buffer); + + sead::Vector2f real_size; + getOnFrameBufferSize(&real_size, buffer); + + SEAD_ASSERT(buffer.getPhysicalArea().isInside(real_pos) && + buffer.getPhysicalArea().isInside(real_pos + real_size)); + + real_pos.y = (buffer.getPhysicalArea().getSizeY() - real_size.y) - real_pos.y; + + sead::Graphics::instance()->setViewportRealPosition(real_pos.x, real_pos.y, real_size.x, + real_size.y); + sead::Graphics::instance()->setScissorRealPosition(real_pos.x, real_pos.y, real_size.x, + real_size.y); + context->getCommandBuffer()->SetDepthBounds(mDepthBounds.x, mDepthBounds.y); +} + +void Viewport::applyViewport(DrawContext* context, const LogicalFrameBuffer& buffer) const +{ + sead::Vector2f real_pos; + getOnFrameBufferPos(&real_pos, buffer); + + sead::Vector2f real_size; + getOnFrameBufferSize(&real_size, buffer); + + SEAD_ASSERT(buffer.getPhysicalArea().isInside(real_pos) && + buffer.getPhysicalArea().isInside(real_pos + real_size)); + + real_pos.y = (buffer.getPhysicalArea().getSizeY() - real_size.y) - real_pos.y; + // real_pos.x = (buffer.getPhysicalArea().getSizeX() - real_size.x) - real_pos.x; + + sead::Graphics::instance()->setViewportRealPosition(real_pos.x, real_pos.y, real_size.x, + real_size.y); +} + +void Viewport::applyScissor(DrawContext* context, const LogicalFrameBuffer& buffer) const +{ + sead::Vector2f real_pos; + getOnFrameBufferPos(&real_pos, buffer); + + sead::Vector2f real_size; + getOnFrameBufferSize(&real_size, buffer); + + SEAD_ASSERT(buffer.getPhysicalArea().isInside(real_pos) && + buffer.getPhysicalArea().isInside(real_pos + real_size)); + + real_pos.y = (buffer.getPhysicalArea().getSizeY() - real_size.y) - real_pos.y; + + sead::Graphics::instance()->setScissorRealPosition(real_pos.x, real_pos.y, real_size.x, + real_size.y); +} + +void Viewport::project(Vector2f* aVec, const Vector3f& bVec) const +{ + aVec->x = getHalfSizeX() * bVec.x; + aVec->y = getHalfSizeY() * bVec.y; +} + +void Viewport::project(Vector2f* aVec, const Vector2f& bVec) const +{ + aVec->x = getHalfSizeX() * bVec.x; + aVec->y = getHalfSizeY() * bVec.y; +} + +void Viewport::unproject(Vector3f* dst, const Vector2f& some2Vec, const Projection& projection, + const Camera& camera) const +{ + Vector3f screenPos; + screenPos.x = some2Vec.x / getHalfSizeX(); + screenPos.y = some2Vec.y / getHalfSizeY(); + screenPos.z = 0.0f; + projection.unproject(dst, screenPos, camera); +} + +void Viewport::unprojectRay(Ray* dst, const Vector2f& some2Vec, + const Projection& projection, const Camera& camera) const +{ + Vector3f screenPos; + screenPos.x = some2Vec.x / getHalfSizeX(); + screenPos.y = some2Vec.y / getHalfSizeY(); + screenPos.z = 0.0f; + projection.unprojectRay(dst, screenPos, camera); +} + +} // namespace sead diff --git a/modules/src/math/seadGeometry.cpp b/modules/src/math/seadGeometry.cpp new file mode 100644 index 00000000..0efcdf76 --- /dev/null +++ b/modules/src/math/seadGeometry.cpp @@ -0,0 +1,25 @@ +#include + +namespace sead +{ + +float Geometry::calcSquaredDistancePointToRay(Vector2* point, Ray>* ray, + float* scalar) +{ + auto diff = *point - ray->position; + + auto numerator = diff.dot(ray->direction); + auto squaredLength = diff.squaredLength(); + if (numerator < 0.0f) + { + numerator = 0.0f; + squaredLength = diff.squaredLength(); + } + if (scalar != nullptr) + { + *scalar = numerator; + } + return squaredLength; +} + +} // namespace sead From e473dc2f446c8c7758230b0d8bb9d15af7d75f2d Mon Sep 17 00:00:00 2001 From: AboodXD Date: Mon, 17 Apr 2023 18:17:13 +0400 Subject: [PATCH 03/22] engine/geom: Add Segment --- CMakeLists.txt | 2 -- include/geom/seadLine.h | 48 ++++++++++++++++++++++++++++++++++ include/gfx/seadProjection.h | 2 +- include/math/seadGeometry.h | 25 +++++------------- modules/src/gfx/seadCamera.cpp | 2 +- 5 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 include/geom/seadLine.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3740802f..f4ef6b99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,6 @@ add_library(sead OBJECT include/math/seadBoundBox.h include/math/seadBoundBox.hpp - include/math/seadGeometry.h include/math/seadMathBase.h include/math/seadMathCalcCommon.h include/math/seadMathCalcCommon.hpp @@ -157,7 +156,6 @@ add_library(sead OBJECT include/math/seadVectorCalcCommon.hpp include/math/seadVectorFwd.h modules/src/math/seadBoundBox.cpp - modules/src/math/seadGeometry.cpp modules/src/math/seadMathCalcCommon.cpp modules/src/math/seadMatrix.cpp modules/src/math/seadQuat.cpp diff --git a/include/geom/seadLine.h b/include/geom/seadLine.h new file mode 100644 index 00000000..4a624717 --- /dev/null +++ b/include/geom/seadLine.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +namespace sead +{ + +template +class Segment +{ +public: + using T = typename VectorType::ValueType; + +public: + Segment() : mP0(VectorType::zero), mP1(VectorType::ex) {} + Segment(const VectorType& p0, const VectorType& p1) : mP0(p0), mP1(p1) {} + + const VectorType& getPos0() const { return mP0; } + void setPos0(const VectorType& p0) { mP0 = p0; } + + const VectorType& getPos1() const { return mP1; } + void setPos1(const VectorType& p1) { mP1 = p1; } + +private: + VectorType mP0; + VectorType mP1; +}; + +using Segment2f = Segment; +using Segment3f = Segment; + +#ifdef cafe +static_assert(sizeof(Segment2f) == 0x10, "sead::Segment size mismatch"); +static_assert(sizeof(Segment3f) == 0x18, "sead::Segment size mismatch"); +#endif // cafe + +template +class Ray +{ +public: + T position; + T direction; +}; + +using Ray2f = Ray; +using Ray3f = Ray; + +} // namespace sead diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index 25625615..8c67b34d 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -138,7 +138,7 @@ class PerspectiveProjection : public Projection f32 mFovySin; f32 mFovyCos; f32 mFovyTan; - f32 mAspect = 1.333333f; + f32 mAspect = 4.0f / 3.0f; Vector2f mOffset = Vector2f::zero; }; #ifdef cafe diff --git a/include/math/seadGeometry.h b/include/math/seadGeometry.h index 1ae70d93..43877782 100644 --- a/include/math/seadGeometry.h +++ b/include/math/seadGeometry.h @@ -1,28 +1,17 @@ #pragma once +#include #include namespace sead { - -template -struct Ray -{ - Ray(); - - T position; - T direction; -}; - namespace Geometry { -float calcSquaredDistancePointToRay(Vector2* point, Ray>* ray, float* scalar); -// float calcSquaredDistancePointToLine(Vector2* const, Line>* const, -// float*); float calcSquaredDistancePointToSegment(Vector3* const, Segment>* -// const, float*); float calcSquaredDistancePointToSegment(); -// float calcSquaredDistanceSegmentToSegment(Segment>* const, -// Segment>* const, float*, float*); -// float calcSquaredDistanceRayToSegment(Ray> const&, Segment>* const, -// float*, float*); +float calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, float* scalar); +// float calcSquaredDistancePointToLine(Vector2f* const, Line2f* const, float*); +// float calcSquaredDistancePointToSegment(Vector3f* const, Segment3f* const, float*); +// float calcSquaredDistancePointToSegment(); +// float calcSquaredDistanceSegmentToSegment(Segment2f* const, Segment2f* const, float*, float*); +// float calcSquaredDistanceRayToSegment(Ray2f const&, Segment2f* const, float*, float*); } // namespace Geometry } // namespace sead diff --git a/modules/src/gfx/seadCamera.cpp b/modules/src/gfx/seadCamera.cpp index 85a399a1..a52cf758 100644 --- a/modules/src/gfx/seadCamera.cpp +++ b/modules/src/gfx/seadCamera.cpp @@ -42,7 +42,7 @@ void Camera::getUpVectorByMatrix(Vector3f* dst) const void Camera::worldPosToCameraPosByMatrix(Vector3f* dst, const Vector3f& world_pos) const { - *dst = mMatrix * world_pos; + dst->setMul(mMatrix, world_pos); } void Camera::cameraPosToWorldPosByMatrix(Vector3f* dst, const Vector3f& camera_pos) const From 20a9e8e4b8d5e8903ab63794edd6648b5e076480 Mon Sep 17 00:00:00 2001 From: Esras Date: Sun, 9 Aug 2026 12:41:05 -0600 Subject: [PATCH 04/22] Add a vectorized copy function for 4x4 f32 Matrices, guarded by NNSDK. Matched matrix copies in Projection functions in BotW. --- include/math/seadMatrixCalcCommon.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/math/seadMatrixCalcCommon.hpp b/include/math/seadMatrixCalcCommon.hpp index de6a03f2..bdc1071a 100644 --- a/include/math/seadMatrixCalcCommon.hpp +++ b/include/math/seadMatrixCalcCommon.hpp @@ -1991,6 +1991,19 @@ void Matrix44CalcCommon::copy(Base& o, const Base& n) o.m[3][3] = n.m[3][3]; } +#ifdef NNSDK + +template <> +inline void Matrix44CalcCommon::copy(Base& o, const Base& n) +{ + for (int i = 0; i < 4; ++i) + { + vst1q_f32(o.m[i], vld1q_f32(n.m[i])); + } +} + +#endif + #ifdef cafe template <> From 8dfce9d8f5f0fff4a3f77e8bf2b42da43c03895c Mon Sep 17 00:00:00 2001 From: Esras Date: Sun, 9 Aug 2026 18:29:18 -0600 Subject: [PATCH 05/22] With copious help from GRAnimated (read: linked me the matched function), Projection::doUpdateDeviceMatrix matches. --- modules/src/gfx/seadProjection.cpp | 60 +++++++++++------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 73908632..bad235dc 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -96,21 +96,21 @@ void Projection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_ *dst *= scale; } -namespace +static void swapMatrixXY(Matrix44f* mtx) { + Vector4f x = mtx->getRow(0); + mtx->setRow(0, mtx->getRow(1)); + mtx->setRow(1, x); +} -void swapMatrixXY(Matrix44f* tgt) +static void negateRow(Matrix44f* mtx, s32 row) { - Vector4f x; - Vector4f y; - tgt->getRow(x, 0); - tgt->getRow(y, 1); - tgt->setRow(0, y); - tgt->setRow(1, x); + (*mtx)(row, 0) *= -1; + (*mtx)(row, 1) *= -1; + (*mtx)(row, 2) *= -1; + (*mtx)(row, 3) *= -1; } -} // namespace - void Projection::doUpdateDeviceMatrix(Matrix44f* dst, const Matrix44f& src, Graphics::DevicePosture pose) const { @@ -120,49 +120,31 @@ void Projection::doUpdateDeviceMatrix(Matrix44f* dst, const Matrix44f& src, { case Graphics::cDevicePosture_Same: break; - case Graphics::cDevicePosture_RotateRight: - (*dst)(0, 0) *= -1; - (*dst)(0, 1) *= -1; - (*dst)(0, 2) *= -1; - (*dst)(0, 3) *= -1; + case Graphics::cDevicePosture_RotateLeft: + negateRow(dst, 1); swapMatrixXY(dst); break; - case Graphics::cDevicePosture_RotateLeft: - (*dst)(1, 0) *= -1; - (*dst)(1, 1) *= -1; - (*dst)(1, 2) *= -1; - (*dst)(1, 3) *= -1; + case Graphics::cDevicePosture_RotateRight: + negateRow(dst, 0); swapMatrixXY(dst); break; case Graphics::cDevicePosture_RotateHalfAround: - (*dst)(0, 0) *= -1; - (*dst)(0, 1) *= -1; - (*dst)(0, 2) *= -1; - (*dst)(0, 3) *= -1; - (*dst)(1, 0) *= -1; - (*dst)(1, 1) *= -1; - (*dst)(1, 2) *= -1; - (*dst)(1, 3) *= -1; + negateRow(dst, 0); + negateRow(dst, 1); break; case Graphics::cDevicePosture_FlipX: - (*dst)(0, 0) *= -1; - (*dst)(0, 1) *= -1; - (*dst)(0, 2) *= -1; - (*dst)(0, 3) *= -1; + negateRow(dst, 0); break; case Graphics::cDevicePosture_FlipY: - (*dst)(1, 0) *= -1; - (*dst)(1, 1) *= -1; - (*dst)(1, 2) *= -1; - (*dst)(1, 3) *= -1; + for (s32 i = 0; i < 4; ++i) + (*dst)(1, i) *= -1; + break; + default: break; - default:; - // SEAD_ASSERTMSG(false, "Invalid DevicePosture(%d).", s32(pose)); } (*dst)(2, 0) = (*dst)(2, 0) * mDeviceZScale; (*dst)(2, 1) = (*dst)(2, 1) * mDeviceZScale; - (*dst)(2, 2) = ((*dst)(2, 2) + (*dst)(3, 2) * mDeviceZOffset) * mDeviceZScale; (*dst)(2, 3) = (*dst)(2, 3) * mDeviceZScale + (*dst)(3, 3) * mDeviceZOffset; } From b3dbe2aec7c59f5aa09198459be74b4a4a2dff77 Mon Sep 17 00:00:00 2001 From: Esras Date: Sun, 9 Aug 2026 20:58:07 -0600 Subject: [PATCH 06/22] Minor fixing up to names / templates for Geometry and Segment. --- include/geom/seadLine.h | 25 +++++++++++-------------- include/math/seadGeometry.h | 2 +- modules/src/gfx/seadCamera.cpp | 24 ++++++++++++------------ modules/src/math/seadGeometry.cpp | 16 +++++++++------- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/include/geom/seadLine.h b/include/geom/seadLine.h index 4a624717..abbc9f7f 100644 --- a/include/geom/seadLine.h +++ b/include/geom/seadLine.h @@ -5,25 +5,22 @@ namespace sead { -template +template class Segment { public: - using T = typename VectorType::ValueType; - -public: - Segment() : mP0(VectorType::zero), mP1(VectorType::ex) {} - Segment(const VectorType& p0, const VectorType& p1) : mP0(p0), mP1(p1) {} + Segment() = default; + Segment(const T& p0, const T& p1) : mP0(p0), mP1(p1) {} - const VectorType& getPos0() const { return mP0; } - void setPos0(const VectorType& p0) { mP0 = p0; } + const T& getPos0() const { return mP0; } + void setPos0(const T& p0) { mP0 = p0; } - const VectorType& getPos1() const { return mP1; } - void setPos1(const VectorType& p1) { mP1 = p1; } + const T& getPos1() const { return mP1; } + void setPos1(const T& p1) { mP1 = p1; } private: - VectorType mP0; - VectorType mP1; + T mP0 = T::zero; + T mP1 = T::ex; }; using Segment2f = Segment; @@ -38,8 +35,8 @@ template class Ray { public: - T position; - T direction; + T mP; + T mD; }; using Ray2f = Ray; diff --git a/include/math/seadGeometry.h b/include/math/seadGeometry.h index 43877782..70dd43e8 100644 --- a/include/math/seadGeometry.h +++ b/include/math/seadGeometry.h @@ -7,7 +7,7 @@ namespace sead { namespace Geometry { -float calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, float* scalar); +float calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, f32* closestRayPos); // float calcSquaredDistancePointToLine(Vector2f* const, Line2f* const, float*); // float calcSquaredDistancePointToSegment(Vector3f* const, Segment3f* const, float*); // float calcSquaredDistancePointToSegment(); diff --git a/modules/src/gfx/seadCamera.cpp b/modules/src/gfx/seadCamera.cpp index a52cf758..2888ce33 100644 --- a/modules/src/gfx/seadCamera.cpp +++ b/modules/src/gfx/seadCamera.cpp @@ -68,18 +68,18 @@ void Camera::projectByMatrix(Vector2f* dst, const Vector3f& world_pos, const Pro void Camera::unprojectRayByMatrix(Ray* dst, const Vector3f& camera_pos) const { - dst->direction.x = mMatrix.getBase(0).dot(camera_pos); - dst->direction.y = mMatrix.getBase(1).dot(camera_pos); - dst->direction.z = mMatrix.getBase(2).dot(camera_pos); - dst->direction.normalize(); - - dst->position.x = ((-mMatrix(0, 0) * mMatrix(0, 3)) - mMatrix(1, 0) * mMatrix(1, 3)) - - mMatrix(2, 0) * mMatrix(2, 3); - dst->position.y = ((-mMatrix(0, 1) * mMatrix(0, 3)) - mMatrix(1, 1) * mMatrix(1, 3)) - - mMatrix(2, 1) * mMatrix(2, 3); - dst->position.z = ((-mMatrix(0, 2) * mMatrix(0, 3)) - mMatrix(1, 2) * mMatrix(1, 3)) - - mMatrix(2, 2) * mMatrix(2, 3); - dst->position *= -1.0f; + dst->mD.x = mMatrix.getBase(0).dot(camera_pos); + dst->mD.y = mMatrix.getBase(1).dot(camera_pos); + dst->mD.z = mMatrix.getBase(2).dot(camera_pos); + dst->mD.normalize(); + + dst->mP.x = ((-mMatrix(0, 0) * mMatrix(0, 3)) - mMatrix(1, 0) * mMatrix(1, 3)) - + mMatrix(2, 0) * mMatrix(2, 3); + dst->mP.y = ((-mMatrix(0, 1) * mMatrix(0, 3)) - mMatrix(1, 1) * mMatrix(1, 3)) - + mMatrix(2, 1) * mMatrix(2, 3); + dst->mP.z = ((-mMatrix(0, 2) * mMatrix(0, 3)) - mMatrix(1, 2) * mMatrix(1, 3)) - + mMatrix(2, 2) * mMatrix(2, 3); + dst->mP *= -1.0f; } LookAtCamera::~LookAtCamera() = default; diff --git a/modules/src/math/seadGeometry.cpp b/modules/src/math/seadGeometry.cpp index 0efcdf76..2e427033 100644 --- a/modules/src/math/seadGeometry.cpp +++ b/modules/src/math/seadGeometry.cpp @@ -3,21 +3,23 @@ namespace sead { -float Geometry::calcSquaredDistancePointToRay(Vector2* point, Ray>* ray, - float* scalar) +// BUG: returns the distance from point to ray origin, ignoring its direction +// (closestRayPos is fine) +float Geometry::calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, f32* closestRayPos) { - auto diff = *point - ray->position; + Vector2f diff = *point - ray->mP; + + f32 numerator = diff.dot(ray->mD); + f32 squaredLength = diff.squaredLength(); - auto numerator = diff.dot(ray->direction); - auto squaredLength = diff.squaredLength(); if (numerator < 0.0f) { numerator = 0.0f; squaredLength = diff.squaredLength(); } - if (scalar != nullptr) + if (closestRayPos != nullptr) { - *scalar = numerator; + *closestRayPos = numerator; } return squaredLength; } From 6a91967e4cffccb1057b349385561c5feda8d459 Mon Sep 17 00:00:00 2001 From: Esras Date: Mon, 10 Aug 2026 09:29:01 -0600 Subject: [PATCH 07/22] Match PerspectiveProjection::getOffset, does assignment based on individual elements instead of vector assignment. --- include/gfx/seadProjection.h | 2 +- modules/src/gfx/seadProjection.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index 8c67b34d..30e24f37 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -113,7 +113,7 @@ class PerspectiveProjection : public Projection f32 getFar() const override { return mFar; } f32 getFovy() const override { return mAngle; } f32 getAspect() const override { return mAspect; } - void getOffset(Vector2f* offset) const override { offset->set(mOffset); } + void getOffset(Vector2f* offset) const override; f32 getTop() const; f32 getBottom() const; diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index bad235dc..b955ab39 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -180,6 +180,12 @@ void PerspectiveProjection::setFovy_(f32 fovy) setDirty(); } +void PerspectiveProjection::getOffset(Vector2f* offset) const +{ + offset->x = mOffset.x; + offset->y = mOffset.y; +} + f32 PerspectiveProjection::getTop() const { f32 clip_height = calcNearClipHeight_(); From 1169fbce3089c6d75dbab4a5d748dcf317b88552 Mon Sep 17 00:00:00 2001 From: Esras Date: Tue, 11 Aug 2026 10:29:37 -0600 Subject: [PATCH 08/22] Match the remaining Projection functions in sead against BotW. --- include/gfx/seadProjection.h | 15 +-- include/gfx/seadViewport.h | 2 + modules/src/gfx/seadProjection.cpp | 183 +++++++++++++++++++++++------ 3 files changed, 158 insertions(+), 42 deletions(-) diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index 30e24f37..965acb0f 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -93,7 +93,8 @@ class PerspectiveProjection : public Projection mFar = far; setDirty(); } - void setFovx(f32 fovx); + void setFovx(f32 fovx); // Unused, potentially setFovy_(2 * Mathf::atan2(Mathf::tan(fovx * + // 0.5f), mAspect)); void setFovy(f32 fovy) { setFovy_(fovy); } void setAspect(f32 aspect) { @@ -134,7 +135,7 @@ class PerspectiveProjection : public Projection f32 mNear = 1.0f; f32 mFar = 10000.0f; - f32 mAngle = numbers::pi / 2.0f; + f32 mAngle; f32 mFovySin; f32 mFovyCos; f32 mFovyTan; @@ -252,14 +253,14 @@ class DirectProjection : public Projection public: DirectProjection(); - DirectProjection(const Matrix44f* mtx, Graphics::DevicePosture posture); + DirectProjection(const Matrix44f& mtx, Graphics::DevicePosture posture); ~DirectProjection() override = default; void updateAttributesForDirectProjection() override; Type getProjectionType() const override { return cType_Undefined; } void doUpdateMatrix(Matrix44f* dst) const override; - void setDirectProjectionMatrix(const Matrix44f* mtx, Graphics::DevicePosture posture); + void setProjectionMatrix(const Matrix44f& mtx, Graphics::DevicePosture posture); f32 getNear() const override { return mNear; } f32 getFar() const override { return mFar; } @@ -271,13 +272,13 @@ class DirectProjection : public Projection void doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const override; private: - Matrix44f mDirectMatrix = Matrix44f::ident; + Matrix44f mDirectMatrix; f32 mNear = 0.0; f32 mFar = 0.0; f32 mFovy = 0.0; f32 mAspect = 0.0; - Vector2f mOffset = Vector2f::zero; - bool someBool = true; + Vector2f mOffset = {0.0f, 0.0f}; + bool mAttributesDirty = true; }; #ifdef cafe static_assert(sizeof(FrustumProjection) == 0xAC, "sead::FrustumProjection size mismatch"); diff --git a/include/gfx/seadViewport.h b/include/gfx/seadViewport.h index a3601420..2347d14c 100644 --- a/include/gfx/seadViewport.h +++ b/include/gfx/seadViewport.h @@ -34,6 +34,8 @@ class Viewport : public BoundBox2f void unproject(Vector3f*, const Vector2f&, const Projection&, const Camera&) const; void unprojectRay(Ray3f*, const Vector2f&, const Projection&, const Camera&) const; + Graphics::DevicePosture getDevicePosture() const { return mDevicePosture; } + private: Graphics::DevicePosture mDevicePosture = Graphics::getDefaultDevicePosture(); Vector2f mDepthBounds = Vector2f(0.0f, 1.0f); diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index b955ab39..1afb2bc0 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -111,6 +111,14 @@ static void negateRow(Matrix44f* mtx, s32 row) (*mtx)(row, 3) *= -1; } +static void negateMatrixRow(Matrix44f* mtx, s32 row) +{ + Vector4f* p = reinterpret_cast(mtx) + row; + Vector4f v = *p; + v.negate(); + *p = v; +} + void Projection::doUpdateDeviceMatrix(Matrix44f* dst, const Matrix44f& src, Graphics::DevicePosture pose) const { @@ -151,7 +159,7 @@ void Projection::doUpdateDeviceMatrix(Matrix44f* dst, const Matrix44f& src, PerspectiveProjection::PerspectiveProjection() { - setFovy_(mAngle); // 45 degrees + setFovy_(numbers::pi / 4.0f); // 45 degrees } PerspectiveProjection::PerspectiveProjection(f32 near, f32 far, f32 fovy_rad, f32 aspect) @@ -270,6 +278,7 @@ void PerspectiveProjection::doScreenPosToCameraPosTo(Vector3f* dst, OrthoProjection::OrthoProjection() : mNear(0.0), mFar(1.0), mTop(0.5), mBottom(-0.5), mLeft(-0.5), mRight(0.5) { + setDirty(); } OrthoProjection::OrthoProjection(f32 _near, f32 _far, f32 top, f32 bottom, f32 left, f32 right) @@ -280,7 +289,11 @@ OrthoProjection::OrthoProjection(f32 _near, f32 _far, f32 top, f32 bottom, f32 l OrthoProjection::OrthoProjection(f32 _near, f32 _far, const Viewport& vp) : mNear(_near), mFar(_far) { - setByViewport(vp); + mTop = 0.5f * vp.getSizeY(); + mBottom = -0.5f * vp.getSizeY(); + mLeft = -0.5f * vp.getSizeX(); + mRight = 0.5f * vp.getSizeX(); + setDevicePosture(vp.getDevicePosture()); setDirty(); } @@ -343,50 +356,53 @@ void OrthoProjection::setTBLR(float top, float bottom, float left, float right) void OrthoProjection::doUpdateMatrix(Matrix44f* dst) const { + f32 sum_x = mLeft + mRight; + f32 sum_y = mTop + mBottom; f32 inv_size = (mRight - mLeft) * 0.5f; (*dst)(0, 0) = 1.0f / inv_size; (*dst)(0, 1) = 0.0f; (*dst)(0, 2) = 0.0f; - (*dst)(0, 3) = -0.5f * (mLeft + mRight) / inv_size; + (*dst)(0, 3) = sum_x * -0.5f / inv_size; - inv_size = 0.5f * (mTop - mBottom); + inv_size = (mTop - mBottom) * 0.5f; (*dst)(1, 0) = 0; (*dst)(1, 1) = 1.0f / inv_size; (*dst)(1, 2) = 0; - (*dst)(1, 3) = -0.5f * (mTop + mBottom) / inv_size; + (*dst)(1, 3) = sum_y * -0.5f / inv_size; - inv_size = 0.5f * (mFar - mNear); + f32 inv_depth = 1.0f / (mFar - mNear); (*dst)(2, 0) = 0; (*dst)(2, 1) = 0; - (*dst)(2, 2) = -1.0f / inv_size; - (*dst)(2, 3) = -0.5f * (mNear * mFar) / inv_size; + (*dst)(2, 2) = inv_depth * -2.0f; + (*dst)(2, 3) = -(inv_depth * (mNear + mFar)); (*dst)(3, 0) = 0; (*dst)(3, 1) = 0; (*dst)(3, 2) = 0; - (*dst)(3, 3) = -1.0f; + (*dst)(3, 3) = 1.0f; } -// NON-MATCHING: Adds an additional register for a multiplication void OrthoProjection::setByViewport(const Viewport& vp) { - f32 halfY = vp.getHalfSizeY(); - f32 halfX = vp.getHalfSizeX(); - mTop = halfY; - mBottom = -halfY; - mLeft = -halfX; - mRight = halfX; + f32 top = 0.5f * vp.getSizeY(); + f32 bottom = -0.5f * vp.getSizeY(); + f32 right = 0.5f * vp.getSizeX(); + f32 left = -0.5f * vp.getSizeX(); + mTop = top; + mBottom = bottom; + mLeft = left; + mRight = right; setDirty(); } void OrthoProjection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const { - dst->x = 0.5f * ((mRight + mLeft) + screen_pos.x * (mRight - mLeft)); - dst->y = 0.5f * ((mTop + mBottom) + (screen_pos.y * (mTop - mBottom))); - dst->z = mNear; + dst->x = screen_pos.x * (mRight - mLeft) * 0.5f + (mRight + mLeft) * 0.5f; + dst->y = screen_pos.y * (mTop - mBottom) * 0.5f + (mTop + mBottom) * 0.5f; + dst->z = -mNear; } FrustumProjection::FrustumProjection(f32 _near, f32 _far, f32 top, f32 bottom, f32 left, f32 right) @@ -429,6 +445,13 @@ void FrustumProjection::doUpdateMatrix(Matrix44f* dst) const (*dst)(3, 3) = 0.0f; } +void FrustumProjection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const +{ + dst->z = -mNear; + dst->x = (mRight - mLeft) * screen_pos.x * 0.5f + (mRight + mLeft) * 0.5f; + dst->y = (mTop - mBottom) * screen_pos.y * 0.5f + (mTop + mBottom) * 0.5f; +} + void FrustumProjection::setNear(f32 near) { mNear = near; @@ -484,20 +507,72 @@ void FrustumProjection::getOffset(Vector2f* dst) const dst->y = (float)0.5 * (mTop + mBottom) / denom; } -DirectProjection::DirectProjection() +DirectProjection::DirectProjection() : mDirectMatrix(Matrix44f::ident) { setDirty(); } -DirectProjection::DirectProjection(const Matrix44f* mtx, Graphics::DevicePosture posture) +DirectProjection::DirectProjection(const Matrix44f& mtx, Graphics::DevicePosture posture) { - setDirectProjectionMatrix(mtx, posture); + setProjectionMatrix(mtx, posture); +} + +static bool isXShifted(const Vector3f& near_corner, const Vector3f& far_corner) +{ + const f32 d = near_corner.x - far_corner.x; + return (d > 0.0f ? d : -d) > 0.0001f; } void DirectProjection::updateAttributesForDirectProjection() { - Matrix44f newMatrix; - newMatrix.setInverse(mDirectMatrix); + if (!mAttributesDirty) + { + return; + } + + Matrix44f inv; + inv.setInverse(mDirectMatrix); + + // Corners 0-3 are near plane quad, 4-7 are far-plane quad (Z sign indicates) + const Vector4f corners[8] = { + {-1, -1, -1, 1}, {-1, 1, -1, 1}, {1, 1, -1, 1}, {1, -1, -1, 1}, + {-1, -1, 1, 1}, {-1, 1, 1, 1}, {1, 1, 1, 1}, {1, -1, 1, 1}, + }; + + Vector3f cameraSpaceCorners[8]; + for (s32 i = 0; i < 8; ++i) + { + const Vector4f& c = corners[i]; + Vector3f p; + p.x = c.x * inv(0, 0) + c.y * inv(0, 1) + c.z * inv(0, 2) + c.w * inv(0, 3); + p.y = c.x * inv(1, 0) + c.y * inv(1, 1) + c.z * inv(1, 2) + c.w * inv(1, 3); + p.z = c.x * inv(2, 0) + c.y * inv(2, 1) + c.z * inv(2, 2) + c.w * inv(2, 3); + const f32 inv_w = + 1.0f / (c.x * inv(3, 0) + c.y * inv(3, 1) + c.z * inv(3, 2) + c.w * inv(3, 3)); + cameraSpaceCorners[i] = p * inv_w; + } + + mNear = -cameraSpaceCorners[0].z; + mFar = -cameraSpaceCorners[4].z; + f32 height = cameraSpaceCorners[1].y - cameraSpaceCorners[0].y; + mAspect = (cameraSpaceCorners[2].x - cameraSpaceCorners[0].x) / height; + mOffset.x = (cameraSpaceCorners[0].x + cameraSpaceCorners[2].x) * 0.5f / + (cameraSpaceCorners[2].x - cameraSpaceCorners[0].x); + mOffset.y = (cameraSpaceCorners[1].y + cameraSpaceCorners[0].y) * 0.5f / height; + + if (isXShifted(cameraSpaceCorners[0], cameraSpaceCorners[4]) || + isXShifted(cameraSpaceCorners[1], cameraSpaceCorners[5]) || + isXShifted(cameraSpaceCorners[2], cameraSpaceCorners[6]) || + isXShifted(cameraSpaceCorners[3], cameraSpaceCorners[7])) + { + mFovy = 2 * Mathf::atan2(height * 0.5f, mNear); + } + else + { + mFovy = 0.0f; + } + + mAttributesDirty = false; } void DirectProjection::doUpdateMatrix(Matrix44f* dst) const @@ -505,24 +580,62 @@ void DirectProjection::doUpdateMatrix(Matrix44f* dst) const *dst = mDirectMatrix; } -void DirectProjection::setDirectProjectionMatrix(const Matrix44f* mtx, - Graphics::DevicePosture posture) +void DirectProjection::setProjectionMatrix(const Matrix44f& mtx, Graphics::DevicePosture posture) { - mDirectMatrix = (*mtx); + mDirectMatrix = mtx; + + s32 negate_row = -1; + + switch (posture) + { + case Graphics::cDevicePosture_Same: + break; + case Graphics::cDevicePosture_RotateLeft: + negate_row = 1; + swapMatrixXY(&mDirectMatrix); + break; + case Graphics::cDevicePosture_RotateRight: + negate_row = 0; + swapMatrixXY(&mDirectMatrix); + break; + case Graphics::cDevicePosture_RotateHalfAround: + negateMatrixRow(&mDirectMatrix, 0); + negate_row = 1; + break; + case Graphics::cDevicePosture_FlipX: + negate_row = 0; + break; + case Graphics::cDevicePosture_FlipY: + negate_row = 1; + break; + default: + break; + } + + if (negate_row >= 0) + { + negateMatrixRow(&mDirectMatrix, negate_row); + } + + setDirty(); + mAttributesDirty = true; } void DirectProjection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const { Matrix44f inverseDirect; inverseDirect.setInverse(mDirectMatrix); - f32 scale = 1.0f / (inverseDirect(3, 3) + screen_pos.x * inverseDirect(3, 0) + - screen_pos.y * inverseDirect(3, 1) + screen_pos.z * inverseDirect(3, 2)); - dst->x = scale * (inverseDirect(0, 3) + screen_pos.x * inverseDirect(0, 0) + - screen_pos.y * inverseDirect(0, 1) + screen_pos.z * inverseDirect(0, 2)); - dst->y = scale * (inverseDirect(1, 3) + screen_pos.x * inverseDirect(1, 0) + - screen_pos.y * inverseDirect(1, 1) + screen_pos.z * inverseDirect(1, 2)); - dst->z = scale * (inverseDirect(2, 3) + screen_pos.x * inverseDirect(2, 0) + - screen_pos.y * inverseDirect(2, 1) + screen_pos.z * inverseDirect(2, 2)); + const f32 x = screen_pos.x; + const f32 y = screen_pos.y; + const f32 z = screen_pos.z; + f32 scale = 1.0f / (x * inverseDirect(3, 0) + y * inverseDirect(3, 1) + + z * inverseDirect(3, 2) + inverseDirect(3, 3)); + dst->x = scale * (x * inverseDirect(0, 0) + y * inverseDirect(0, 1) + z * inverseDirect(0, 2) + + inverseDirect(0, 3)); + dst->y = scale * (x * inverseDirect(1, 0) + y * inverseDirect(1, 1) + z * inverseDirect(1, 2) + + inverseDirect(1, 3)); + dst->z = scale * (x * inverseDirect(2, 0) + y * inverseDirect(2, 1) + z * inverseDirect(2, 2) + + inverseDirect(2, 3)); } } // namespace sead From 467ccf685c51e5fb7e33a596f08182fab551e348 Mon Sep 17 00:00:00 2001 From: Esras Date: Tue, 11 Aug 2026 15:13:09 -0600 Subject: [PATCH 09/22] Minor corrections based on earlier feedback on the PR. --- include/geom/seadLine.h | 10 ++++++++ include/gfx/seadViewport.h | 2 +- include/math/seadGeometry.h | 2 +- modules/src/gfx/seadCamera.cpp | 40 ++++++++++++++++-------------- modules/src/gfx/seadProjection.cpp | 11 ++++---- modules/src/gfx/seadViewport.cpp | 5 ++-- modules/src/math/seadGeometry.cpp | 6 ++--- 7 files changed, 45 insertions(+), 31 deletions(-) diff --git a/include/geom/seadLine.h b/include/geom/seadLine.h index abbc9f7f..9552c862 100644 --- a/include/geom/seadLine.h +++ b/include/geom/seadLine.h @@ -35,6 +35,16 @@ template class Ray { public: + Ray() = default; + Ray(const T& p, const T& d) : mP(p), mD(d) {} + + const T& getPos() const { return mP; } + void setPos(const T& p) { mP = p; } + + const T& getDir() const { return mD; } + void setDir(const T& d) { mD = d; } + +private: T mP; T mD; }; diff --git a/include/gfx/seadViewport.h b/include/gfx/seadViewport.h index 2347d14c..7cdf8235 100644 --- a/include/gfx/seadViewport.h +++ b/include/gfx/seadViewport.h @@ -15,7 +15,7 @@ class Viewport : public BoundBox2f SEAD_RTTI_BASE(Viewport) public: Viewport(); - Viewport(float left, float top, float right, float bottom); + Viewport(f32 left, f32 top, f32 size_x, f32 size_y); explicit Viewport(const BoundBox2f& parent); explicit Viewport(const LogicalFrameBuffer& buffer); virtual ~Viewport() = default; diff --git a/include/math/seadGeometry.h b/include/math/seadGeometry.h index 70dd43e8..aa28ebe9 100644 --- a/include/math/seadGeometry.h +++ b/include/math/seadGeometry.h @@ -7,7 +7,7 @@ namespace sead { namespace Geometry { -float calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, f32* closestRayPos); +f32 calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, f32* closestRayPos); // float calcSquaredDistancePointToLine(Vector2f* const, Line2f* const, float*); // float calcSquaredDistancePointToSegment(Vector3f* const, Segment3f* const, float*); // float calcSquaredDistancePointToSegment(); diff --git a/modules/src/gfx/seadCamera.cpp b/modules/src/gfx/seadCamera.cpp index 2888ce33..edb12736 100644 --- a/modules/src/gfx/seadCamera.cpp +++ b/modules/src/gfx/seadCamera.cpp @@ -24,21 +24,21 @@ void Camera::getWorldPosByMatrix(Vector3f* dst) const void Camera::getLookVectorByMatrix(Vector3f* dst) const { // Also known as the forward vector - auto vec = mMatrix.getRow(2); + const Vector4f vec = mMatrix.getRow(2); dst->set(vec.x, vec.y, vec.z); -}; +} void Camera::getRightVectorByMatrix(Vector3f* dst) const { - auto vec = mMatrix.getRow(0); + const Vector4f vec = mMatrix.getRow(0); dst->set(vec.x, vec.y, vec.z); } void Camera::getUpVectorByMatrix(Vector3f* dst) const { - auto vec = mMatrix.getRow(1); + const Vector4f vec = mMatrix.getRow(1); dst->set(vec.x, vec.y, vec.z); -}; +} void Camera::worldPosToCameraPosByMatrix(Vector3f* dst, const Vector3f& world_pos) const { @@ -61,25 +61,29 @@ void Camera::cameraPosToWorldPosByMatrix(Vector3f* dst, const Vector3f& camera_p void Camera::projectByMatrix(Vector2f* dst, const Vector3f& world_pos, const Projection& projection, const Viewport& viewport) const { - auto temp = mMatrix * world_pos; + Vector3f temp = mMatrix * world_pos; temp += mMatrix.getBase(3); projection.project(dst, temp, viewport); } void Camera::unprojectRayByMatrix(Ray* dst, const Vector3f& camera_pos) const { - dst->mD.x = mMatrix.getBase(0).dot(camera_pos); - dst->mD.y = mMatrix.getBase(1).dot(camera_pos); - dst->mD.z = mMatrix.getBase(2).dot(camera_pos); - dst->mD.normalize(); - - dst->mP.x = ((-mMatrix(0, 0) * mMatrix(0, 3)) - mMatrix(1, 0) * mMatrix(1, 3)) - - mMatrix(2, 0) * mMatrix(2, 3); - dst->mP.y = ((-mMatrix(0, 1) * mMatrix(0, 3)) - mMatrix(1, 1) * mMatrix(1, 3)) - - mMatrix(2, 1) * mMatrix(2, 3); - dst->mP.z = ((-mMatrix(0, 2) * mMatrix(0, 3)) - mMatrix(1, 2) * mMatrix(1, 3)) - - mMatrix(2, 2) * mMatrix(2, 3); - dst->mP *= -1.0f; + Vector3f dir; + dir.x = mMatrix.getBase(0).dot(camera_pos); + dir.y = mMatrix.getBase(1).dot(camera_pos); + dir.z = mMatrix.getBase(2).dot(camera_pos); + dir.normalize(); + dst->setDir(dir); + + Vector3f pos; + pos.x = ((-mMatrix(0, 0) * mMatrix(0, 3)) - mMatrix(1, 0) * mMatrix(1, 3)) - + mMatrix(2, 0) * mMatrix(2, 3); + pos.y = ((-mMatrix(0, 1) * mMatrix(0, 3)) - mMatrix(1, 1) * mMatrix(1, 3)) - + mMatrix(2, 1) * mMatrix(2, 3); + pos.z = ((-mMatrix(0, 2) * mMatrix(0, 3)) - mMatrix(1, 2) * mMatrix(1, 3)) - + mMatrix(2, 2) * mMatrix(2, 3); + pos *= -1.0f; + dst->setPos(pos); } LookAtCamera::~LookAtCamera() = default; diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 1afb2bc0..689bd41b 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -304,8 +304,8 @@ f32 OrthoProjection::getAspect() const void OrthoProjection::getOffset(Vector2f* offset) const { - offset->x = ((float)0.5 * (mLeft + mRight)) / (mRight - mLeft); - offset->y = ((float)0.5 * (mTop + mBottom)) / (mTop - mBottom); + offset->x = (0.5f * (mLeft + mRight)) / (mRight - mLeft); + offset->y = (0.5f * (mTop + mBottom)) / (mTop - mBottom); } void OrthoProjection::setNear(f32 near) @@ -351,7 +351,6 @@ void OrthoProjection::setTBLR(float top, float bottom, float left, float right) mLeft = left; mRight = right; setDirty(); - // this->projectionType = ProjectionType::cOrthoProjection; } void OrthoProjection::doUpdateMatrix(Matrix44f* dst) const @@ -500,11 +499,11 @@ f32 FrustumProjection::getAspect() const void FrustumProjection::getOffset(Vector2f* dst) const { - float denom = mRight - mLeft; - dst->x = (float)0.5 * (mRight + mLeft) / denom; + f32 denom = mRight - mLeft; + dst->x = 0.5f * (mRight + mLeft) / denom; denom = mTop - mBottom; - dst->y = (float)0.5 * (mTop + mBottom) / denom; + dst->y = 0.5f * (mTop + mBottom) / denom; } DirectProjection::DirectProjection() : mDirectMatrix(Matrix44f::ident) diff --git a/modules/src/gfx/seadViewport.cpp b/modules/src/gfx/seadViewport.cpp index 9de7d6e0..2ab221ee 100644 --- a/modules/src/gfx/seadViewport.cpp +++ b/modules/src/gfx/seadViewport.cpp @@ -13,10 +13,11 @@ Viewport::Viewport() setUndef(); } -Viewport::Viewport(f32 left, f32 top, f32 sizeX, f32 sizeY) - : BoundBox2f(left, top, left + sizeX, top + sizeY) +Viewport::Viewport(f32 left, f32 top, f32 size_x, f32 size_y) + : BoundBox2f(left, top, left + size_x, top + size_y) { } + Viewport::Viewport(const LogicalFrameBuffer& frame_buffer) { setByFrameBuffer(frame_buffer); diff --git a/modules/src/math/seadGeometry.cpp b/modules/src/math/seadGeometry.cpp index 2e427033..b49b2c2a 100644 --- a/modules/src/math/seadGeometry.cpp +++ b/modules/src/math/seadGeometry.cpp @@ -5,11 +5,11 @@ namespace sead // BUG: returns the distance from point to ray origin, ignoring its direction // (closestRayPos is fine) -float Geometry::calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, f32* closestRayPos) +f32 Geometry::calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, f32* closestRayPos) { - Vector2f diff = *point - ray->mP; + Vector2f diff = *point - ray->getPos(); - f32 numerator = diff.dot(ray->mD); + f32 numerator = diff.dot(ray->getDir()); f32 squaredLength = diff.squaredLength(); if (numerator < 0.0f) From 3950cb4b2906ee3b9962d1d10172b0e56013450c Mon Sep 17 00:00:00 2001 From: Esras Date: Tue, 11 Aug 2026 19:12:10 -0600 Subject: [PATCH 10/22] Move PerspectiveProjection::get* functions from the header to the cpp to avoid inlining. --- include/gfx/seadProjection.h | 8 ++++---- modules/src/gfx/seadProjection.cpp | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index 965acb0f..47b71fae 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -110,10 +110,10 @@ class PerspectiveProjection : public Projection void createDividedProjection(PerspectiveProjection* dst, s32 partno_x, s32 partno_y, s32 divnum_x, s32 divnum_y) const; - f32 getNear() const override { return mNear; } - f32 getFar() const override { return mFar; } - f32 getFovy() const override { return mAngle; } - f32 getAspect() const override { return mAspect; } + f32 getNear() const override; + f32 getFar() const override; + f32 getFovy() const override; + f32 getAspect() const override; void getOffset(Vector2f* offset) const override; f32 getTop() const; diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 689bd41b..8f6b04bb 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -188,6 +188,26 @@ void PerspectiveProjection::setFovy_(f32 fovy) setDirty(); } +f32 PerspectiveProjection::getNear() const +{ + return mNear; +} + +f32 PerspectiveProjection::getFar() const +{ + return mFar; +} + +f32 PerspectiveProjection::getFovy() const +{ + return mAngle; +} + +f32 PerspectiveProjection::getAspect() const +{ + return mAspect; +} + void PerspectiveProjection::getOffset(Vector2f* offset) const { offset->x = mOffset.x; From 9c7ec64356bb3f4ff4c83118c935d21ae73aafd9 Mon Sep 17 00:00:00 2001 From: Esras Date: Tue, 11 Aug 2026 19:42:51 -0600 Subject: [PATCH 11/22] Move more header functions into the CPP for Projection functions. Add the getOffsetX and getOffsetY functions for the FrustumProjection class. --- include/gfx/seadProjection.h | 22 ++++++----- modules/src/gfx/seadProjection.cpp | 60 ++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index 47b71fae..c8ba329c 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -170,9 +170,9 @@ class OrthoProjection : public Projection void createDividedProjection(OrthoProjection* dst, s32 partno_x, s32 partno_y, s32 divnum_x, s32 divnum_y) const; - f32 getNear() const override { return mNear; } - f32 getFar() const override { return mFar; } - f32 getFovy() const override { return 0; } + f32 getNear() const override; + f32 getFar() const override; + f32 getFovy() const override; f32 getTop() const { return mTop; } f32 getBottom() const { return mBottom; } f32 getLeft() const { return mLeft; } @@ -225,8 +225,8 @@ class FrustumProjection : public Projection void createDividedProjection(FrustumProjection* dst, s32 partno_x, s32 partno_y, s32 divnum_x, s32 divnum_y) const; - f32 getNear() const override { return mNear; } - f32 getFar() const override { return mFar; } + f32 getNear() const override; + f32 getFar() const override; f32 getTop() const { return mTop; } f32 getBottom() const { return mBottom; } f32 getLeft() const { return mLeft; } @@ -235,6 +235,8 @@ class FrustumProjection : public Projection f32 getFovy() const override; f32 getAspect() const override; void getOffset(Vector2f* dst) const override; + f32 getOffsetX() const; + f32 getOffsetY() const; void setFovyAspectOffset(f32 fovy, f32 aspect, const Vector2f& offset); @@ -262,12 +264,12 @@ class DirectProjection : public Projection void setProjectionMatrix(const Matrix44f& mtx, Graphics::DevicePosture posture); - f32 getNear() const override { return mNear; } - f32 getFar() const override { return mFar; } - f32 getFovy() const override { return mFovy; } + f32 getNear() const override; + f32 getFar() const override; + f32 getFovy() const override; - f32 getAspect() const override { return mAspect; } - void getOffset(Vector2f* offset) const override { *offset = mOffset; } + f32 getAspect() const override; + void getOffset(Vector2f* offset) const override; void doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const override; diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 8f6b04bb..68353cb6 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -317,6 +317,21 @@ OrthoProjection::OrthoProjection(f32 _near, f32 _far, const Viewport& vp) : mNea setDirty(); } +f32 OrthoProjection::getNear() const +{ + return mNear; +} + +f32 OrthoProjection::getFar() const +{ + return mFar; +} + +f32 OrthoProjection::getFovy() const +{ + return 0; +} + f32 OrthoProjection::getAspect() const { return (mRight - mLeft) / (mTop - mBottom); @@ -435,6 +450,16 @@ FrustumProjection::FrustumProjection(f32 _near, f32 _far, const BoundBox2f& box) { } +f32 FrustumProjection::getNear() const +{ + return mNear; +} + +f32 FrustumProjection::getFar() const +{ + return mFar; +} + void FrustumProjection::doUpdateMatrix(Matrix44f* dst) const { f32 inv_size = 1.0f / (mRight - mLeft); @@ -526,6 +551,16 @@ void FrustumProjection::getOffset(Vector2f* dst) const dst->y = 0.5f * (mTop + mBottom) / denom; } +f32 FrustumProjection::getOffsetX() const +{ + return 0.5f * (mLeft + mBottom) / (mLeft - mBottom); +} + +f32 FrustumProjection::getOffsetY() const +{ + return 0.5f * (mFar + mTop) / (mFar - mTop); +} + DirectProjection::DirectProjection() : mDirectMatrix(Matrix44f::ident) { setDirty(); @@ -640,6 +675,31 @@ void DirectProjection::setProjectionMatrix(const Matrix44f& mtx, Graphics::Devic mAttributesDirty = true; } +f32 DirectProjection::getNear() const +{ + return mNear; +} + +f32 DirectProjection::getFar() const +{ + return mFar; +} + +f32 DirectProjection::getFovy() const +{ + return mFovy; +} + +f32 DirectProjection::getAspect() const +{ + return mAspect; +} + +void DirectProjection::getOffset(Vector2f* offset) const +{ + *offset = mOffset; +} + void DirectProjection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const { Matrix44f inverseDirect; From f720a833d3ed048199b0f8ad16a87cab256add9c Mon Sep 17 00:00:00 2001 From: Esras Date: Tue, 11 Aug 2026 20:19:08 -0600 Subject: [PATCH 12/22] Update the getOffsetX and getOffsetY functions according to the SMO decomp. --- modules/src/gfx/seadProjection.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 68353cb6..102c8d47 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -553,12 +553,16 @@ void FrustumProjection::getOffset(Vector2f* dst) const f32 FrustumProjection::getOffsetX() const { - return 0.5f * (mLeft + mBottom) / (mLeft - mBottom); + f32 den = mRight - mLeft; + f32 num = mRight + mLeft; + return 0.5f * num / den; } f32 FrustumProjection::getOffsetY() const { - return 0.5f * (mFar + mTop) / (mFar - mTop); + f32 den = mTop - mBottom; + f32 num = mTop + mBottom; + return 0.5f * num / den; } DirectProjection::DirectProjection() : mDirectMatrix(Matrix44f::ident) From d00a838d39749102a6ef3612012d6a6ff40b82f2 Mon Sep 17 00:00:00 2001 From: Esras Date: Wed, 12 Aug 2026 09:15:01 -0600 Subject: [PATCH 13/22] Match the remaining camera functions, at least as they show up in BotW from 0xb1b9f0 to 0xb1c680 --- include/gfx/seadCamera.h | 4 +- modules/src/gfx/seadCamera.cpp | 121 ++++++++++++++++++++++++++------- 2 files changed, 98 insertions(+), 27 deletions(-) diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index 4c89cbd6..60c6b55f 100644 --- a/include/gfx/seadCamera.h +++ b/include/gfx/seadCamera.h @@ -16,7 +16,7 @@ class Camera SEAD_RTTI_BASE(Camera) public: - Camera(); + Camera() = default; virtual ~Camera(); virtual void doUpdateMatrix(Matrix34f* dst) const = 0; @@ -65,7 +65,7 @@ class LookAtCamera : public Camera void addAt(const Vector3f& at) { mAt += at; } private: - Vector3f mPos = {0.0f, 0.0f, 10.0f}; + Vector3f mPos = {0.0f, 0.0f, 1.0f}; Vector3f mAt = {0.0f, 0.0f, 0.0f}; Vector3f mUp = {0.0f, 1.0f, 0.0f}; }; diff --git a/modules/src/gfx/seadCamera.cpp b/modules/src/gfx/seadCamera.cpp index edb12736..e643d544 100644 --- a/modules/src/gfx/seadCamera.cpp +++ b/modules/src/gfx/seadCamera.cpp @@ -6,7 +6,6 @@ namespace sead { -Camera::Camera() = default; Camera::~Camera() = default; @@ -47,43 +46,56 @@ void Camera::worldPosToCameraPosByMatrix(Vector3f* dst, const Vector3f& world_po void Camera::cameraPosToWorldPosByMatrix(Vector3f* dst, const Vector3f& camera_pos) const { - dst->x = mMatrix(0, 0) * camera_pos.x + mMatrix(1, 0) * camera_pos.y + - ((-(mMatrix(0, 3) * mMatrix(0, 0)) - mMatrix(1, 3) * mMatrix(1, 1)) - - mMatrix(2, 3) * mMatrix(2, 0)); - dst->y = mMatrix(0, 1) * camera_pos.x + mMatrix(1, 1) * camera_pos.y + - ((-(mMatrix(0, 3) * mMatrix(0, 1)) - mMatrix(1, 3) * mMatrix(1, 2)) - - mMatrix(2, 3) * mMatrix(2, 1)); - dst->z = mMatrix(0, 2) * camera_pos.x + mMatrix(1, 2) * camera_pos.y + - ((-(mMatrix(0, 3) * mMatrix(0, 2)) - mMatrix(1, 3) * mMatrix(1, 3)) - - mMatrix(2, 3) * mMatrix(2, 2)); + Vector3f up; + Vector3f right; + Vector3f look; + + getUpVectorByMatrix(&up); + getRightVectorByMatrix(&right); + getLookVectorByMatrix(&look); + + up = up * camera_pos.y; + look = look * camera_pos.z; + right = right * camera_pos.x; + + Vector3f pos; + getWorldPosByMatrix(&pos); + pos = pos + up + look; + + dst->setAdd(pos, right); } void Camera::projectByMatrix(Vector2f* dst, const Vector3f& world_pos, const Projection& projection, const Viewport& viewport) const { - Vector3f temp = mMatrix * world_pos; - temp += mMatrix.getBase(3); - projection.project(dst, temp, viewport); + Vector3f camera_pos; + worldPosToCameraPosByMatrix(&camera_pos, world_pos); + projection.project(dst, camera_pos, viewport); } void Camera::unprojectRayByMatrix(Ray* dst, const Vector3f& camera_pos) const { + Vector3f up; + Vector3f right; + Vector3f look; + + getUpVectorByMatrix(&up); + getRightVectorByMatrix(&right); + getLookVectorByMatrix(&look); + + up = up * camera_pos.y; + look = look * camera_pos.z; + right = right * camera_pos.x; + Vector3f dir; - dir.x = mMatrix.getBase(0).dot(camera_pos); - dir.y = mMatrix.getBase(1).dot(camera_pos); - dir.z = mMatrix.getBase(2).dot(camera_pos); + dir.setAdd(up, look); + dir = dir + right; dir.normalize(); - dst->setDir(dir); Vector3f pos; - pos.x = ((-mMatrix(0, 0) * mMatrix(0, 3)) - mMatrix(1, 0) * mMatrix(1, 3)) - - mMatrix(2, 0) * mMatrix(2, 3); - pos.y = ((-mMatrix(0, 1) * mMatrix(0, 3)) - mMatrix(1, 1) * mMatrix(1, 3)) - - mMatrix(2, 1) * mMatrix(2, 3); - pos.z = ((-mMatrix(0, 2) * mMatrix(0, 3)) - mMatrix(1, 2) * mMatrix(1, 3)) - - mMatrix(2, 2) * mMatrix(2, 3); - pos *= -1.0f; + getWorldPosByMatrix(&pos); dst->setPos(pos); + dst->setDir(dir); } LookAtCamera::~LookAtCamera() = default; @@ -95,12 +107,71 @@ LookAtCamera::LookAtCamera(const Vector3f& pos, const Vector3f& at, const Vector mUp.normalize(); } -void LookAtCamera::doUpdateMatrix(Matrix34f* dst) const {} +void LookAtCamera::doUpdateMatrix(Matrix34f* dst) const +{ + if (mPos == mAt) + return; + + Vector3f dir = mPos; + dir -= mAt; + dir.normalize(); + + Vector3f right; + right.setCross(mUp, dir); + right.normalize(); + + Vector3f up; + up.setCross(dir, right); + + f32 x = -right.dot(mPos); + f32 y = -up.dot(mPos); + f32 z = -dir.dot(mPos); + + (*dst)(0, 0) = right.x; + (*dst)(0, 1) = right.y; + (*dst)(0, 2) = right.z; + (*dst)(0, 3) = x; + + (*dst)(1, 0) = up.x; + (*dst)(1, 1) = up.y; + (*dst)(1, 2) = up.z; + (*dst)(1, 3) = y; + + (*dst)(2, 0) = dir.x; + (*dst)(2, 1) = dir.y; + (*dst)(2, 2) = dir.z; + (*dst)(2, 3) = z; +} DirectCamera::~DirectCamera() = default; +void DirectCamera::doUpdateMatrix(Matrix34f* dst) const +{ + *dst = mDirectMatrix; +} + OrthoCamera::OrthoCamera() = default; +OrthoCamera::OrthoCamera(const OrthoProjection& projection) + : LookAtCamera({0.5f * (projection.getLeft() + projection.getRight()), + 0.5f * (projection.getTop() + projection.getBottom()), + projection.getNear()}, + {0.5f * (projection.getLeft() + projection.getRight()), + 0.5f * (projection.getTop() + projection.getBottom()), + projection.getNear() - 1.0f}, + {0.0f, 1.0f, 0.0f}) +{ +} + OrthoCamera::~OrthoCamera() = default; +void OrthoCamera::setByOrthoProjection(const OrthoProjection& projection) +{ + setPos({0.5f * (projection.getLeft() + projection.getRight()), + 0.5f * (projection.getTop() + projection.getBottom()), projection.getNear()}); + setAt({0.5f * (projection.getLeft() + projection.getRight()), + 0.5f * (projection.getTop() + projection.getBottom()), projection.getNear() - 1.0f}); + setUp({0.0f, 1.0f, 0.0f}); +} + } // namespace sead From 594dbbd1aafba4c567f31894a01836feee06c90b Mon Sep 17 00:00:00 2001 From: Esras Date: Wed, 12 Aug 2026 10:46:25 -0600 Subject: [PATCH 14/22] Rename the mDepthBound -> mDepthRange, based on the nvn commands being called. Update the apply functions in the CPP to match all of the Viewport functions in BotW. --- include/gfx/seadViewport.h | 2 +- modules/src/gfx/seadViewport.cpp | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/include/gfx/seadViewport.h b/include/gfx/seadViewport.h index 7cdf8235..55f69f93 100644 --- a/include/gfx/seadViewport.h +++ b/include/gfx/seadViewport.h @@ -38,7 +38,7 @@ class Viewport : public BoundBox2f private: Graphics::DevicePosture mDevicePosture = Graphics::getDefaultDevicePosture(); - Vector2f mDepthBounds = Vector2f(0.0f, 1.0f); + Vector2f mDepthRange = Vector2f(0.0f, 1.0f); }; #ifdef cafe static_assert(sizeof(Viewport) == 0x18, "sead::Viewport size mismatch"); diff --git a/modules/src/gfx/seadViewport.cpp b/modules/src/gfx/seadViewport.cpp index 2ab221ee..61592637 100644 --- a/modules/src/gfx/seadViewport.cpp +++ b/modules/src/gfx/seadViewport.cpp @@ -4,6 +4,8 @@ #include #include "math/seadBoundBox.h" #include "nn/gfx/gfx_StateInfo.h" +#include "nvn/nvn.h" +#include "nvn/nvn_FuncPtrInline.h" namespace sead { @@ -131,11 +133,12 @@ void Viewport::apply(DrawContext* context, const LogicalFrameBuffer& buffer) con real_pos.y = (buffer.getPhysicalArea().getSizeY() - real_size.y) - real_pos.y; - sead::Graphics::instance()->setViewportRealPosition(real_pos.x, real_pos.y, real_size.x, - real_size.y); - sead::Graphics::instance()->setScissorRealPosition(real_pos.x, real_pos.y, real_size.x, - real_size.y); - context->getCommandBuffer()->SetDepthBounds(mDepthBounds.x, mDepthBounds.y); + NVNcommandBuffer* cb = context->getCommandBuffer()->ToData()->pNvnCommandBuffer; + nvnCommandBufferSetScissor(cb, s32(real_pos.x), s32(real_pos.y), u32(real_size.x), + u32(real_size.y)); + nvnCommandBufferSetViewport(cb, s32(real_pos.x), s32(real_pos.y), u32(real_size.x), + u32(real_size.y)); + nvnCommandBufferSetDepthRange(cb, mDepthRange.x, mDepthRange.y); } void Viewport::applyViewport(DrawContext* context, const LogicalFrameBuffer& buffer) const @@ -150,10 +153,11 @@ void Viewport::applyViewport(DrawContext* context, const LogicalFrameBuffer& buf buffer.getPhysicalArea().isInside(real_pos + real_size)); real_pos.y = (buffer.getPhysicalArea().getSizeY() - real_size.y) - real_pos.y; - // real_pos.x = (buffer.getPhysicalArea().getSizeX() - real_size.x) - real_pos.x; - sead::Graphics::instance()->setViewportRealPosition(real_pos.x, real_pos.y, real_size.x, - real_size.y); + NVNcommandBuffer* cb = context->getCommandBuffer()->ToData()->pNvnCommandBuffer; + nvnCommandBufferSetViewport(cb, s32(real_pos.x), s32(real_pos.y), u32(real_size.x), + u32(real_size.y)); + nvnCommandBufferSetDepthRange(cb, mDepthRange.x, mDepthRange.y); } void Viewport::applyScissor(DrawContext* context, const LogicalFrameBuffer& buffer) const @@ -169,8 +173,9 @@ void Viewport::applyScissor(DrawContext* context, const LogicalFrameBuffer& buff real_pos.y = (buffer.getPhysicalArea().getSizeY() - real_size.y) - real_pos.y; - sead::Graphics::instance()->setScissorRealPosition(real_pos.x, real_pos.y, real_size.x, - real_size.y); + NVNcommandBuffer* cb = context->getCommandBuffer()->ToData()->pNvnCommandBuffer; + nvnCommandBufferSetScissor(cb, s32(real_pos.x), s32(real_pos.y), u32(real_size.x), + u32(real_size.y)); } void Viewport::project(Vector2f* aVec, const Vector3f& bVec) const From 0f1c9a65a98dcc36e98554bedfcc4f1ef99b4480 Mon Sep 17 00:00:00 2001 From: Esras Date: Wed, 12 Aug 2026 11:25:56 -0600 Subject: [PATCH 15/22] Add a guard for the mDepthRange on the Viewport function so that it will match on SMO and others, leave comments indicating unknown status on some of the other branches. Additionally, remove the RTTI functions on the Viewport class, since they don't exist anywhere. Also revert a change to the initial mPos on the LookAtCamera, the change was leftover from a constructor match exercise. --- include/gfx/seadCamera.h | 2 +- include/gfx/seadViewport.h | 3 ++- include/seadVersion.h | 6 ++++++ modules/src/gfx/seadViewport.cpp | 4 ++++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index 60c6b55f..a039d159 100644 --- a/include/gfx/seadCamera.h +++ b/include/gfx/seadCamera.h @@ -65,7 +65,7 @@ class LookAtCamera : public Camera void addAt(const Vector3f& at) { mAt += at; } private: - Vector3f mPos = {0.0f, 0.0f, 1.0f}; + Vector3f mPos = {0.0f, 0.0f, 10.0f}; Vector3f mAt = {0.0f, 0.0f, 0.0f}; Vector3f mUp = {0.0f, 1.0f, 0.0f}; }; diff --git a/include/gfx/seadViewport.h b/include/gfx/seadViewport.h index 55f69f93..5a4de890 100644 --- a/include/gfx/seadViewport.h +++ b/include/gfx/seadViewport.h @@ -12,7 +12,6 @@ class Projection; class Viewport : public BoundBox2f { - SEAD_RTTI_BASE(Viewport) public: Viewport(); Viewport(f32 left, f32 top, f32 size_x, f32 size_y); @@ -38,7 +37,9 @@ class Viewport : public BoundBox2f private: Graphics::DevicePosture mDevicePosture = Graphics::getDefaultDevicePosture(); +#if SEAD_VIEWPORT_DEPTH_RANGE Vector2f mDepthRange = Vector2f(0.0f, 1.0f); +#endif }; #ifdef cafe static_assert(sizeof(Viewport) == 0x18, "sead::Viewport size mismatch"); diff --git a/include/seadVersion.h b/include/seadVersion.h index e485907c..a32261e6 100644 --- a/include/seadVersion.h +++ b/include/seadVersion.h @@ -46,6 +46,8 @@ /// Fixes two bugs on FindContainHeapCache (incomplete locks and 64-bit pointers) /// SEAD_THREAD_SETAFFINITY_RELOAD: /// Store new affinity into member, then reload instead of reusing parameter +/// SEAD_VIEWPORT_DEPTH_RANGE: +/// Adds mDepthRange to Viewport, and a SetDepthRange call to apply and applyViewport #if SEAD_VERSION == SEAD_VERSION_BOTW #define SEAD_SAFESTRING_NONVIRTUAL 0 @@ -64,6 +66,7 @@ #define SEAD_HOSTIO_NONVIRTUAL 0 #define SEAD_FINDCONTAINHEAPCACHE_FIXED 0 #define SEAD_THREAD_SETAFFINITY_RELOAD 1 +#define SEAD_VIEWPORT_DEPTH_RANGE 1 #elif SEAD_VERSION == SEAD_VERSION_SMO #define SEAD_SAFESTRING_NONVIRTUAL 0 #define SEAD_RESOURCEMGR_TRYCREATE_NO_FACTORY_NAME 0 @@ -81,6 +84,7 @@ #define SEAD_HOSTIO_NONVIRTUAL 0 #define SEAD_FINDCONTAINHEAPCACHE_FIXED 0 #define SEAD_THREAD_SETAFFINITY_RELOAD 1 +#define SEAD_VIEWPORT_DEPTH_RANGE 0 #elif SEAD_VERSION == SEAD_VERSION_SPL3 or SEAD_VERSION == SEAD_VERSION_TOTK or \ SEAD_VERSION == SEAD_VERSION_SMBW #define SEAD_SAFESTRING_NONVIRTUAL 1 @@ -99,6 +103,7 @@ #define SEAD_HOSTIO_NONVIRTUAL 0 #define SEAD_FINDCONTAINHEAPCACHE_FIXED 0 #define SEAD_THREAD_SETAFFINITY_RELOAD 1 +#define SEAD_VIEWPORT_DEPTH_RANGE 0 // TODO: figure this out #elif SEAD_VERSION == SEAD_VERSION_SMM2 #define SEAD_SAFESTRING_NONVIRTUAL 0 // TODO: figure this out #define SEAD_RESOURCEMGR_TRYCREATE_NO_FACTORY_NAME 0 // TODO: figure this out @@ -116,6 +121,7 @@ #define SEAD_HOSTIO_NONVIRTUAL 1 #define SEAD_FINDCONTAINHEAPCACHE_FIXED 1 #define SEAD_THREAD_SETAFFINITY_RELOAD 0 +#define SEAD_VIEWPORT_DEPTH_RANGE 0 // TODO: figure this out #endif /// feature-specific macros diff --git a/modules/src/gfx/seadViewport.cpp b/modules/src/gfx/seadViewport.cpp index 61592637..fd16d4b2 100644 --- a/modules/src/gfx/seadViewport.cpp +++ b/modules/src/gfx/seadViewport.cpp @@ -138,7 +138,9 @@ void Viewport::apply(DrawContext* context, const LogicalFrameBuffer& buffer) con u32(real_size.y)); nvnCommandBufferSetViewport(cb, s32(real_pos.x), s32(real_pos.y), u32(real_size.x), u32(real_size.y)); +#if SEAD_VIEWPORT_DEPTH_RANGE nvnCommandBufferSetDepthRange(cb, mDepthRange.x, mDepthRange.y); +#endif } void Viewport::applyViewport(DrawContext* context, const LogicalFrameBuffer& buffer) const @@ -157,7 +159,9 @@ void Viewport::applyViewport(DrawContext* context, const LogicalFrameBuffer& buf NVNcommandBuffer* cb = context->getCommandBuffer()->ToData()->pNvnCommandBuffer; nvnCommandBufferSetViewport(cb, s32(real_pos.x), s32(real_pos.y), u32(real_size.x), u32(real_size.y)); +#if SEAD_VIEWPORT_DEPTH_RANGE nvnCommandBufferSetDepthRange(cb, mDepthRange.x, mDepthRange.y); +#endif } void Viewport::applyScissor(DrawContext* context, const LogicalFrameBuffer& buffer) const From 8c1a68ca6eb4846b08c8554d1d9583c29181a78c Mon Sep 17 00:00:00 2001 From: Esras Date: Wed, 12 Aug 2026 12:12:51 -0600 Subject: [PATCH 16/22] Remove the base Projection::doScreenPos... function - it's supposed to be overridden and its existence here is an artifact. Change the mPos vector back to 1.0f - all of the constructors seem to use it like that and the 10.0f override seems to be coming from other game functions' ctors. Move the PerspectiveProjection dtor to be defined in the CPP - this may be wrong, based on what pointer nonsense is going on. --- include/gfx/seadCamera.h | 2 +- include/gfx/seadProjection.h | 2 +- modules/src/gfx/seadProjection.cpp | 11 ++--------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index a039d159..60c6b55f 100644 --- a/include/gfx/seadCamera.h +++ b/include/gfx/seadCamera.h @@ -65,7 +65,7 @@ class LookAtCamera : public Camera void addAt(const Vector3f& at) { mAt += at; } private: - Vector3f mPos = {0.0f, 0.0f, 10.0f}; + Vector3f mPos = {0.0f, 0.0f, 1.0f}; Vector3f mAt = {0.0f, 0.0f, 0.0f}; Vector3f mUp = {0.0f, 1.0f, 0.0f}; }; diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index c8ba329c..f99f5c1f 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -79,7 +79,7 @@ class PerspectiveProjection : public Projection public: PerspectiveProjection(); PerspectiveProjection(f32 near, f32 far, f32 fovy_rad, f32 aspect); - ~PerspectiveProjection() override = default; + ~PerspectiveProjection() override; void set(f32 _near, f32 _far, f32 fovy_rad, f32 aspect); diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 102c8d47..7f32e9bb 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -87,15 +87,6 @@ void Projection::unprojectRay(Ray* dst, const Vector3f& screen_pos, camera.unprojectRayByMatrix(dst, camera_pos); } -void Projection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const -{ - updateMatrixImpl_(); - f32 scale = 1.0f / (mMatrix(3, 3) + screen_pos.x * mMatrix(3, 0) + - screen_pos.y * mMatrix(3, 1) + screen_pos.z * mMatrix(3, 2)); - *dst = static_cast(mMatrix) * screen_pos; - *dst *= scale; -} - static void swapMatrixXY(Matrix44f* mtx) { Vector4f x = mtx->getRow(0); @@ -168,6 +159,8 @@ PerspectiveProjection::PerspectiveProjection(f32 near, f32 far, f32 fovy_rad, f3 setFovy_(fovy_rad); } +PerspectiveProjection::~PerspectiveProjection() = default; + void PerspectiveProjection::set(f32 _near, f32 _far, f32 fovy_rad, f32 aspect) { setNear(_near); From ba7cf0431c3e6d3a008ca078952d593c83946224 Mon Sep 17 00:00:00 2001 From: Esras Date: Wed, 12 Aug 2026 12:15:08 -0600 Subject: [PATCH 17/22] Move functions out of the CPP and into the header - they're all inlined. --- include/gfx/seadProjection.h | 72 +++++++++++++++++++++++++----- modules/src/gfx/seadProjection.cpp | 72 ------------------------------ 2 files changed, 60 insertions(+), 84 deletions(-) diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index f99f5c1f..534b2651 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -157,12 +157,36 @@ class OrthoProjection : public Projection OrthoProjection(f32 _near, f32 _far, const Viewport& vp); ~OrthoProjection() override = default; - void setNear(f32 near); - void setFar(f32 far); - void setTop(f32 top); - void setBottom(f32 bottom); - void setLeft(f32 left); - void setRight(f32 right); + void setNear(f32 near) + { + mNear = near; + setDirty(); + } + void setFar(f32 far) + { + mFar = far; + setDirty(); + } + void setTop(f32 top) + { + mTop = top; + setDirty(); + } + void setBottom(f32 bottom) + { + mBottom = bottom; + setDirty(); + } + void setLeft(f32 left) + { + mLeft = left; + setDirty(); + } + void setRight(f32 right) + { + mRight = right; + setDirty(); + } void setTBLR(f32 top, f32 bottom, f32 left, f32 right); void setByViewport(const Viewport& vp); void setBoundBox(const BoundBox2f& box); @@ -211,12 +235,36 @@ class FrustumProjection : public Projection void doUpdateMatrix(Matrix44f* dst) const override; void doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& screen_pos) const override; - void setNear(f32 near); - void setFar(f32 far); - void setTop(f32 top); - void setBottom(f32 bottom); - void setLeft(f32 left); - void setRight(f32 right); + void setNear(f32 near) + { + mNear = near; + setDirty(); + } + void setFar(f32 far) + { + mFar = far; + setDirty(); + } + void setTop(f32 top) + { + mTop = top; + setDirty(); + } + void setBottom(f32 bottom) + { + mBottom = bottom; + setDirty(); + } + void setLeft(f32 left) + { + mLeft = left; + setDirty(); + } + void setRight(f32 right) + { + mRight = right; + setDirty(); + } void setTBLR(f32 top, f32 bottom, f32 left, f32 right); diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 7f32e9bb..a1e61187 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -336,42 +336,6 @@ void OrthoProjection::getOffset(Vector2f* offset) const offset->y = (0.5f * (mTop + mBottom)) / (mTop - mBottom); } -void OrthoProjection::setNear(f32 near) -{ - mNear = near; - setDirty(); -} - -void OrthoProjection::setFar(f32 far) -{ - mFar = far; - setDirty(); -} - -void OrthoProjection::setTop(f32 top) -{ - mTop = top; - setDirty(); -} - -void OrthoProjection::setBottom(f32 bottom) -{ - mBottom = bottom; - setDirty(); -} - -void OrthoProjection::setLeft(f32 left) -{ - mLeft = left; - setDirty(); -} - -void OrthoProjection::setRight(f32 right) -{ - mRight = right; - setDirty(); -} - void OrthoProjection::setTBLR(float top, float bottom, float left, float right) { mTop = top; @@ -489,42 +453,6 @@ void FrustumProjection::doScreenPosToCameraPosTo(Vector3f* dst, const Vector3f& dst->y = (mTop - mBottom) * screen_pos.y * 0.5f + (mTop + mBottom) * 0.5f; } -void FrustumProjection::setNear(f32 near) -{ - mNear = near; - setDirty(); -} - -void FrustumProjection::setFar(f32 far) -{ - mFar = far; - setDirty(); -} - -void FrustumProjection::setTop(f32 top) -{ - mTop = top; - setDirty(); -} - -void FrustumProjection::setBottom(f32 bottom) -{ - mBottom = bottom; - setDirty(); -} - -void FrustumProjection::setLeft(f32 left) -{ - mLeft = left; - setDirty(); -} - -void FrustumProjection::setRight(f32 right) -{ - mRight = right; - setDirty(); -} - f32 FrustumProjection::getFovy() const { return 2 * Mathf::atan2(0.5f * (mTop - mBottom), getNear()); From 63d9f32a24073d8d67e2096646d7e1a20f504eb2 Mon Sep 17 00:00:00 2001 From: Esras Date: Wed, 12 Aug 2026 14:23:14 -0600 Subject: [PATCH 18/22] Remove the normalizeUp function in favor of folding its usage directly into setUp. This will break the SMO build. --- include/gfx/seadCamera.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index 60c6b55f..05a4272a 100644 --- a/include/gfx/seadCamera.h +++ b/include/gfx/seadCamera.h @@ -58,9 +58,12 @@ class LookAtCamera : public Camera void setPos(const Vector3f& pos) { mPos = pos; } void setAt(const Vector3f& at) { mAt = at; } - void setUp(const Vector3f& up) { mUp = up; } + void setUp(const Vector3f& up) + { + mUp = up; + mUp.normalize(); + } - void normalizeUp() { mUp.normalize(); } void addPos(const Vector3f& pos) { mPos += pos; } void addAt(const Vector3f& at) { mAt += at; } From 8d1bc9e417bfaca3a8b1c0b0f0574ecf3f91555a Mon Sep 17 00:00:00 2001 From: Esras Date: Fri, 14 Aug 2026 08:29:36 -0600 Subject: [PATCH 19/22] Remove unused GraphicsContext port and dead FrustumProjection(BoundBox2f) constructor. GraphicsContext was ported from aboood's WiiU branch but nothing in my code calls it. Its existence is causing the BotW and SMO builds to fail their CI checks. Finally, the FrustumProjection constructor that takes the BoundBox2f doesn't seem to appear in BotW or SMO. --- CMakeLists.txt | 2 - include/gfx/seadGraphicsContext.h | 272 ------------------------ include/gfx/seadProjection.h | 1 - modules/src/gfx/seadGraphicsContext.cpp | 193 ----------------- modules/src/gfx/seadProjection.cpp | 5 - 5 files changed, 473 deletions(-) delete mode 100644 include/gfx/seadGraphicsContext.h delete mode 100644 modules/src/gfx/seadGraphicsContext.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f4ef6b99..66ec67ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,6 @@ add_library(sead OBJECT include/gfx/seadDrawLockContext.h include/gfx/seadFrameBuffer.h include/gfx/seadGraphics.h - include/gfx/seadGraphicsContext.h include/gfx/seadViewport.h include/gfx/seadPrimitiveRenderer.h include/gfx/seadPrimitiveRendererUtil.h @@ -116,7 +115,6 @@ add_library(sead OBJECT modules/src/gfx/seadDrawLockContext.cpp modules/src/gfx/seadFrameBuffer.cpp modules/src/gfx/seadGraphics.cpp - modules/src/gfx/seadGraphicsContext.cpp modules/src/gfx/seadViewport.cpp # modules/src/gfx/seadPrimitiveRenderer.cpp # modules/src/gfx/seadPrimitiveRendererUtil.cpp diff --git a/include/gfx/seadGraphicsContext.h b/include/gfx/seadGraphicsContext.h deleted file mode 100644 index 705674a1..00000000 --- a/include/gfx/seadGraphicsContext.h +++ /dev/null @@ -1,272 +0,0 @@ -#pragma once - -#include -#include - -namespace sead -{ - -class GraphicsContext -{ -public: - GraphicsContext(); - virtual ~GraphicsContext() {} - - void apply() const; - void applyAlphaTest() const; - void applyDepthAndStencilTest() const; - void applyColorMask() const; - void applyBlendAndFastZ() const; - void applyBlendConstantColor() const; - void applyCullingAndPolygonModeAndPolygonOffset() const; - - void setDepthEnable(bool test_enable, bool write_enable) - { - setDepthTestEnable(test_enable); - setDepthWriteEnable(write_enable); - } - - void setDepthTestEnable(bool test_enable) { mDepthTestEnable = test_enable; } - - void setDepthWriteEnable(bool write_enable) { mDepthWriteEnable = write_enable; } - - void setDepthFunc(Graphics::DepthFunc func) { mDepthFunc = func; } - - void setCullingMode(Graphics::CullingMode mode) { mCullingMode = mode; } - - void setBlendEnable(bool blend) { mBlendEnable = blend; } - - void setBlendFactor(Graphics::BlendFactor src_factor, Graphics::BlendFactor dst_factor) - { - setBlendFactorSrc(src_factor); - setBlendFactorDst(dst_factor); - } - - void setBlendFactorSeparate(Graphics::BlendFactor src_factor_rgb, - Graphics::BlendFactor dst_factor_rgb, - Graphics::BlendFactor src_factor_a, - Graphics::BlendFactor dst_factor_a) - { - setBlendFactorSrcRGB(src_factor_rgb); - setBlendFactorDstRGB(dst_factor_rgb); - setBlendFactorSrcAlpha(src_factor_a); - setBlendFactorDstAlpha(dst_factor_a); - } - - void setBlendFactorSrc(Graphics::BlendFactor factor) - { - setBlendFactorSrcRGB(factor); - setBlendFactorSrcAlpha(factor); - } - - void setBlendFactorDst(Graphics::BlendFactor factor) - { - setBlendFactorDstRGB(factor); - setBlendFactorDstAlpha(factor); - } - - void setBlendFactorSrcRGB(Graphics::BlendFactor factor) { mBlendFactorSrcRGB = factor; } - - void setBlendFactorSrcAlpha(Graphics::BlendFactor factor) { mBlendFactorSrcA = factor; } - - void setBlendFactorDstRGB(Graphics::BlendFactor factor) { mBlendFactorDstRGB = factor; } - - void setBlendFactorDstAlpha(Graphics::BlendFactor factor) { mBlendFactorDstA = factor; } - - void setBlendEquation(Graphics::BlendEquation equation) - { - setBlendEquationRGB(equation); - setBlendEquationAlpha(equation); - } - - void setBlendEquationSeparate(Graphics::BlendEquation equation_rgb, - Graphics::BlendEquation equation_a) - { - setBlendEquationRGB(equation_rgb); - setBlendEquationAlpha(equation_a); - } - - void setBlendEquationRGB(Graphics::BlendEquation equation) { mBlendEquationRGB = equation; } - - void setBlendEquationAlpha(Graphics::BlendEquation equation) { mBlendEquationA = equation; } - - void setBlendConstantColor(const Color4f& color) { mBlendConstantColor = color; } - - void setAlphaTestEnable(bool enable) { mAlphaTestEnable = enable; } - - void setAlphaTestFunc(Graphics::AlphaFunc func, f32 ref) - { - mAlphaTestFunc = func; - mAlphaTestRef = ref; - } - - void setColorMask(bool r, bool g, bool b, bool a) - { - mColorMaskR = r; - mColorMaskG = g; - mColorMaskB = b; - mColorMaskA = a; - } - - void setStencilTestEnable(bool enable) { mStencilTestEnable = enable; } - - void setStencilTestFunc(Graphics::StencilFunc func, s32 ref, u32 mask) - { - mStencilTestFunc = func; - mStencilTestRef = ref; - mStencilTestMask = mask; - } - - void setStencilTestOp(Graphics::StencilOp fail, Graphics::StencilOp zfail, - Graphics::StencilOp zpass) - { - mStencilOpFail = fail; - mStencilOpZFail = zfail; - mStencilOpZPass = zpass; - } - - void setPolygonMode(Graphics::PolygonMode front, Graphics::PolygonMode back) - { -#ifdef cafe - mPolygonModeFront = front; - mPolygonModeBack = back; -#endif // cafe - } - - void setPolygonOffsetEnable(bool fill_front_enable, bool fill_back_enable, - bool point_line_enable) - { -#ifdef cafe - mPolygonOffsetFrontEnable = fill_front_enable; - mPolygonOffsetBackEnable = fill_back_enable; - mPolygonOffsetPointLineEnable = point_line_enable; -#endif // cafe - } - - bool getDepthTestEnable() const { return mDepthTestEnable; } - - bool getDepthWriteEnable() const { return mDepthWriteEnable; } - - Graphics::DepthFunc getDepthFunc() const { return mDepthFunc; } - - Graphics::CullingMode getCullingMode() const { return mCullingMode; } - - bool getBlendEnable() const { return mBlendEnable; } - - Graphics::BlendFactor getBlendFactorSrcRGB() const { return mBlendFactorSrcRGB; } - - Graphics::BlendFactor getBlendFactorSrcAlpha() const { return mBlendFactorSrcA; } - - Graphics::BlendFactor getBlendFactorDstRGB() const { return mBlendFactorDstRGB; } - - Graphics::BlendFactor getBlendFactorDstAlpha() const { return mBlendFactorDstA; } - - Graphics::BlendEquation getBlendEquationRGB() const { return mBlendEquationRGB; } - - Graphics::BlendEquation getBlendEquationAlpha() const { return mBlendEquationA; } - - const Color4f& getBlendConstantColor() const { return mBlendConstantColor; } - - bool getAlphaTestEnable() const { return mAlphaTestEnable; } - - Graphics::AlphaFunc getAlphaTestFunc() const { return mAlphaTestFunc; } - - f32 getAlphaTestRef() const { return mAlphaTestRef; } - - bool getColorMaskR() const { return mColorMaskR; } - - bool getColorMaskG() const { return mColorMaskG; } - - bool getColorMaskB() const { return mColorMaskB; } - - bool getColorMaskA() const { return mColorMaskA; } - - bool getStencilTestEnable() const { return mStencilTestEnable; } - - Graphics::StencilFunc getStencilTestFunc() const { return mStencilTestFunc; } - - s32 getStencilTestRef() const { return mStencilTestRef; } - - u32 getStencilTestMask() const { return mStencilTestMask; } - - Graphics::StencilOp getStencilTestOpFail() const { return mStencilOpFail; } - - Graphics::StencilOp getStencilTestOpZFail() const { return mStencilOpZFail; } - - Graphics::StencilOp getStencilTestOpZPass() const { return mStencilOpZPass; } - - Graphics::PolygonMode getPolygonModeFront() const - { -#ifdef cafe - return mPolygonModeFront; -#endif // cafe - } - - Graphics::PolygonMode getPolygonModeBack() const - { -#ifdef cafe - return mPolygonModeBack; -#endif // cafe - } - - bool getPolygonOffsetFrontEnable() const - { -#ifdef cafe - return mPolygonOffsetFrontEnable; -#endif // cafe - } - - bool getPolygonOffsetBackEnable() const - { -#ifdef cafe - return mPolygonOffsetBackEnable; -#endif // cafe - } - - bool getPolygonOffsetPointLineEnable() const - { -#ifdef cafe - return mPolygonOffsetPointLineEnable; -#endif // cafe - } - -private: - bool mDepthTestEnable; - bool mDepthWriteEnable; - Graphics::DepthFunc mDepthFunc; - Graphics::CullingMode mCullingMode; - bool mBlendEnable; - Graphics::BlendFactor mBlendFactorSrcRGB; - Graphics::BlendFactor mBlendFactorSrcA; - Graphics::BlendFactor mBlendFactorDstRGB; - Graphics::BlendFactor mBlendFactorDstA; - Graphics::BlendEquation mBlendEquationRGB; - Graphics::BlendEquation mBlendEquationA; - Color4f mBlendConstantColor; - bool mAlphaTestEnable; - Graphics::AlphaFunc mAlphaTestFunc; - f32 mAlphaTestRef; - bool mColorMaskR; - bool mColorMaskG; - bool mColorMaskB; - bool mColorMaskA; - bool mStencilTestEnable; - Graphics::StencilFunc mStencilTestFunc; - s32 mStencilTestRef; - u32 mStencilTestMask; - Graphics::StencilOp mStencilOpFail; - Graphics::StencilOp mStencilOpZFail; - Graphics::StencilOp mStencilOpZPass; -#ifdef cafe - Graphics::PolygonMode mPolygonModeFront; - Graphics::PolygonMode mPolygonModeBack; - bool mPolygonOffsetFrontEnable; - bool mPolygonOffsetBackEnable; - bool mPolygonOffsetPointLineEnable; -#endif // cafe -}; -#ifdef cafe -static_assert(sizeof(GraphicsContext) == 0x74, "sead::GraphicsContext size mismatch"); -#endif // cafe - -} // namespace sead diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index 534b2651..498e4892 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -228,7 +228,6 @@ class FrustumProjection : public Projection public: FrustumProjection() = default; FrustumProjection(f32 _near, f32 _far, f32 top, f32 bottom, f32 left, f32 right); - FrustumProjection(f32 _near, f32 _far, const BoundBox2f& box); ~FrustumProjection() override = default; Type getProjectionType() const override { return Projection::cType_Perspective; } diff --git a/modules/src/gfx/seadGraphicsContext.cpp b/modules/src/gfx/seadGraphicsContext.cpp deleted file mode 100644 index 745a15fb..00000000 --- a/modules/src/gfx/seadGraphicsContext.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include - -namespace sead -{ - -GraphicsContext::GraphicsContext() -#ifdef cafe - - : - - mDepthTestEnable(true), mDepthWriteEnable(true), mDepthFunc(Graphics::cDepthFunc_LessEqual), - mCullingMode(Graphics::cCullingMode_Back) - - , - mBlendEnable(true), mBlendFactorSrcRGB(Graphics::cBlendFactor_SrcAlpha), - mBlendFactorSrcA(Graphics::cBlendFactor_SrcAlpha), - mBlendFactorDstRGB(Graphics::cBlendFactor_InvSrcAlpha), - mBlendFactorDstA(Graphics::cBlendFactor_InvSrcAlpha), - mBlendEquationRGB(Graphics::cBlendEquation_Add), - mBlendEquationA(Graphics::cBlendEquation_Add), mBlendConstantColor(1.0f, 1.0f, 1.0f, 1.0f) - - , - mAlphaTestEnable(false), mAlphaTestFunc(Graphics::cAlphaFunc_Greater), mAlphaTestRef(0.0f) - - , - mColorMaskR(true), mColorMaskG(true), mColorMaskB(true), mColorMaskA(true) - - , - mStencilTestEnable(false), mStencilTestFunc(Graphics::cStencilFunc_Never), mStencilTestRef(0), - mStencilTestMask(0xFFFFFFFF), mStencilOpFail(Graphics::cStencilOp_Keep), - mStencilOpZFail(Graphics::cStencilOp_Keep), mStencilOpZPass(Graphics::cStencilOp_Keep) - - , - mPolygonModeFront(Graphics::cPolygonMode_Fill), mPolygonModeBack(Graphics::cPolygonMode_Fill), - mPolygonOffsetFrontEnable(false), mPolygonOffsetBackEnable(false), - mPolygonOffsetPointLineEnable(false) -#endif // cafe -{ -} - -void GraphicsContext::apply() const -{ -#ifdef cafe - GX2SetDepthStencilControl( - static_cast(mDepthTestEnable), static_cast(mDepthWriteEnable), - static_cast(mDepthFunc), static_cast(mStencilTestEnable), - static_cast(mStencilTestEnable), - static_cast(mStencilTestFunc), - static_cast(mStencilOpZPass), - static_cast(mStencilOpZFail), - static_cast(mStencilOpFail), - static_cast(mStencilTestFunc), - static_cast(mStencilOpZPass), - static_cast(mStencilOpZFail), - static_cast(mStencilOpFail)); - - GX2SetStencilMask(mStencilTestMask, mStencilTestRef, - mStencilTestRef, // Bug: ref in place of write mask - mStencilTestMask, mStencilTestRef, mStencilTestRef); // ^^^ - - { - static const GX2Boolean cCullSettings[4][2] = {{GX2_ENABLE, GX2_DISABLE}, - {GX2_DISABLE, GX2_ENABLE}, - {GX2_DISABLE, GX2_DISABLE}, - {GX2_ENABLE, GX2_ENABLE}}; - const GX2Boolean* const& settings = cCullSettings[mCullingMode]; - - GX2SetPolygonControl( - GX2_FRONT_FACE_CCW, settings[0], settings[1], - static_cast(mPolygonModeFront != Graphics::cPolygonMode_Fill || - mPolygonModeBack != Graphics::cPolygonMode_Fill), - static_cast(mPolygonModeFront), - static_cast(mPolygonModeBack), - static_cast(mPolygonOffsetFrontEnable), - static_cast(mPolygonOffsetBackEnable), - static_cast(mPolygonOffsetPointLineEnable)); - } - - GX2SetColorControl( - GX2_LOGIC_OP_NONE, mBlendEnable ? 0xFF : 0, GX2_DISABLE, - static_cast(mColorMaskR || mColorMaskG || mColorMaskB || mColorMaskA)); - - GX2SetBlendControl(GX2_RENDER_TARGET_0, static_cast(mBlendFactorSrcRGB), - static_cast(mBlendFactorDstRGB), - static_cast(mBlendEquationRGB), GX2_ENABLE, - static_cast(mBlendFactorSrcA), - static_cast(mBlendFactorDstA), - static_cast(mBlendEquationA)); - - GX2SetBlendConstantColor(mBlendConstantColor.r, mBlendConstantColor.g, mBlendConstantColor.b, - mBlendConstantColor.a); - - GX2SetAlphaTest(static_cast(mAlphaTestEnable), - static_cast(mAlphaTestFunc), mAlphaTestRef); - - GX2SetTargetChannelMasks( - static_cast( - mColorMaskR * GX2_CHANNEL_MASK_R + mColorMaskG * GX2_CHANNEL_MASK_G + - mColorMaskB * GX2_CHANNEL_MASK_B + mColorMaskA * GX2_CHANNEL_MASK_A), - GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, - GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE); - - GX2SetAlphaToMask(GX2_DISABLE, GX2_ALPHA_TO_MASK_0); -#endif // cafe -} - -void GraphicsContext::applyAlphaTest() const -{ -#ifdef cafe - GX2SetAlphaTest(static_cast(mAlphaTestEnable), - static_cast(mAlphaTestFunc), mAlphaTestRef); -#endif // cafe -} - -void GraphicsContext::applyDepthAndStencilTest() const -{ -#ifdef cafe - GX2SetDepthStencilControl( - static_cast(mDepthTestEnable), static_cast(mDepthWriteEnable), - static_cast(mDepthFunc), static_cast(mStencilTestEnable), - static_cast(mStencilTestEnable), - static_cast(mStencilTestFunc), - static_cast(mStencilOpZPass), - static_cast(mStencilOpZFail), - static_cast(mStencilOpFail), - static_cast(mStencilTestFunc), - static_cast(mStencilOpZPass), - static_cast(mStencilOpZFail), - static_cast(mStencilOpFail)); - - GX2SetStencilMask(mStencilTestMask, mStencilTestRef, - mStencilTestRef, // Bug: ref in place of write mask - mStencilTestMask, mStencilTestRef, mStencilTestRef); // ^^^ -#endif // cafe -} - -void GraphicsContext::applyColorMask() const -{ -#ifdef cafe - GX2SetTargetChannelMasks( - static_cast( - mColorMaskR * GX2_CHANNEL_MASK_R + mColorMaskG * GX2_CHANNEL_MASK_G + - mColorMaskB * GX2_CHANNEL_MASK_B + mColorMaskA * GX2_CHANNEL_MASK_A), - GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, - GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE, GX2_CHANNEL_MASK_NONE); -#endif // cafe -} - -void GraphicsContext::applyBlendAndFastZ() const -{ -#ifdef cafe - GX2SetColorControl( - GX2_LOGIC_OP_NONE, mBlendEnable ? 0xFF : 0, GX2_DISABLE, - static_cast(mColorMaskR || mColorMaskG || mColorMaskB || mColorMaskA)); - - GX2SetBlendControl(GX2_RENDER_TARGET_0, static_cast(mBlendFactorSrcRGB), - static_cast(mBlendFactorDstRGB), - static_cast(mBlendEquationRGB), GX2_ENABLE, - static_cast(mBlendFactorSrcA), - static_cast(mBlendFactorDstA), - static_cast(mBlendEquationA)); -#endif // cafe -} - -void GraphicsContext::applyBlendConstantColor() const -{ -#ifdef cafe - GX2SetBlendConstantColor(mBlendConstantColor.r, mBlendConstantColor.g, mBlendConstantColor.b, - mBlendConstantColor.a); -#endif // cafe -} - -void GraphicsContext::applyCullingAndPolygonModeAndPolygonOffset() const -{ -#ifdef cafe - static const GX2Boolean cCullSettings[4][2] = {{GX2_ENABLE, GX2_DISABLE}, - {GX2_DISABLE, GX2_ENABLE}, - {GX2_DISABLE, GX2_DISABLE}, - {GX2_ENABLE, GX2_ENABLE}}; - const GX2Boolean* const& settings = cCullSettings[mCullingMode]; - - GX2SetPolygonControl(GX2_FRONT_FACE_CCW, settings[0], settings[1], - static_cast(mPolygonModeFront != Graphics::cPolygonMode_Fill || - mPolygonModeBack != Graphics::cPolygonMode_Fill), - static_cast(mPolygonModeFront), - static_cast(mPolygonModeBack), - static_cast(mPolygonOffsetFrontEnable), - static_cast(mPolygonOffsetBackEnable), - static_cast(mPolygonOffsetPointLineEnable)); -#endif // cafe -} - -} // namespace sead diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index a1e61187..45315994 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -402,11 +402,6 @@ FrustumProjection::FrustumProjection(f32 _near, f32 _far, f32 top, f32 bottom, f setDirty(); } -FrustumProjection::FrustumProjection(f32 _near, f32 _far, const BoundBox2f& box) - : mNear(_near), mFar(_far) -{ -} - f32 FrustumProjection::getNear() const { return mNear; From 136aa695bba2ab92af9dedc2b356caf3e083ad1b Mon Sep 17 00:00:00 2001 From: Esras Date: Fri, 14 Aug 2026 08:55:57 -0600 Subject: [PATCH 20/22] Restore LookAtCamera::normalizeUp() for SMO compat 63d9f32 folded the normalize into setUp() and dropped the standalone method, but SMO's CameraPoser::makeLookAtCameraPrev calls setUp() immediately followed by normalizeUp() as two separate steps - it's decomp output tracking the actual SMO binary, so it can't be edited to match. Re-adding the wrapper keeps both builds green; no BotW caller depends on normalizeUp() being absent. --- include/gfx/seadCamera.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index 05a4272a..88cd2e68 100644 --- a/include/gfx/seadCamera.h +++ b/include/gfx/seadCamera.h @@ -63,6 +63,7 @@ class LookAtCamera : public Camera mUp = up; mUp.normalize(); } + void normalizeUp() { mUp.normalize(); } void addPos(const Vector3f& pos) { mPos += pos; } void addAt(const Vector3f& at) { mAt += at; } From 2d9f2e57a05aeccd74db85cc3f1a06e3899724a6 Mon Sep 17 00:00:00 2001 From: Esras Date: Fri, 14 Aug 2026 08:57:46 -0600 Subject: [PATCH 21/22] Revert "Restore LookAtCamera::normalizeUp() for SMO compat" This reverts commit 136aa695bba2ab92af9dedc2b356caf3e083ad1b. --- include/gfx/seadCamera.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index 88cd2e68..05a4272a 100644 --- a/include/gfx/seadCamera.h +++ b/include/gfx/seadCamera.h @@ -63,7 +63,6 @@ class LookAtCamera : public Camera mUp = up; mUp.normalize(); } - void normalizeUp() { mUp.normalize(); } void addPos(const Vector3f& pos) { mPos += pos; } void addAt(const Vector3f& at) { mAt += at; } From e0013cbef75bd4422cf42f4724661439ce04c797 Mon Sep 17 00:00:00 2001 From: Esras Date: Fri, 14 Aug 2026 09:07:42 -0600 Subject: [PATCH 22/22] Add back an empty LookAtCamera::normalizeUp() so SMO compiles. --- include/gfx/seadCamera.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index 05a4272a..4aabff04 100644 --- a/include/gfx/seadCamera.h +++ b/include/gfx/seadCamera.h @@ -63,6 +63,7 @@ class LookAtCamera : public Camera mUp = up; mUp.normalize(); } + void normalizeUp() {} void addPos(const Vector3f& pos) { mPos += pos; } void addAt(const Vector3f& at) { mAt += at; }