diff --git a/asm/Kyoto/Graphics/DolphinCTexture.s b/asm/Kyoto/Graphics/DolphinCTexture.s index 047b33fb..6ca9582b 100644 --- a/asm/Kyoto/Graphics/DolphinCTexture.s +++ b/asm/Kyoto/Graphics/DolphinCTexture.s @@ -54,8 +54,8 @@ lbl_805A9438: .section .text, "ax" -.global sub_8030e10c -sub_8030e10c: +.global sub_8030e10c__8CTextureFv +sub_8030e10c__8CTextureFv: /* 8030E10C 0030B06C 94 21 FF F0 */ stwu r1, -0x10(r1) /* 8030E110 0030B070 7C 08 02 A6 */ mflr r0 /* 8030E114 0030B074 90 01 00 14 */ stw r0, 0x14(r1) diff --git a/asm/MetaRender/CCubeRenderer.s b/asm/MetaRender/CCubeRenderer.s index 02b8f1d5..25da3bd2 100644 --- a/asm/MetaRender/CCubeRenderer.s +++ b/asm/MetaRender/CCubeRenderer.s @@ -9161,7 +9161,7 @@ BeginScene__13CCubeRendererFv: /* 802BDD6C 002BACCC 2C 00 00 00 */ cmpwi r0, 0 /* 802BDD70 002BACD0 40 82 00 20 */ bne lbl_802BDD90 /* 802BDD74 002BACD4 80 7F 03 14 */ lwz r3, 0x314(r31) -/* 802BDD78 002BACD8 48 05 03 95 */ bl sub_8030e10c +/* 802BDD78 002BACD8 48 05 03 95 */ bl sub_8030e10c__8CTextureFv /* 802BDD7C 002BACDC 80 7F 03 14 */ lwz r3, 0x314(r31) /* 802BDD80 002BACE0 38 80 00 01 */ li r4, 1 /* 802BDD84 002BACE4 48 05 1C 75 */ bl __dt__8CTextureFv @@ -9854,7 +9854,7 @@ __dt__13CCubeRendererFv: /* 802BE6DC 002BB63C 80 7E 03 14 */ lwz r3, 0x314(r30) /* 802BE6E0 002BB640 28 03 00 00 */ cmplwi r3, 0 /* 802BE6E4 002BB644 41 82 00 08 */ beq lbl_802BE6EC -/* 802BE6E8 002BB648 48 04 FA 25 */ bl sub_8030e10c +/* 802BE6E8 002BB648 48 04 FA 25 */ bl sub_8030e10c__8CTextureFv lbl_802BE6EC: /* 802BE6EC 002BB64C 34 1E 03 14 */ addic. r0, r30, 0x314 /* 802BE6F0 002BB650 41 82 00 10 */ beq lbl_802BE700 diff --git a/asm/MetroidPrime/CProjectedShadow.s b/asm/MetroidPrime/CProjectedShadow.s index 45bc8fe8..f6847ab5 100644 --- a/asm/MetroidPrime/CProjectedShadow.s +++ b/asm/MetroidPrime/CProjectedShadow.s @@ -876,7 +876,7 @@ __dt__16CProjectedShadowFv: /* 8029E394 0029B2F4 93 C1 00 08 */ stw r30, 8(r1) /* 8029E398 0029B2F8 7C 7E 1B 79 */ or. r30, r3, r3 /* 8029E39C 0029B2FC 41 82 00 24 */ beq lbl_8029E3C0 -/* 8029E3A0 0029B300 48 06 FD 6D */ bl sub_8030e10c +/* 8029E3A0 0029B300 48 06 FD 6D */ bl sub_8030e10c__8CTextureFv /* 8029E3A4 0029B304 7F C3 F3 78 */ mr r3, r30 /* 8029E3A8 0029B308 38 80 FF FF */ li r4, -1 /* 8029E3AC 0029B30C 48 07 16 4D */ bl __dt__8CTextureFv diff --git a/asm/MetroidPrime/CWorldShadow.s b/asm/MetroidPrime/CWorldShadow.s index 92e18918..4c82b9e0 100644 --- a/asm/MetroidPrime/CWorldShadow.s +++ b/asm/MetroidPrime/CWorldShadow.s @@ -908,7 +908,7 @@ __dt__12CWorldShadowFv: /* 80111B74 0010EAD4 80 7E 00 00 */ lwz r3, 0(r30) /* 80111B78 0010EAD8 28 03 00 00 */ cmplwi r3, 0 /* 80111B7C 0010EADC 41 82 00 08 */ beq lbl_80111B84 -/* 80111B80 0010EAE0 48 1F C5 8D */ bl sub_8030e10c +/* 80111B80 0010EAE0 48 1F C5 8D */ bl sub_8030e10c__8CTextureFv lbl_80111B84: /* 80111B84 0010EAE4 28 1E 00 00 */ cmplwi r30, 0 /* 80111B88 0010EAE8 41 82 00 10 */ beq lbl_80111B98 @@ -1007,4 +1007,3 @@ lbl_803CF1F8: # ROM: 0x3CC1F8 .asciz "??(??)" .balign 4 - diff --git a/asm/MetroidPrime/Player/CMorphBallShadow.s b/asm/MetroidPrime/Player/CMorphBallShadow.s index 5d65b274..c9089539 100644 --- a/asm/MetroidPrime/Player/CMorphBallShadow.s +++ b/asm/MetroidPrime/Player/CMorphBallShadow.s @@ -1049,7 +1049,7 @@ __dt__16CMorphBallShadowFv: /* 80296A7C 002939DC 7C 7E 1B 79 */ or. r30, r3, r3 /* 80296A80 002939E0 41 82 00 9C */ beq lbl_80296B1C /* 80296A84 002939E4 38 7E 00 40 */ addi r3, r30, 0x40 -/* 80296A88 002939E8 48 07 76 85 */ bl sub_8030e10c +/* 80296A88 002939E8 48 07 76 85 */ bl sub_8030e10c__8CTextureFv /* 80296A8C 002939EC 34 1E 00 A8 */ addic. r0, r30, 0xa8 /* 80296A90 002939F0 41 82 00 10 */ beq lbl_80296AA0 /* 80296A94 002939F4 38 7E 00 A8 */ addi r3, r30, 0xa8 diff --git a/configure.py b/configure.py index 43ea5e02..6f3eeb7e 100755 --- a/configure.py +++ b/configure.py @@ -138,7 +138,7 @@ LIBS = [ ["MetroidPrime/CActorParameters", False], "MetroidPrime/CInGameGuiManager", "MetroidPrime/Enemies/CWarWasp", - "MetroidPrime/CWorldShadow", + ["MetroidPrime/CWorldShadow", False], ["MetroidPrime/CAudioStateWin", True], "MetroidPrime/Player/CPlayerVisor", "MetroidPrime/CModelData", diff --git a/include/Kyoto/Graphics/CCubeModel.hpp b/include/Kyoto/Graphics/CCubeModel.hpp index fd8ae1b8..67adf34d 100644 --- a/include/Kyoto/Graphics/CCubeModel.hpp +++ b/include/Kyoto/Graphics/CCubeModel.hpp @@ -1,9 +1,15 @@ #ifndef _CCUBEMODEL #define _CCUBEMODEL +class CTexture; +class CTransform4f; + class CCubeModel { public: static void SetRenderModelBlack(bool v); + static void DisableShadowMaps(); + static void EnableShadowMaps(const CTexture*, const CTransform4f&, unsigned char, unsigned char); + static void SetDrawingOccluders(bool); }; #endif // _CCUBEMODEL diff --git a/include/Kyoto/Graphics/CGraphics.hpp b/include/Kyoto/Graphics/CGraphics.hpp index f65a767a..10434db0 100644 --- a/include/Kyoto/Graphics/CGraphics.hpp +++ b/include/Kyoto/Graphics/CGraphics.hpp @@ -161,6 +161,7 @@ struct CViewport { class COsContext; class CTexture; class CTimeProvider; +class CTexture; // TODO typedef struct { @@ -234,6 +235,9 @@ public: static void SetDefaultVtxAttrFmt(); static CMatrix4f GetPerspectiveProjectionMatrix(); static CMatrix4f CalculatePerspectiveMatrix(float fovy, float aspect, float znear, float zfar); + + static float GetDepthNear() { return mDepthNear; } + static float GetDepthFar() { return mDepthFar; } static bool IsBeginSceneClearFb(); static void SetIsBeginSceneClearFb(bool); @@ -243,6 +247,7 @@ public: static void SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass); static void StreamBegin(ERglPrimitive primitive); static void StreamColor(uint color); + static void StreamColor(float, float, float, float); static void StreamColor(const CColor& color); static void StreamTexcoord(float u, float v); static void StreamVertex(float, float, float); @@ -284,6 +289,9 @@ public: static void sub_80309564(uint* stretch, uint* xOffset, uint* yOffset); static void sub_803094b0(uint stretch, uint xOffset, uint yOffset); + // Render + static void Render2D(const CTexture& tex, int x, int y, int w, int h, const CColor& col); + static CTevCombiners::CTevPass& kEnvPassthru; static CTevCombiners::CTevPass kEnvModulateConstColor; static CTevCombiners::CTevPass kEnvConstColor; diff --git a/include/Kyoto/Graphics/CTexture.hpp b/include/Kyoto/Graphics/CTexture.hpp index 06169072..5ec9ddf8 100644 --- a/include/Kyoto/Graphics/CTexture.hpp +++ b/include/Kyoto/Graphics/CTexture.hpp @@ -7,6 +7,21 @@ class CInputStream; +enum ETexelFormat { + kTF_Invalid = -1, + kTF_I4 = 0, + kTF_I8 = 1, + kTF_IA4 = 2, + kTF_IA8 = 3, + kTF_C4 = 4, + kTF_C8 = 5, + kTF_C14X2 = 6, + kTF_RGB565 = 7, + kTF_RGB5A3 = 8, + kTF_RGBA8 = 9, + kTF_CMPR = 10, +}; + class CTexture { public: enum EClampMode { @@ -21,20 +36,35 @@ public: kBK_Zero, }; + CTexture(ETexelFormat fmt, short w, short h, int mips); CTexture(CInputStream& stream, EAutoMipmap mip, EBlackKey bk); + ~CTexture(); + + // Used in certain destructors + void sub_8030e10c(); void Load(GXTexMapID texMapId, EClampMode clampMode) const; + void UnLock(); + + void* GetBitMapData(int); static void InvalidateTexmap(GXTexMapID id); + uint GetTexelFormat() const { return mTexelFormat; } short GetWidth() const { return mWidth; } short GetHeight() const { return mHeight; } + + void SetFlag1(bool b) { mFlag1 = b; } private: uint mTexelFormat; // TODO: Enum short mWidth; short mHeight; - uchar pad[0x60]; + uchar mNumMips; + uchar mBitsPerPixel; + uchar mFlag1 : 1; + uchar pad[0x57]; }; +// CHECK_SIZEOF(CTexture, ) #endif // _CTEXTURE diff --git a/include/Kyoto/Math/CFrustumPlanes.hpp b/include/Kyoto/Math/CFrustumPlanes.hpp index c8e1708e..f65a57d9 100644 --- a/include/Kyoto/Math/CFrustumPlanes.hpp +++ b/include/Kyoto/Math/CFrustumPlanes.hpp @@ -20,6 +20,7 @@ public: float z; float d; }; + CFrustumPlanes(const CTransform4f&, float, float, float, bool, float); bool BoxInFrustumPlanes(const CAABox& box) const; bool BoxInFrustumPlanes(const rstl::optional_object< CAABox >& box) const; diff --git a/include/Kyoto/PVS/CPVSVisSet.hpp b/include/Kyoto/PVS/CPVSVisSet.hpp new file mode 100644 index 00000000..26695a1d --- /dev/null +++ b/include/Kyoto/PVS/CPVSVisSet.hpp @@ -0,0 +1,17 @@ +#ifndef _CPVSVISSET +#define _CPVSVISSET + +#include "rstl/auto_ptr.hpp" + +class CPVSVisSet { +public: + static CPVSVisSet Reset(int); + +private: + int x0_state; + uint x4_numBits; + uint x8_numLights; + rstl::auto_ptr< u8 > x10_ptr; +}; + +#endif // _CPVSVISSET diff --git a/include/MetaRender/CCubeRenderer.hpp b/include/MetaRender/CCubeRenderer.hpp index 373dbe5f..34b9c5f3 100644 --- a/include/MetaRender/CCubeRenderer.hpp +++ b/include/MetaRender/CCubeRenderer.hpp @@ -25,13 +25,13 @@ public: ~CCubeRenderer() override; // TODO types void AddStaticGeometry() override; - void EnablePVS() override; + void EnablePVS(const CPVSVisSet& set, int areaIdx) override; void DisablePVS() override; void RemoveStaticGeometry() override; - void DrawUnsortedGeometry() override; - void DrawSortedGeometry() override; - void DrawStaticGeometry() override; - void DrawAreaGeometry() override; + void DrawUnsortedGeometry(int areaIdx, int mask, int targetMask) override; + void DrawSortedGeometry(int areaIdx, int mask, int targetMask) override; + void DrawStaticGeometry(int areaIdx, int mask, int targetMask) override; + void DrawAreaGeometry(int areaIdx, int mask, int targetMask) override; void PostRenderFogs() override; void SetModelMatrix(const CTransform4f& xf) override; void AddParticleGen(const CParticleGen& gen) override; @@ -45,8 +45,8 @@ public: void SetPerspective2() override; rstl::pair< CVector2f, CVector2f > SetViewportOrtho(bool centered, float znear, float zfar) override; - void SetClippingPlanes() override; - void SetViewport() override; + void SetClippingPlanes(const CFrustumPlanes&) override; + void SetViewport(int left, int right, int width, int height) override; void SetDepthReadWrite(bool read, bool update) override; void SetBlendMode_AdditiveAlpha() override; void SetBlendMode_AlphaBlended() override; @@ -90,7 +90,7 @@ public: void SetGXRegister1Color() override; void SetWorldLightFadeLevel() override; void Something() override; - void PrepareDynamicLights() override; + void PrepareDynamicLights(const rstl::vector& lights) override; void AllocatePhazonSuitMaskTexture(); diff --git a/include/MetaRender/IRenderer.hpp b/include/MetaRender/IRenderer.hpp index 183c6594..94a8275a 100644 --- a/include/MetaRender/IRenderer.hpp +++ b/include/MetaRender/IRenderer.hpp @@ -3,6 +3,7 @@ #include "types.h" #include "rstl/pair.hpp" +#include "rstl/vector.hpp" #include "Kyoto/TToken.hpp" @@ -16,8 +17,11 @@ class CAABox; class CVector2f; class CVector3f; class CModel; +class CFrustumPlanes; class CSkinnedModel; class CColor; +class CLight; +class CPVSVisSet; class IRenderer { public: @@ -32,13 +36,13 @@ public: // TODO vtable virtual void AddStaticGeometry(); - virtual void EnablePVS(); + virtual void EnablePVS(const CPVSVisSet& set, int areaIdx); virtual void DisablePVS(); virtual void RemoveStaticGeometry(); - virtual void DrawUnsortedGeometry(); - virtual void DrawSortedGeometry(); - virtual void DrawStaticGeometry(); - virtual void DrawAreaGeometry(); + virtual void DrawUnsortedGeometry(int areaIdx, int mask, int targetMask); + virtual void DrawSortedGeometry(int areaIdx, int mask, int targetMask); + virtual void DrawStaticGeometry(int areaIdx, int mask, int targetMask); + virtual void DrawAreaGeometry(int areaIdx, int mask, int targetMask); virtual void PostRenderFogs(); virtual void SetModelMatrix(const CTransform4f& xf); virtual void AddParticleGen(const CParticleGen& gen); @@ -52,8 +56,8 @@ public: virtual void SetPerspective2(); virtual rstl::pair< CVector2f, CVector2f > SetViewportOrtho(bool centered, float znear, float zfar); - virtual void SetClippingPlanes(); - virtual void SetViewport(); + virtual void SetClippingPlanes(const CFrustumPlanes&); + virtual void SetViewport(int left, int right, int width, int height); virtual void SetDepthReadWrite(bool read, bool update); virtual void SetBlendMode_AdditiveAlpha(); virtual void SetBlendMode_AlphaBlended(); @@ -98,7 +102,7 @@ public: virtual void SetGXRegister1Color(); virtual void SetWorldLightFadeLevel(); virtual void Something(); - virtual void PrepareDynamicLights(); + virtual void PrepareDynamicLights(const rstl::vector& lights); }; namespace Renderer { diff --git a/include/MetroidPrime/CGameArea.hpp b/include/MetroidPrime/CGameArea.hpp index 168a0561..07f45d5b 100644 --- a/include/MetroidPrime/CGameArea.hpp +++ b/include/MetroidPrime/CGameArea.hpp @@ -47,6 +47,7 @@ class CToken; class IDvdRequest; class CScriptAreaAttributes; class CWorldLight; +class CPVSAreaSet; class CGameArea : public IGameArea { public: @@ -150,9 +151,11 @@ public: enum EOcclusionState { kOS_Occluded, kOS_Visible }; struct CPostConstructed { - uchar x0_pad[0x10c4]; + uchar x0_pad[0xa0]; + CPVSAreaSet* xa0_pvs; + uchar xa4_pad[0x1020]; rstl::single_ptr< CAreaFog > x10c4_areaFog; - rstl::optional_object< void* > x10c8_sclyBuf; // was rstl::optional_object + rstl::optional_object< void* > x10c8_sclyBuf; u32 x10d0_sclySize; const u8* x10d4_firstMatPtr; const CScriptAreaAttributes* x10d8_areaAttributes; @@ -165,6 +168,7 @@ public: EOcclusionState GetOcclusionState() const { return x12c_postConstructed->x10dc_occlusionState; } const rstl::vector& GetLightsA() const; const rstl::vector& GetLightsB() const; + const CPVSAreaSet* GetAreaVisSet() const { return x12c_postConstructed->xa0_pvs; } private: uchar x110_pad[0x1c]; diff --git a/include/MetroidPrime/CWorldShadow.hpp b/include/MetroidPrime/CWorldShadow.hpp index 3bbe5f52..caadff12 100644 --- a/include/MetroidPrime/CWorldShadow.hpp +++ b/include/MetroidPrime/CWorldShadow.hpp @@ -9,6 +9,8 @@ #include "rstl/single_ptr.hpp" class CTexture; +class CStateManager; +class CAABox; class CWorldShadow { rstl::single_ptr< CTexture > x0_texture; @@ -25,8 +27,8 @@ public: CWorldShadow(uint w, uint h, bool rgba8); ~CWorldShadow(); - void EnableModelProjectedShadow(const CTransform4f& pos, uint lightIdx, float f1); - void DisableModelProjectedShadow(); + void EnableModelProjectedShadow(const CTransform4f& pos, uint lightIdx, float f1) const; + void DisableModelProjectedShadow() const; void BuildLightShadowTexture(const CStateManager& mgr, TAreaId aid, uint lightIdx, const CAABox& aabb, bool motionBlur, bool lighten); void ResetBlur(); diff --git a/include/WorldFormat/CPVSAreaSet.hpp b/include/WorldFormat/CPVSAreaSet.hpp new file mode 100644 index 00000000..f023a103 --- /dev/null +++ b/include/WorldFormat/CPVSAreaSet.hpp @@ -0,0 +1,11 @@ +#ifndef _CPVSAREASET +#define _CPVSAREASET + +class CPVSVisSet; + +class CPVSAreaSet { +public: + CPVSVisSet GetLightSet(int) const; +}; + +#endif // _CPVSAREASET diff --git a/include/WorldFormat/CWorldLight.hpp b/include/WorldFormat/CWorldLight.hpp index 964b5d7c..98e30348 100644 --- a/include/WorldFormat/CWorldLight.hpp +++ b/include/WorldFormat/CWorldLight.hpp @@ -24,6 +24,8 @@ public: CLight GetAsCGraphicsLight() const; + const CVector3f& GetPosition() const { return x10_position; } + public: EWorldLightType x0_type; CVector3f x4_color; diff --git a/src/MetroidPrime/CWorldShadow.cpp b/src/MetroidPrime/CWorldShadow.cpp new file mode 100644 index 00000000..76359595 --- /dev/null +++ b/src/MetroidPrime/CWorldShadow.cpp @@ -0,0 +1,185 @@ +#include "MetroidPrime/CWorldShadow.hpp" + +#include "MetroidPrime/CGameArea.hpp" +#include "MetroidPrime/CStateManager.hpp" +#include "MetroidPrime/CWorld.hpp" +#include "WorldFormat/CPVSAreaSet.hpp" +#include "WorldFormat/CWorldLight.hpp" + +#include "Kyoto/Alloc/CMemory.hpp" +#include "Kyoto/Graphics/CCubeModel.hpp" +#include "Kyoto/Graphics/CTexture.hpp" +#include "Kyoto/Math/CMath.hpp" +#include "Kyoto/PVS/CPVSVisSet.hpp" +#include "MetaRender/CCubeRenderer.hpp" + +static int kUnknownValue = 1; + +CWorldShadow::CWorldShadow(uint w, uint h, bool rgba8) +: x0_texture(NEW CTexture(rgba8 ? kTF_RGBA8 : kTF_RGB565, w, h, 1)) +, x4_view(CTransform4f::Identity()) +, x34_model(CTransform4f::Identity()) +, x64_objHalfExtent(1.f) +, x68_objPos(0.0f, 1.f, 0.0f) +, x74_lightPos(CVector3f::Zero()) +, x80_aid(kInvalidAreaId) +, x84_lightIdx(-1) +, x88_blurReset(true) + +{} + +CWorldShadow::~CWorldShadow() { + if (x0_texture.get()) + x0_texture->sub_8030e10c(); +} + +void CWorldShadow::BuildLightShadowTexture(const CStateManager& mgr, TAreaId aid, uint lightIdx, + const CAABox& aabb, bool motionBlur, bool lighten) { + if (x80_aid != aid || x84_lightIdx != lightIdx) { + x88_blurReset = true; + x80_aid = aid; + x84_lightIdx = lightIdx; + } + + if (aid != kInvalidAreaId) { + const CGameArea& area = mgr.GetWorld()->GetAreaAlways(aid); + if (area.IsLoaded()) { + const CWorldLight& light = area.GetLightsA()[lightIdx]; + CVector3f centerPoint = aabb.GetCenterPoint(); + const CPVSAreaSet* pvs = area.GetAreaVisSet(); + if (pvs && kUnknownValue == 1) { + CPVSVisSet lightSet = pvs->GetLightSet(lightIdx); + gpRender->EnablePVS(lightSet, aid.Value()); + } else { + gpRender->EnablePVS(CPVSVisSet::Reset(2), aid.Value()); + } + CVector3f lightToPoint = centerPoint - light.GetPosition(); + x64_objHalfExtent = (aabb.GetMaxPoint() - centerPoint).Magnitude(); + float distance = lightToPoint.Magnitude(); + float fov = CMath::Rad2Deg(atan2f(x64_objHalfExtent, distance)) * 2.f; + if (!(fov < 0.00001f)) { + lightToPoint.Normalize(); + x4_view = + CTransform4f::LookAt(light.GetPosition(), centerPoint, CVector3f(0.0f, 0.0f, -1.0f)); + x68_objPos = centerPoint; + x74_lightPos = light.GetPosition(); + CGraphics::SetViewPointMatrix(x4_view); + CFrustumPlanes frumtum( + x4_view, + fov * 0.01745329238474369, + 1.0f, + 0.1f, + true, + distance + x64_objHalfExtent + ); + gpRender->SetClippingPlanes(frumtum); + gpRender->SetPerspective1(fov, x0_texture->GetWidth(), x0_texture->GetHeight(), 0.1f, + 1000.f); + float backupDepthNear = CGraphics::GetDepthNear(); + float backupDepthFar = CGraphics::GetDepthFar(); + CGraphics::SetDepthRange(0.f, 1.0f); + int backupVpHeight = CGraphics::GetViewport().mHeight; + int backupVpWidth = CGraphics::GetViewport().mWidth; + int backupVpTop = CGraphics::GetViewport().mTop; + int backupVpLeft = CGraphics::GetViewport().mLeft; + gpRender->SetViewport(0, 0, x0_texture->GetWidth(), x0_texture->GetHeight()); + + float extent = 1.4142f * x64_objHalfExtent; + x34_model = + CTransform4f::LookAt(centerPoint - CVector3f(0.f, 0.f, 0.1f), light.GetPosition()); + gpRender->SetModelMatrix(x34_model); + + gpRender->PrimColor(CColor::White()); + CGraphics::SetAlphaCompare(kAF_Always, 0, kAO_And, kAF_Always, 0); + CGraphics::SetDepthWriteMode(true, kE_LEqual, true); + CGraphics::SetBlendMode(kBM_Blend, kBF_SrcAlpha, kBF_InvSrcAlpha, kLO_Clear); + CGraphics::SetTevOp(kTS_Stage0, CGraphics::kEnvPassthru); + CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassthru); + + gpRender->BeginTriangleStrip(4); + gpRender->PrimVertex(CVector3f(-extent, 0.f, extent)); + gpRender->PrimVertex(CVector3f(extent, 0.f, extent)); + gpRender->PrimVertex(CVector3f(-extent, 0.f, -extent)); + gpRender->PrimVertex(CVector3f(extent, 0.f, -extent)); + gpRender->EndPrimitive(); + + gpRender->SetModelMatrix(CTransform4f::Identity()); + CCubeModel::SetRenderModelBlack(true); + CCubeModel::SetDrawingOccluders(true); + gpRender->PrepareDynamicLights(rstl::vector< CLight >()); + gpRender->DrawUnsortedGeometry(aid.value, 0, 0); + CCubeModel::SetRenderModelBlack(false); + CCubeModel::SetDrawingOccluders(false); + + if (lighten) { + gpRender->SetModelMatrix(x34_model); + CGraphics::SetAlphaCompare(kAF_Always, 0, kAO_And, kAF_Always, 0); + CGraphics::SetDepthWriteMode(false, kE_LEqual, false); + CGraphics::SetBlendMode(kBM_Blend, kBF_SrcAlpha, kBF_InvSrcAlpha, kLO_Clear); + CGraphics::SetTevOp(kTS_Stage0, CGraphics::kEnvPassthru); + CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassthru); + CGraphics::StreamBegin(kP_TriangleStrip); + CGraphics::StreamColor(1.f, 1.f, 1.f, 0.25f); + CGraphics::StreamVertex(CVector3f(-extent, 0.f, extent)); + CGraphics::StreamVertex(CVector3f(extent, 0.f, extent)); + CGraphics::StreamVertex(CVector3f(-extent, 0.f, -extent)); + CGraphics::StreamVertex(CVector3f(extent, 0.f, -extent)); + CGraphics::StreamEnd(); + CGraphics::SetDepthWriteMode(true, kE_LEqual, true); + } + + if (motionBlur && x88_blurReset != true) { + CGraphics::SetDepthWriteMode(false, kE_LEqual, false); + CGraphics::SetBlendMode(kBM_Blend, kBF_SrcAlpha, + kBF_InvSrcAlpha, kLO_Clear); + CGraphics::SetAlphaCompare(kAF_Always, 0, kAO_And, + kAF_Always, 0); + CGraphics::SetTevOp(kTS_Stage0, CGraphics::kEnvModulate); + CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassthru); + CGraphics::Render2D(*x0_texture, 0, x0_texture->GetWidth() * 2, + x0_texture->GetHeight() * 2, x0_texture->GetWidth() * -2, + CColor(1.f, 1.f, 1.f, 0.85f)); + CGraphics::SetDepthWriteMode(true, kE_LEqual, true); + } + + x88_blurReset = false; + + GXSetTexCopySrc(0, 448 - x0_texture->GetHeight() * 2, x0_texture->GetWidth() * 2, x0_texture->GetHeight() * 2); + GXTexFmt fmt = GX_TF_RGBA8; + if (x0_texture->GetTexelFormat() == 0x7) { + fmt = GX_TF_RGB565; + } + GXSetTexCopyDst(x0_texture->GetWidth(), x0_texture->GetHeight(), fmt, true); + static int unkInt = 0; + x0_texture->SetFlag1(true); + void * dest = x0_texture->GetBitMapData(0); + GXCopyTex(dest, true); + x0_texture->UnLock(); + + gpRender->SetViewport(backupVpLeft, backupVpTop, backupVpWidth, backupVpHeight); + CGraphics::SetDepthRange(backupDepthNear, backupDepthFar); + } + } + } +} + +void CWorldShadow::EnableModelProjectedShadow(const CTransform4f& pos, uint lightIdx, + float f1) const { + + static float M_SQRT2 = CMath::SqrtD(2.0); // TODO: should be an inlined function + CTransform4f texTransform = CTransform4f::LookAt(CVector3f::Zero(), x74_lightPos - x68_objPos, + CVector3f(0.0f, 0.0f, 1.0f)); + CTransform4f posXf = pos; + posXf.SetTranslation(CVector3f::Zero()); + texTransform = posXf.GetInverse() * texTransform; + texTransform = texTransform * CTransform4f::Scale(float(M_SQRT2) * x64_objHalfExtent * f1); + texTransform = texTransform.GetInverse(); + texTransform = CTransform4f::Translate(0.5f, 0.f, 0.5f) * texTransform; + + uchar lightMask = 1 << lightIdx; + CCubeModel::EnableShadowMaps(x0_texture.get(), texTransform, lightMask, lightMask); +} + +void CWorldShadow::DisableModelProjectedShadow() const { CCubeModel::DisableShadowMaps(); } + +void CWorldShadow::ResetBlur() { x88_blurReset = true; }