diff --git a/asm/MetroidPrime/Cameras/CCameraFilter.s b/asm/MetroidPrime/Cameras/CCameraFilter.s index 500ff03f..5bcd391d 100644 --- a/asm/MetroidPrime/Cameras/CCameraFilter.s +++ b/asm/MetroidPrime/Cameras/CCameraFilter.s @@ -1805,19 +1805,16 @@ DrawFilterShape__17CCameraFilterPassFQ217CCameraFilterPass12EFilterShapeRC6CColo /* 800EC094 000E8FF4 7C 03 00 2E */ lwzx r0, r3, r0 /* 800EC098 000E8FF8 7C 09 03 A6 */ mtctr r0 /* 800EC09C 000E8FFC 4E 80 04 20 */ bctr -.global lbl_800EC0A0 lbl_800EC0A0: /* 800EC0A0 000E9000 7C 83 23 78 */ mr r3, r4 /* 800EC0A4 000E9004 38 80 00 01 */ li r4, 1 /* 800EC0A8 000E9008 48 00 09 4D */ bl DrawScanLines__17CCameraFilterPassFRC6CColorb /* 800EC0AC 000E900C 48 00 00 8C */ b lbl_800EC138 -.global lbl_800EC0B0 lbl_800EC0B0: /* 800EC0B0 000E9010 7C 83 23 78 */ mr r3, r4 /* 800EC0B4 000E9014 38 80 00 00 */ li r4, 0 /* 800EC0B8 000E9018 48 00 09 3D */ bl DrawScanLines__17CCameraFilterPassFRC6CColorb /* 800EC0BC 000E901C 48 00 00 7C */ b lbl_800EC138 -.global lbl_800EC0C0 lbl_800EC0C0: /* 800EC0C0 000E9020 28 05 00 00 */ cmplwi r5, 0 /* 800EC0C4 000E9024 41 82 00 14 */ beq lbl_800EC0D8 @@ -1829,7 +1826,6 @@ lbl_800EC0D8: /* 800EC0D8 000E9038 7C 83 23 78 */ mr r3, r4 /* 800EC0DC 000E903C 48 00 0F 85 */ bl DrawFullScreenColoredQuad__17CCameraFilterPassFRC6CColor /* 800EC0E0 000E9040 48 00 00 58 */ b lbl_800EC138 -.global lbl_800EC0E4 lbl_800EC0E4: /* 800EC0E4 000E9044 28 05 00 00 */ cmplwi r5, 0 /* 800EC0E8 000E9048 41 82 00 14 */ beq lbl_800EC0FC @@ -1841,20 +1837,17 @@ lbl_800EC0FC: /* 800EC0FC 000E905C 7C 83 23 78 */ mr r3, r4 /* 800EC100 000E9060 48 00 0F 61 */ bl DrawFullScreenColoredQuad__17CCameraFilterPassFRC6CColor /* 800EC104 000E9064 48 00 00 34 */ b lbl_800EC138 -.global lbl_800EC108 lbl_800EC108: /* 800EC108 000E9068 7C 83 23 78 */ mr r3, r4 /* 800EC10C 000E906C 7C A4 2B 78 */ mr r4, r5 /* 800EC110 000E9070 48 00 05 11 */ bl DrawWideScreen__17CCameraFilterPassFRC6CColorPC8CTexturef /* 800EC114 000E9074 48 00 00 24 */ b lbl_800EC138 -.global lbl_800EC118 lbl_800EC118: /* 800EC118 000E9078 C0 22 90 DC */ lfs f1, lbl_805AADFC@sda21(r2) /* 800EC11C 000E907C 7C 83 23 78 */ mr r3, r4 /* 800EC120 000E9080 38 80 00 00 */ li r4, 0 /* 800EC124 000E9084 48 00 01 CD */ bl DrawRandomStatic__17CCameraFilterPassFRC6CColorfb /* 800EC128 000E9088 48 00 00 10 */ b lbl_800EC138 -.global lbl_800EC12C lbl_800EC12C: /* 800EC12C 000E908C 7C 83 23 78 */ mr r3, r4 /* 800EC130 000E9090 38 80 00 01 */ li r4, 1 @@ -1888,10 +1881,8 @@ DrawFilter__17CCameraFilterPassFQ217CCameraFilterPass11EFilterTypeQ217CCameraFil /* 800EC190 000E90F0 7C 03 00 2E */ lwzx r0, r3, r0 /* 800EC194 000E90F4 7C 09 03 A6 */ mtctr r0 /* 800EC198 000E90F8 4E 80 04 20 */ bctr -.global lbl_800EC19C lbl_800EC19C: /* 800EC19C 000E90FC 48 00 00 D4 */ b lbl_800EC270 -.global lbl_800EC1A0 lbl_800EC1A0: /* 800EC1A0 000E9100 80 6D A0 68 */ lwz r3, gpRender@sda21(r13) /* 800EC1A4 000E9104 81 83 00 00 */ lwz r12, 0(r3) @@ -1899,7 +1890,6 @@ lbl_800EC1A0: /* 800EC1AC 000E910C 7D 89 03 A6 */ mtctr r12 /* 800EC1B0 000E9110 4E 80 04 21 */ bctrl /* 800EC1B4 000E9114 48 00 00 94 */ b lbl_800EC248 -.global lbl_800EC1B8 lbl_800EC1B8: /* 800EC1B8 000E9118 80 6D A0 68 */ lwz r3, gpRender@sda21(r13) /* 800EC1BC 000E911C 81 83 00 00 */ lwz r12, 0(r3) @@ -1907,7 +1897,6 @@ lbl_800EC1B8: /* 800EC1C4 000E9124 7D 89 03 A6 */ mtctr r12 /* 800EC1C8 000E9128 4E 80 04 21 */ bctrl /* 800EC1CC 000E912C 48 00 00 7C */ b lbl_800EC248 -.global lbl_800EC1D0 lbl_800EC1D0: /* 800EC1D0 000E9130 80 6D A0 68 */ lwz r3, gpRender@sda21(r13) /* 800EC1D4 000E9134 81 83 00 00 */ lwz r12, 0(r3) @@ -1915,7 +1904,6 @@ lbl_800EC1D0: /* 800EC1DC 000E913C 7D 89 03 A6 */ mtctr r12 /* 800EC1E0 000E9140 4E 80 04 21 */ bctrl /* 800EC1E4 000E9144 48 00 00 64 */ b lbl_800EC248 -.global lbl_800EC1E8 lbl_800EC1E8: /* 800EC1E8 000E9148 80 6D A0 68 */ lwz r3, gpRender@sda21(r13) /* 800EC1EC 000E914C 81 83 00 00 */ lwz r12, 0(r3) @@ -1923,7 +1911,6 @@ lbl_800EC1E8: /* 800EC1F4 000E9154 7D 89 03 A6 */ mtctr r12 /* 800EC1F8 000E9158 4E 80 04 21 */ bctrl /* 800EC1FC 000E915C 48 00 00 4C */ b lbl_800EC248 -.global lbl_800EC200 lbl_800EC200: /* 800EC200 000E9160 38 60 00 03 */ li r3, 3 /* 800EC204 000E9164 38 80 00 01 */ li r4, 1 @@ -1931,10 +1918,8 @@ lbl_800EC200: /* 800EC20C 000E916C 38 C0 00 00 */ li r6, 0 /* 800EC210 000E9170 48 21 C6 C1 */ bl SetBlendMode__3CGXF12_GXBlendMode14_GXBlendFactor14_GXBlendFactor10_GXLogicOp /* 800EC214 000E9174 48 00 00 34 */ b lbl_800EC248 -.global lbl_800EC218 lbl_800EC218: /* 800EC218 000E9178 48 00 00 58 */ b lbl_800EC270 -.global lbl_800EC21C lbl_800EC21C: /* 800EC21C 000E917C 80 6D A0 68 */ lwz r3, gpRender@sda21(r13) /* 800EC220 000E9180 81 83 00 00 */ lwz r12, 0(r3) @@ -1942,7 +1927,6 @@ lbl_800EC21C: /* 800EC228 000E9188 7D 89 03 A6 */ mtctr r12 /* 800EC22C 000E918C 4E 80 04 21 */ bctrl /* 800EC230 000E9190 48 00 00 18 */ b lbl_800EC248 -.global lbl_800EC234 lbl_800EC234: /* 800EC234 000E9194 80 6D A0 68 */ lwz r3, gpRender@sda21(r13) /* 800EC238 000E9198 81 83 00 00 */ lwz r12, 0(r3) diff --git a/include/Kyoto/Graphics/CGraphics.hpp b/include/Kyoto/Graphics/CGraphics.hpp index 25dacbf6..b726d415 100644 --- a/include/Kyoto/Graphics/CGraphics.hpp +++ b/include/Kyoto/Graphics/CGraphics.hpp @@ -109,6 +109,13 @@ enum ERglEnum { kE_Always = GX_ALWAYS, }; +enum ERglCullMode { + kCM_None = GX_CULL_NONE, + kCM_Front = GX_CULL_FRONT, + kCM_Back = GX_CULL_BACK, + kCM_All = GX_CULL_ALL, +}; + class CTimeProvider; class CGraphics { @@ -122,6 +129,7 @@ public: static void StreamTexcoord(float u, float v); static void StreamVertex(float, float, float); static void StreamVertex(const CVector3f& vtx); + static void StreamVertex(const float*); static void StreamEnd(); static const CTransform4f& GetViewMatrix() { return mViewMatrix; } @@ -137,6 +145,7 @@ public: u8 ref1); static void SetDepthWriteMode(bool test, ERglEnum comp, bool write); static void SetBlendMode(ERglBlendMode, ERglBlendFactor, ERglBlendFactor, ERglLogicOp); + static void SetCullMode(ERglCullMode); // Screen Position static void sub_80309564(uint* stretch, uint* xOffset, uint* yOffset); diff --git a/include/Kyoto/Math/CVector2f.hpp b/include/Kyoto/Math/CVector2f.hpp index 96db5b31..be5ba66b 100644 --- a/include/Kyoto/Math/CVector2f.hpp +++ b/include/Kyoto/Math/CVector2f.hpp @@ -8,6 +8,7 @@ class CVector2f { public: CVector2f(float x, float y); + float GetX() const { return mX; } float GetY() const { return mY; } diff --git a/include/MetroidPrime/Cameras/CCameraFilterPass.hpp b/include/MetroidPrime/Cameras/CCameraFilterPass.hpp index 88673b4a..01ec1488 100644 --- a/include/MetroidPrime/Cameras/CCameraFilterPass.hpp +++ b/include/MetroidPrime/Cameras/CCameraFilterPass.hpp @@ -38,12 +38,20 @@ public: kFS_CookieCutterDepthRandomStatic }; + CCameraFilterPass(); + void SetFilter(EFilterType type, EFilterShape shape, float time, const CColor& color, CAssetId txtr); void DisableFilter(float time); + void Update(float dt); static void DrawWideScreen(const CColor& color, const CTexture* tex, float v); - static void DrawFilter(EFilterType type, EFilterShape shape, const CColor& color, const CTexture* tex, float lod); + static void DrawFilter(EFilterType type, EFilterShape shape, const CColor& color, + const CTexture* tex, float lod); + static void DrawFullScreenColoredQuad(const CColor& color); + static void DrawFullScreenTexturedQuad(const CColor& color, const CTexture* tex, float lod); + static void DrawFullScreenTexturedQuadQuarters(const CColor& color, const CTexture* tex, + float lod); private: EFilterType x0_curType; diff --git a/src/MetroidPrime/Cameras/CCameraFilter.cpp b/src/MetroidPrime/Cameras/CCameraFilter.cpp index 15f6d85e..a8f1917d 100644 --- a/src/MetroidPrime/Cameras/CCameraFilter.cpp +++ b/src/MetroidPrime/Cameras/CCameraFilter.cpp @@ -1,10 +1,180 @@ -#include "Kyoto/Graphics/CGraphics.hpp" -#include "Kyoto/Graphics/CTexture.hpp" -#include "MetaRender/CCubeRenderer.hpp" #include "MetroidPrime/Cameras/CCameraFilterPass.hpp" +#include "Kyoto/Graphics/CGraphics.hpp" +#include "Kyoto/Graphics/CTexture.hpp" + +#include "MetaRender/CCubeRenderer.hpp" + +#include "rstl/math.hpp" + #include "stdlib.h" +static const CColor& skIdentityColorMultiply = CColor::White(); + +CCameraFilterPass::CCameraFilterPass() +: x0_curType(kFT_Passthru) +, x4_nextType(kFT_Passthru) +, x8_shape(kFS_Fullscreen) +, xc_duration(0.f) +, x10_remTime(0.f) +, x14_prevColor(0xFFFFFFFF) +, x18_curColor(0xFFFFFFFF) +, x1c_nextColor(0xFFFFFFFF) +, x20_nextTxtr(kInvalidAssetId) {} + +void CCameraFilterPass::SetFilter(EFilterType type, EFilterShape shape, float time, + const CColor& color, CAssetId txtr) { + if (time == 0.f) { + xc_duration = 0.f; + x10_remTime = 0.f; + x8_shape = shape; + x4_nextType = type; + x0_curType = type; + x1c_nextColor = color; + x18_curColor = color; + x14_prevColor = color; + x20_nextTxtr = txtr; + + if (txtr != kInvalidAssetId) { + x24_texObj = + new TLockedToken< CTexture >(gpSimplePool->GetObj(SObjectTag(SBig('TXTR'), txtr))); + } + } else { + x1c_nextColor = color; + x14_prevColor = x18_curColor; + x8_shape = shape; + x20_nextTxtr = txtr; + + if (txtr != kInvalidAssetId) { + x24_texObj = + new TLockedToken< CTexture >(gpSimplePool->GetObj(SObjectTag(SBig('TXTR'), txtr))); + } + + x10_remTime = time; + xc_duration = time; + x0_curType = x4_nextType; + x4_nextType = type; + + if (type == kFT_Passthru) { + if (x0_curType == kFT_Multiply) { + x1c_nextColor = skIdentityColorMultiply; + } else if (x0_curType == kFT_Add || x0_curType == kFT_Blend) { + x1c_nextColor = + CColor(x1c_nextColor.GetRed(), x1c_nextColor.GetGreen(), x1c_nextColor.GetBlue(), 0.f); + } + } else { + if (x0_curType == kFT_Passthru) { + if (type == kFT_Multiply) { + x18_curColor = skIdentityColorMultiply; + } else if (type == kFT_Add || type == kFT_Blend) { + x18_curColor = CColor(x1c_nextColor.GetRed(), x1c_nextColor.GetGreen(), + x1c_nextColor.GetBlue(), 0.f); + x14_prevColor = x18_curColor; + } + } + x0_curType = x4_nextType; + } + } +} + +void CCameraFilterPass::DisableFilter(float time) { + SetFilter(kFT_Passthru, x8_shape, time, 0xFFFFFFFF, kInvalidAssetId); +} + +void CCameraFilterPass::Update(float dt) { + if (x10_remTime > 0.f) { + EFilterType origType = x0_curType; + + x10_remTime = rstl::max_val(0.f, x10_remTime - dt); + x18_curColor = CColor::Lerp(x1c_nextColor, x14_prevColor, x10_remTime / xc_duration); + + if (x10_remTime == 0.f) { + x0_curType = x4_nextType; + if (x0_curType == kFT_Passthru) { + x24_texObj = nullptr; + x20_nextTxtr = kInvalidAssetId; + } + } + } +} + +void CCameraFilterPass::DrawFullScreenColoredQuad(const CColor& color) { + rstl::pair< CVector2f, CVector2f > vp = gpRender->SetViewportOrtho(true, -4096.f, 4096.f); + float left = vp.first.GetX(); + float top = vp.first.GetY(); + float right = vp.second.GetX(); + float bottom = vp.second.GetY(); + gpRender->SetDepthReadWrite(false, false); + gpRender->BeginTriangleStrip(4); + gpRender->PrimColor(color); + gpRender->PrimVertex(CVector3f(left - 1.f, 0.f, bottom + 1.f)); + gpRender->PrimVertex(CVector3f(left - 1.f, 0.f, top - 1.f)); + gpRender->PrimVertex(CVector3f(right + 1.f, 0.f, bottom + 1.f)); + gpRender->PrimVertex(CVector3f(right + 1.f, 0.f, top - 1.f)); + gpRender->EndPrimitive(); +} + +void CCameraFilterPass::DrawFullScreenTexturedQuad(const CColor& color, const CTexture* tex, + float lod) { + const float u = 0.5f - 0.5f * lod; + const float v = 0.5f + 0.5f * lod; + rstl::pair< CVector2f, CVector2f > vp = gpRender->SetViewportOrtho(true, -4096.f, 4096.f); + float left = vp.first.GetX(); + float top = vp.first.GetY(); + float right = vp.second.GetX(); + float bottom = vp.second.GetY(); + gpRender->SetDepthReadWrite(false, false); + if (tex != nullptr) { + tex->Load(GX_TEXMAP0, CTexture::kCM_Repeat); + } + CGraphics::SetTevOp(kTS_Stage0, CGraphics::kEnvModulate); + CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassthru); + CGraphics::StreamBegin(kP_TriangleStrip); + CGraphics::StreamColor(color); + CGraphics::StreamTexcoord(u, v); + CGraphics::StreamVertex(CVector3f(left - 1.f, 0.f, 1.f + bottom)); + CGraphics::StreamTexcoord(u, u); + CGraphics::StreamVertex(CVector3f(left - 1.f, 0.f, top - 1.f)); + CGraphics::StreamTexcoord(v, v); + CGraphics::StreamVertex(CVector3f(1.f + right, 0.f, 1.f + bottom)); + CGraphics::StreamTexcoord(v, u); + CGraphics::StreamVertex(CVector3f(1.f + right, 0.f, top - 1.f)); + CGraphics::StreamEnd(); +} + +void CCameraFilterPass::DrawFullScreenTexturedQuadQuarters(const CColor& color, const CTexture* tex, + float lod) { + rstl::pair< CVector2f, CVector2f > vp = gpRender->SetViewportOrtho(true, -4096.f, 4096.f); + float left = vp.first.GetX(); + float top = vp.first.GetY(); + float right = vp.second.GetX(); + float bottom = vp.second.GetY(); + CGraphics::SetTevOp(kTS_Stage0, CGraphics::kEnvModulate); + CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassthru); + gpRender->SetDepthReadWrite(false, false); + if (tex != nullptr) { + tex->Load(GX_TEXMAP0, CTexture::kCM_Repeat); + } + CGraphics::SetCullMode(kCM_None); + for (int i = 0; i < 4; ++i) { + float x = (i & 1) > 0 ? 1.f : -1.f; + float z = (i & 2) > 0 ? 1.f : -1.f; + gpRender->SetModelMatrix(CTransform4f::Scale(x, 0.f, z)); + CGraphics::StreamBegin(kP_TriangleStrip); + CGraphics::StreamColor(color); + CGraphics::StreamTexcoord(lod, lod); + CGraphics::StreamVertex(CVector3f(left, 0.f, bottom)); + CGraphics::StreamTexcoord(lod, 0.f); + CGraphics::StreamVertex(CVector3f(left, 0.f, 0.f)); + CGraphics::StreamTexcoord(0.f, lod); + CGraphics::StreamVertex(CVector3f(0.f, 0.f, bottom)); + CGraphics::StreamTexcoord(0.f, 0.f); + CGraphics::StreamVertex(CVector3f(0.f, 0.f, 0.f)); + CGraphics::StreamEnd(); + } + CGraphics::SetCullMode(kCM_Front); +} + // FIXME non-matching https://decomp.me/scratch/8N81d void CCameraFilterPass::DrawWideScreen(const CColor& color, const CTexture* tex, float lod) { const rstl::pair< CVector2f, CVector2f > vp = gpRender->SetViewportOrtho(true, -4096.f, 4096.f);