diff --git a/CMakeLists.txt b/CMakeLists.txt index edbe2783..66ec67ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,8 @@ add_library(sead OBJECT include/gfx/seadDrawContext.h include/gfx/seadDrawLockContext.h include/gfx/seadFrameBuffer.h + include/gfx/seadGraphics.h + include/gfx/seadViewport.h include/gfx/seadPrimitiveRenderer.h include/gfx/seadPrimitiveRendererUtil.h include/gfx/seadProjection.h @@ -112,6 +114,8 @@ 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/seadViewport.cpp # modules/src/gfx/seadPrimitiveRenderer.cpp # modules/src/gfx/seadPrimitiveRendererUtil.cpp modules/src/gfx/seadProjection.cpp @@ -155,6 +159,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 00000000..9552c862 --- /dev/null +++ b/include/geom/seadLine.h @@ -0,0 +1,55 @@ +#pragma once + +#include + +namespace sead +{ + +template +class Segment +{ +public: + Segment() = default; + Segment(const T& p0, const T& p1) : mP0(p0), mP1(p1) {} + + const T& getPos0() const { return mP0; } + void setPos0(const T& p0) { mP0 = p0; } + + const T& getPos1() const { return mP1; } + void setPos1(const T& p1) { mP1 = p1; } + +private: + T mP0 = T::zero; + T mP1 = T::ex; +}; + +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: + 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; +}; + +using Ray2f = Ray; +using Ray3f = Ray; + +} // namespace sead diff --git a/include/gfx/seadCamera.h b/include/gfx/seadCamera.h index 731ce1c9..4aabff04 100644 --- a/include/gfx/seadCamera.h +++ b/include/gfx/seadCamera.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -9,8 +10,6 @@ namespace sead class OrthoProjection; class Projection; class Viewport; -template -class Ray; class Camera { @@ -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; } @@ -59,14 +58,18 @@ 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() {} - void normalizeUp() { mUp.normalize(); } void addPos(const Vector3f& pos) { mPos += pos; } 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}; }; @@ -75,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 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/seadProjection.h b/include/gfx/seadProjection.h index f3d64fa7..498e4892 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; @@ -74,23 +81,7 @@ class PerspectiveProjection : public Projection 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; - - 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,9 @@ class PerspectiveProjection : public Projection mFar = far; setDirty(); } + 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) { mAspect = aspect; @@ -113,41 +107,106 @@ 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; + f32 getFar() const override; + f32 getFovy() const override; + f32 getAspect() const override; + void getOffset(Vector2f* offset) const override; + + 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; 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; + + 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); + + void createDividedProjection(OrthoProjection* dst, s32 partno_x, s32 partno_y, s32 divnum_x, + s32 divnum_y) const; 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; } + 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 +215,76 @@ 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() 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) + { + 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 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; f32 getFar() const override; + f32 getTop() const { return mTop; } + f32 getBottom() const { return mBottom; } + f32 getLeft() const { return mLeft; } + f32 getRight() const { return mRight; } + f32 getFovy() const override; f32 getAspect() const override; - void getOffset(Vector2f* offset) const override; + void getOffset(Vector2f* dst) const override; f32 getOffsetX() const; f32 getOffsetY() const; - u32 getProjectionType() 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: @@ -200,29 +303,34 @@ class DirectProjection : public Projection public: DirectProjection(); DirectProjection(const Matrix44f& mtx, Graphics::DevicePosture posture); - ~DirectProjection() override; + ~DirectProjection() override = default; + + void updateAttributesForDirectProjection() override; + Type getProjectionType() const override { return cType_Undefined; } + void doUpdateMatrix(Matrix44f* dst) const override; 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; + + 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; + f32 mNear = 0.0; + f32 mFar = 0.0; + f32 mFovy = 0.0; + f32 mAspect = 0.0; + Vector2f mOffset = {0.0f, 0.0f}; + bool mAttributesDirty = 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..5a4de890 100644 --- a/include/gfx/seadViewport.h +++ b/include/gfx/seadViewport.h @@ -1,39 +1,48 @@ #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 { 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; 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; + + Graphics::DevicePosture getDevicePosture() const { return mDevicePosture; } private: - Graphics::DevicePosture mDevicePosture; + 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"); +#endif // cafe + } // namespace sead diff --git a/include/math/seadGeometry.h b/include/math/seadGeometry.h new file mode 100644 index 00000000..aa28ebe9 --- /dev/null +++ b/include/math/seadGeometry.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +namespace sead +{ +namespace Geometry +{ +f32 calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, f32* closestRayPos); +// 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 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 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 <> 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/seadCamera.cpp b/modules/src/gfx/seadCamera.cpp index ae58e851..e643d544 100644 --- a/modules/src/gfx/seadCamera.cpp +++ b/modules/src/gfx/seadCamera.cpp @@ -1,10 +1,103 @@ #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 + const Vector4f vec = mMatrix.getRow(2); + dst->set(vec.x, vec.y, vec.z); +} + +void Camera::getRightVectorByMatrix(Vector3f* dst) const +{ + const Vector4f vec = mMatrix.getRow(0); + dst->set(vec.x, vec.y, vec.z); +} + +void Camera::getUpVectorByMatrix(Vector3f* dst) const +{ + const Vector4f 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 +{ + 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 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.setAdd(up, look); + dir = dir + right; + dir.normalize(); + + Vector3f pos; + getWorldPosByMatrix(&pos); + dst->setPos(pos); + dst->setDir(dir); +} + LookAtCamera::~LookAtCamera() = default; LookAtCamera::LookAtCamera(const Vector3f& pos, const Vector3f& at, const Vector3f& up) @@ -14,8 +107,71 @@ LookAtCamera::LookAtCamera(const Vector3f& pos, const Vector3f& at, const Vector mUp.normalize(); } -OrthoCamera::~OrthoCamera() = default; +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 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/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 9cd07d2d..45315994 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,554 @@ void Projection::unprojectRay(Ray* dst, const Vector3f& screen_pos, camera.unprojectRayByMatrix(dst, camera_pos); } +static void swapMatrixXY(Matrix44f* mtx) +{ + Vector4f x = mtx->getRow(0); + mtx->setRow(0, mtx->getRow(1)); + mtx->setRow(1, x); +} + +static void negateRow(Matrix44f* mtx, s32 row) +{ + (*mtx)(row, 0) *= -1; + (*mtx)(row, 1) *= -1; + (*mtx)(row, 2) *= -1; + (*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 +{ + *dst = src; + + switch (pose) + { + case Graphics::cDevicePosture_Same: + break; + case Graphics::cDevicePosture_RotateLeft: + negateRow(dst, 1); + swapMatrixXY(dst); + break; + case Graphics::cDevicePosture_RotateRight: + negateRow(dst, 0); + swapMatrixXY(dst); + break; + case Graphics::cDevicePosture_RotateHalfAround: + negateRow(dst, 0); + negateRow(dst, 1); + break; + case Graphics::cDevicePosture_FlipX: + negateRow(dst, 0); + break; + case Graphics::cDevicePosture_FlipY: + for (s32 i = 0; i < 4; ++i) + (*dst)(1, i) *= -1; + break; + default: + break; + } + + (*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_(numbers::pi / 4.0f); // 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); +} + +PerspectiveProjection::~PerspectiveProjection() = default; + +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::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; + offset->y = mOffset.y; +} + +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) +{ + setDirty(); +} + +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) +{ + mTop = 0.5f * vp.getSizeY(); + mBottom = -0.5f * vp.getSizeY(); + mLeft = -0.5f * vp.getSizeX(); + mRight = 0.5f * vp.getSizeX(); + setDevicePosture(vp.getDevicePosture()); + 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); +} + +void OrthoProjection::getOffset(Vector2f* offset) const +{ + offset->x = (0.5f * (mLeft + mRight)) / (mRight - mLeft); + offset->y = (0.5f * (mTop + mBottom)) / (mTop - mBottom); +} + +void OrthoProjection::setTBLR(float top, float bottom, float left, float right) +{ + mTop = top; + mBottom = bottom; + mLeft = left; + mRight = right; + setDirty(); +} + +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) = sum_x * -0.5f / inv_size; + + inv_size = (mTop - mBottom) * 0.5f; + + (*dst)(1, 0) = 0; + (*dst)(1, 1) = 1.0f / inv_size; + (*dst)(1, 2) = 0; + (*dst)(1, 3) = sum_y * -0.5f / inv_size; + + f32 inv_depth = 1.0f / (mFar - mNear); + + (*dst)(2, 0) = 0; + (*dst)(2, 1) = 0; + (*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; +} + +void OrthoProjection::setByViewport(const Viewport& vp) +{ + 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 = 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) + : mNear(_near), mFar(_far), mTop(top), mBottom(bottom), mLeft(left), mRight(right) +{ + setDirty(); +} + +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); + + (*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::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; +} + +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 +{ + f32 denom = mRight - mLeft; + dst->x = 0.5f * (mRight + mLeft) / denom; + + denom = mTop - mBottom; + dst->y = 0.5f * (mTop + mBottom) / denom; +} + +f32 FrustumProjection::getOffsetX() const +{ + f32 den = mRight - mLeft; + f32 num = mRight + mLeft; + return 0.5f * num / den; +} + +f32 FrustumProjection::getOffsetY() const +{ + f32 den = mTop - mBottom; + f32 num = mTop + mBottom; + return 0.5f * num / den; +} + +DirectProjection::DirectProjection() : mDirectMatrix(Matrix44f::ident) +{ + setDirty(); +} + +DirectProjection::DirectProjection(const Matrix44f& mtx, Graphics::DevicePosture 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() +{ + 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 +{ + *dst = mDirectMatrix; +} + +void DirectProjection::setProjectionMatrix(const Matrix44f& mtx, Graphics::DevicePosture posture) +{ + 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; +} + +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; + inverseDirect.setInverse(mDirectMatrix); + 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 diff --git a/modules/src/gfx/seadViewport.cpp b/modules/src/gfx/seadViewport.cpp new file mode 100644 index 00000000..fd16d4b2 --- /dev/null +++ b/modules/src/gfx/seadViewport.cpp @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include "math/seadBoundBox.h" +#include "nn/gfx/gfx_StateInfo.h" +#include "nvn/nvn.h" +#include "nvn/nvn_FuncPtrInline.h" + +namespace sead +{ + +Viewport::Viewport() +{ + setUndef(); +} + +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); +} + +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; + + 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)); +#if SEAD_VIEWPORT_DEPTH_RANGE + nvnCommandBufferSetDepthRange(cb, mDepthRange.x, mDepthRange.y); +#endif +} + +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; + + 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 +{ + 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; + + 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 +{ + 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..b49b2c2a --- /dev/null +++ b/modules/src/math/seadGeometry.cpp @@ -0,0 +1,27 @@ +#include + +namespace sead +{ + +// BUG: returns the distance from point to ray origin, ignoring its direction +// (closestRayPos is fine) +f32 Geometry::calcSquaredDistancePointToRay(Vector2f* point, Ray2f* ray, f32* closestRayPos) +{ + Vector2f diff = *point - ray->getPos(); + + f32 numerator = diff.dot(ray->getDir()); + f32 squaredLength = diff.squaredLength(); + + if (numerator < 0.0f) + { + numerator = 0.0f; + squaredLength = diff.squaredLength(); + } + if (closestRayPos != nullptr) + { + *closestRayPos = numerator; + } + return squaredLength; +} + +} // namespace sead