mirror of https://github.com/PrimeDecomp/prime.git
185 lines
7.8 KiB
C++
185 lines
7.8 KiB
C++
#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(rs_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->fn_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;
|
|
void * dest = x0_texture->Lock();
|
|
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 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(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; }
|