diff --git a/CMakeLists.txt b/CMakeLists.txt index a535892e2..66e353a6a 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 @@ -155,6 +161,8 @@ add_library(sead OBJECT 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/geom/seadLine.h b/include/geom/seadLine.h new file mode 100644 index 000000000..4a624717b --- /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/nin/seadGraphicsNvn.h b/include/gfx/nin/seadGraphicsNvn.h index e8686564d..2de267032 100644 --- a/include/gfx/nin/seadGraphicsNvn.h +++ b/include/gfx/nin/seadGraphicsNvn.h @@ -65,4 +65,4 @@ class GraphicsNvn : public Graphics }; static_assert(sizeof(GraphicsNvn) == 0x208); -} // namespace sead \ No newline at end of file +} // namespace sead diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index f0823f0e2..b387ed35b 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; } @@ -79,6 +78,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 1beb2c341..2e127c3c9 100644 --- a/include/gfx/seadGraphics.h +++ b/include/gfx/seadGraphics.h @@ -2,15 +2,20 @@ #include #include +#include + +#ifdef cafe +#include +#endif // cafe namespace sead { -// no content yet, just for the enum -class Graphics : public IDisposer -{ - using UnknownCallback = void (*)(int); - static Graphics* sInstance; +class Color4f; +class Thread; + +class Graphics : public sead::IDisposer +{ public: enum DevicePosture { @@ -21,19 +26,239 @@ class Graphics : public IDisposer cDevicePosture_FlipX = 4, cDevicePosture_FlipY = 5, cDevicePosture_FlipXY = 3, - cDevicePosture_Invalid = 4, + cDevicePosture_Invalid = 4 }; - void lockDrawContext(); - void unlockDrawContext(); - void initHostIO(); - void initializeDrawLockContext(Heap*); + static const u32 cRenderTarget_Num = 8; + + static DevicePosture getDefaultDevicePosture() { return sDefaultDevicePosture; } + static f32 getDefaultDeviceZScale() { return sDefaultDeviceZScale; } + static f32 getDefaultDeviceZOffset() { return sDefaultDeviceZOffset; } + + // The value for each enumerator in the following enums has been confirmed to be + // platform-specific when comparing sead between several platforms (3DS, Wii U, Switch) + + enum DepthFunc + { +#ifdef cafe + cDepthFunc_Never = GX2_COMPARE_NEVER, + cDepthFunc_Less = GX2_COMPARE_LESS, + cDepthFunc_Equal = GX2_COMPARE_EQUAL, + cDepthFunc_LessEqual = GX2_COMPARE_LEQUAL, + cDepthFunc_Greater = GX2_COMPARE_GREATER, + cDepthFunc_NotEqual = GX2_COMPARE_NOTEQUAL, + cDepthFunc_GreaterEqual = GX2_COMPARE_GEQUAL, + cDepthFunc_Always = GX2_COMPARE_ALWAYS +#endif // cafe + }; + + enum CullingMode + { +#ifdef cafe + cCullingMode_Front = 0, + cCullingMode_Back = 1, + cCullingMode_None = 2, + cCullingMode_All = 3 +#endif // cafe + }; + + enum BlendFactor + { +#ifdef cafe + cBlendFactor_Zero = GX2_BLEND_ZERO, + cBlendFactor_One = GX2_BLEND_ONE, + cBlendFactor_SrcColor = GX2_BLEND_SRC_COLOR, + cBlendFactor_InvSrcColor = GX2_BLEND_ONE_MINUS_SRC_COLOR, + cBlendFactor_SrcAlpha = GX2_BLEND_SRC_ALPHA, + cBlendFactor_InvSrcAlpha = GX2_BLEND_ONE_MINUS_SRC_ALPHA, + cBlendFactor_DstAlpha = GX2_BLEND_DST_ALPHA, + cBlendFactor_InvDstAlpha = GX2_BLEND_ONE_MINUS_DST_ALPHA, + cBlendFactor_DstColor = GX2_BLEND_DST_COLOR, + cBlendFactor_InvDstColor = GX2_BLEND_ONE_MINUS_DST_COLOR, + cBlendFactor_SrcAlphaSaturate = GX2_BLEND_SRC_ALPHA_SATURATE, + cBlendFactor_ConstantColor = GX2_BLEND_CONSTANT_COLOR, + cBlendFactor_InvConstantColor = GX2_BLEND_ONE_MINUS_CONSTANT_COLOR, + cBlendFactor_ConstantAlpha = GX2_BLEND_CONSTANT_ALPHA, + cBlendFactor_InvConstantAlpha = GX2_BLEND_ONE_MINUS_CONSTANT_ALPHA +#endif // cafe + }; + + enum BlendEquation + { +#ifdef cafe + cBlendEquation_Add = GX2_BLEND_COMBINE_ADD, + cBlendEquation_Sub = GX2_BLEND_COMBINE_SRC_MINUS_DST, + cBlendEquation_Min = GX2_BLEND_COMBINE_MIN, + cBlendEquation_Max = GX2_BLEND_COMBINE_MAX, + cBlendEquation_ReverseSub = GX2_BLEND_COMBINE_DST_MINUS_SRC +#endif // cafe + }; + + enum AlphaFunc + { +#ifdef cafe + cAlphaFunc_Never = GX2_COMPARE_NEVER, + cAlphaFunc_Less = GX2_COMPARE_LESS, + cAlphaFunc_Equal = GX2_COMPARE_EQUAL, + cAlphaFunc_LessEqual = GX2_COMPARE_LEQUAL, + cAlphaFunc_Greater = GX2_COMPARE_GREATER, + cAlphaFunc_NotEqual = GX2_COMPARE_NOTEQUAL, + cAlphaFunc_GreaterEqual = GX2_COMPARE_GEQUAL, + cAlphaFunc_Always = GX2_COMPARE_ALWAYS +#endif // cafe + }; + + enum StencilFunc + { +#ifdef cafe + cStencilFunc_Never = GX2_COMPARE_NEVER, + cStencilFunc_Less = GX2_COMPARE_LESS, + cStencilFunc_Equal = GX2_COMPARE_EQUAL, + cStencilFunc_LessEqual = GX2_COMPARE_LEQUAL, + cStencilFunc_Greater = GX2_COMPARE_GREATER, + cStencilFunc_NotEqual = GX2_COMPARE_NOTEQUAL, + cStencilFunc_GreaterEqual = GX2_COMPARE_GEQUAL, + cStencilFunc_Always = GX2_COMPARE_ALWAYS +#endif // cafe + }; + + enum StencilOp + { +#ifdef cafe + cStencilOp_Keep = GX2_STENCIL_KEEP, + cStencilOp_Zero = GX2_STENCIL_ZERO, + cStencilOp_Replace = GX2_STENCIL_REPLACE, + cStencilOp_Increment = GX2_STENCIL_INCR, + cStencilOp_Decrement = GX2_STENCIL_DECR, + cStencilOp_Invert = GX2_STENCIL_INVERT, + cStencilOp_IncrementWrap = GX2_STENCIL_INCR_WRAP, + cStencilOp_DecrementWrap = GX2_STENCIL_DECR_WRAP +#endif // cafe + }; + + enum PolygonMode + { +#ifdef cafe + cPolygonMode_Point = GX2_POLYGON_MODE_POINT, + cPolygonMode_Line = GX2_POLYGON_MODE_LINE, + cPolygonMode_Fill = GX2_POLYGON_MODE_TRIANGLE +#endif // cafe + }; static Graphics* instance() { return sInstance; } + static void setInstance(Graphics* impl) { sInstance = impl; } + + Graphics(); + ~Graphics() override; private: - UnknownCallback _20; - DrawLockContext* mDrawLockContext; + Graphics(const Graphics&); + const Graphics& operator=(const Graphics&); + +protected: + virtual void initializeImpl(); + virtual void setViewportImpl(f32 x, f32 y, f32 w, f32 h); + virtual void setScissorImpl(f32 x, f32 y, f32 w, f32 h); + virtual void setDepthTestEnableImpl(bool enable); + virtual void setDepthWriteEnableImpl(bool enable); + virtual void setDepthFuncImpl(DepthFunc func); + virtual bool setVBlankWaitIntervalImpl(u32 interval); + virtual void setCullingModeImpl(CullingMode mode); + virtual void setBlendEnableImpl(bool enable); + virtual void setBlendEnableMRTImpl(u32 target, bool enable); + virtual void setBlendFactorImpl(BlendFactor src_factor_rgb, BlendFactor dst_factor_rgb, + BlendFactor src_factor_a, BlendFactor dst_factor_a); + virtual void setBlendFactorMRTImpl(u32 target, BlendFactor src_factor_rgb, + BlendFactor dst_factor_rgb, BlendFactor src_factor_a, + BlendFactor dst_factor_a); + virtual void setBlendEquationImpl(BlendEquation equation_rgb, BlendEquation equation_a); + virtual void setBlendEquationMRTImpl(u32 target, BlendEquation equation_rgb, + BlendEquation equation_a); + virtual void setBlendConstantColorImpl(const Color4f& color); + virtual void lockDrawContextImpl(); + virtual void unlockDrawContextImpl(); + virtual void waitForVBlankImpl(); + virtual void setColorMaskImpl(bool r, bool g, bool b, bool a); + virtual void setColorMaskMRTImpl(u32 target, bool r, bool g, bool b, bool a); + virtual void setAlphaTestEnableImpl(bool enable); + virtual void setAlphaTestFuncImpl(AlphaFunc func, f32 ref); + virtual void setStencilTestEnableImpl(bool enable); + virtual void setStencilTestFuncImpl(StencilFunc func, s32 ref, u32 mask); + virtual void setStencilTestOpImpl(StencilOp fail, StencilOp zfail, StencilOp zpass); + virtual void setPolygonModeImpl(PolygonMode front, PolygonMode back); + virtual void setPolygonOffsetEnableImpl(bool fill_front_enable, bool fill_back_enable, + bool point_line_enable); + +public: + 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); } + + void setDepthEnable(bool test_enable, bool write_enable) + { + setDepthTestEnableImpl(test_enable); + setDepthWriteEnableImpl(write_enable); + } + + void setBlendEnable(bool enable) { setBlendEnableImpl(enable); } + + void setBlendFactor(BlendFactor src_factor, BlendFactor dst_factor) + { + setBlendFactorImpl(src_factor, dst_factor, src_factor, dst_factor); + } + + void setBlendFactorSeparate(BlendFactor src_factor_rgb, BlendFactor dst_factor_rgb, + BlendFactor src_factor_a, BlendFactor dst_factor_a) + { + setBlendFactorImpl(src_factor_rgb, dst_factor_rgb, src_factor_a, dst_factor_a); + } + + void setBlendFactorMRT(u32 target, BlendFactor src_factor, BlendFactor dst_factor) + { + setBlendFactorMRTImpl(target, src_factor, dst_factor, src_factor, dst_factor); + } + + void setBlendFactorSeparateMRT(u32 target, BlendFactor src_factor_rgb, + BlendFactor dst_factor_rgb, BlendFactor src_factor_a, + BlendFactor dst_factor_a) + { + setBlendFactorMRTImpl(target, src_factor_rgb, dst_factor_rgb, src_factor_a, dst_factor_a); + } + + void setBlendEquation(BlendEquation equation) { setBlendEquationImpl(equation, equation); } + + void setBlendEquationSeparate(BlendEquation equation_rgb, BlendEquation equation_a) + { + setBlendEquationImpl(equation_rgb, equation_a); + } + + void setBlendEquationMRT(u32 target, BlendEquation equation) + { + setBlendEquationMRTImpl(target, equation, equation); + } + + void setBlendEquationSeparateMRT(u32 target, BlendEquation equation_rgb, + BlendEquation equation_a) + { + setBlendEquationMRTImpl(target, equation_rgb, equation_a); + } + + void lockDrawContext(); + void unlockDrawContext(); + +protected: + Thread* mContextHolderThread; + s32 mContextRefCounter; + CriticalSection mContextCriticalSection; + + static Graphics* sInstance; + + static DevicePosture sDefaultDevicePosture; + static f32 sDefaultDeviceZScale; + static f32 sDefaultDeviceZOffset; }; +#ifdef cafe +static_assert(sizeof(Graphics) == 0x54, "sead::Graphics size mismatch"); +#endif // cafe } // namespace sead diff --git a/include/gfx/seadGraphicsContext.h b/include/gfx/seadGraphicsContext.h new file mode 100644 index 000000000..705674a17 --- /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 4f70db7d8..a3ef4fc74 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 @@ -11,13 +11,23 @@ namespace sead { + +class Camera; +class Viewport; + class Projection { SEAD_RTTI_BASE(Projection) public: + enum Type + { + cType_Perspective = 0, + cType_Ortho = 1, + cType_Undefined = 2 + }; Projection(); - virtual ~Projection(); + virtual ~Projection() = default; virtual f32 getNear() const = 0; virtual f32 getFar() const = 0; @@ -25,13 +35,23 @@ 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; + const Matrix44f& getDeviceProjectionMatrix() const; + const Matrix44f& getProjectionMatrix() const; + Matrix44f& getProjectionMatrixMutable(); + virtual void doScreenPosToCameraPosTo(Vector3f*, const Vector3f&) const = 0; + void cameraPosToScreenPos(Vector3f* dst, const Vector3f& camera_pos) const; + void screenPosToCameraPos(Vector3f* dst, const Vector3f& screen_pos) const; + void screenPosToCameraPos(Vector3f* dst, const Vector2f& screen_pos) const; - void updateMatrixImpl_() const; - const Matrix44f& getDeviceProjectionMatrix() const; + void project(Vector2f* dst, const Vector3f& camera_pos, const Viewport& viewport) const; + void unproject(Vector3f* dst, const Vector3f& screenPos, const Camera& camera) const; + void unprojectRay(Ray* dst, const Vector3f& screenPos, const Camera& camera) const; void setDirty() { mDirty = true; } void setDeviceDirty() { mDeviceDirty = true; } @@ -43,6 +63,8 @@ class Projection } private: + void updateMatrixImpl_() const; + mutable bool mDirty; mutable bool mDeviceDirty; Matrix44f mMatrix; @@ -59,25 +81,9 @@ class PerspectiveProjection : public Projection public: PerspectiveProjection(); PerspectiveProjection(f32 near, f32 far, f32 fovy_rad, f32 aspect); - ~PerspectiveProjection() override; + ~PerspectiveProjection() override = default; - 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; - - 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) { @@ -89,6 +95,8 @@ class PerspectiveProjection : public Projection mFar = far; setDirty(); } + void setFovx(f32 fovx); + void setFovy(f32 fovy) { setFovy_(fovy); } void setAspect(f32 aspect) { mAspect = aspect; @@ -100,41 +108,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 = 4.0f / 3.0f; + 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; @@ -143,32 +192,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: @@ -186,30 +254,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 566aaf7c2..a3601420c 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 000000000..43877782f --- /dev/null +++ b/include/math/seadGeometry.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +namespace sead +{ +namespace Geometry +{ +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/include/math/seadMatrix.hpp b/include/math/seadMatrix.hpp index 858f15551..fd3dfa07f 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 diff --git a/modules/src/gfx/seadCamera.cpp b/modules/src/gfx/seadCamera.cpp index ae58e8513..05128893d 100644 --- a/modules/src/gfx/seadCamera.cpp +++ b/modules/src/gfx/seadCamera.cpp @@ -1,10 +1,85 @@ #include "gfx/seadCamera.h" +#include +#include #include "basis/seadRawPrint.h" +#include "math/seadMatrixCalcCommon.h" namespace sead { 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->setMul(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 +89,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 000000000..f49405f63 --- /dev/null +++ b/modules/src/gfx/seadGraphics.cpp @@ -0,0 +1,44 @@ +#include +#include + +namespace sead +{ + +Graphics* Graphics::sInstance = nullptr; + +Graphics::DevicePosture Graphics::sDefaultDevicePosture = Graphics::cDevicePosture_Same; +f32 Graphics::sDefaultDeviceZScale = 1.0f; +f32 Graphics::sDefaultDeviceZOffset = 0.0f; + +void Graphics::lockDrawContext() +{ + sead::Thread* current = ThreadMgr::instance()->getCurrentThread(); + if (current == mContextHolderThread && mContextRefCounter > 0) + { + mContextRefCounter++; + } + else + { + mContextCriticalSection.lock(); + // SEAD_ASSERT(mContextHolderThread == nullptr); + // SEAD_ASSERT(mContextRefCounter == 0); + lockDrawContextImpl(); + mContextHolderThread = current; + mContextRefCounter = 1; + } +} + +void Graphics::unlockDrawContext() +{ + sead::Thread* current = ThreadMgr::instance()->getCurrentThread(); + // SEAD_ASSERT(mContextHolderThread == current); + // SEAD_ASSERT(mContextRefCounter > 0); + if (--mContextRefCounter == 0) + { + mContextHolderThread = nullptr; + unlockDrawContextImpl(); + mContextCriticalSection.unlock(); + } +} + +} // namespace sead diff --git a/modules/src/gfx/seadGraphicsContext.cpp b/modules/src/gfx/seadGraphicsContext.cpp new file mode 100644 index 000000000..745a15fbd --- /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 4179f1e98..8b56f6f0f 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -1,30 +1,517 @@ +#include #include +#include +#include "math/seadMatrixCalcCommon.h" +#include "math/seadVectorCalcCommon.h" namespace sead { +Projection::Projection() + : mDirty(true), mDeviceDirty(true), mDevicePosture(Graphics::getDefaultDevicePosture()), + mDeviceZScale(Graphics::getDefaultDeviceZScale()), + mDeviceZOffset(Graphics::getDefaultDeviceZOffset()) +{ +} + void Projection::updateMatrixImpl_() const { if (mDirty) { doUpdateMatrix(const_cast(&mMatrix)); mDirty = false; - mDeviceDirty = true; - doUpdateDeviceMatrix(const_cast(&mDeviceMatrix), mMatrix, mDevicePosture); - mDeviceDirty = false; } - else if (mDeviceDirty) + if (mDeviceDirty) { doUpdateDeviceMatrix(const_cast(&mDeviceMatrix), mMatrix, mDevicePosture); mDeviceDirty = false; } } +const Matrix44f& Projection::getProjectionMatrix() const +{ + updateMatrixImpl_(); + return mMatrix; +} + const Matrix44f& Projection::getDeviceProjectionMatrix() const { updateMatrixImpl_(); return mDeviceMatrix; } +void Projection::project(Vector2f* dst, const Vector3f& camera_pos, const Viewport& viewport) const +{ + Vector3f temp; + doScreenPosToCameraPosTo(&temp, camera_pos); + viewport.project(dst, temp); +} + +void Projection::unproject(Vector3f* dst, const Vector3f& screenPos, const Camera& camera) const +{ + doScreenPosToCameraPosTo(dst, screenPos); + camera.cameraPosToWorldPosByMatrix(dst, screenPos); +} + +void Projection::unprojectRay(Ray* dst, const Vector3f& screenPos, + const Camera& camera) const +{ + Vector3f newVec; + doScreenPosToCameraPosTo(&dst->position, screenPos); + camera.unprojectRayByMatrix(dst, newVec); +} + +void Projection::updateAttributesForDirectProjection() {} + +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 000000000..9de7d6e02 --- /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 000000000..0efcdf762 --- /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