metaforce/Runtime/Camera/CCameraFilter.cpp

368 lines
12 KiB
C++

#include "Runtime/Camera/CCameraFilter.hpp"
#include "Runtime/CDvdFile.hpp"
#include "Runtime/CSimplePool.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CCubeRenderer.hpp"
#include "Runtime/Graphics/CGX.hpp"
#include "Runtime/Graphics/CGraphics.hpp"
#include <algorithm>
#include <zeus/CColor.hpp>
namespace metaforce {
void CCameraFilterPass::Update(float dt) {
if (x10_remTime <= 0.f)
return;
EFilterType origType = x0_curType;
x10_remTime = std::max(0.f, x10_remTime - dt);
x18_curColor = zeus::CColor::lerp(x1c_nextColor, x14_prevColor, x10_remTime / xc_duration);
if (x10_remTime == 0.f) {
x0_curType = x4_nextType;
if (x0_curType == EFilterType::Passthru) {
x24_texObj = TLockedToken<CTexture>();
x20_nextTxtr = {};
}
}
}
void CCameraFilterPass::SetFilter(EFilterType type, EFilterShape shape, float time, const zeus::CColor& color,
CAssetId txtr) {
if (time == 0.f) {
xc_duration = 0.f;
x10_remTime = 0.f;
if (txtr.IsValid())
x24_texObj = g_SimplePool->GetObj({FOURCC('TXTR'), txtr});
x4_nextType = type;
x0_curType = type;
x8_shape = shape;
x1c_nextColor = color;
x18_curColor = color;
x14_prevColor = color;
x20_nextTxtr = txtr;
} else {
EFilterType origType = x0_curType;
CAssetId origTxtr = x20_nextTxtr;
x1c_nextColor = color;
x14_prevColor = x18_curColor;
x8_shape = shape;
x20_nextTxtr = txtr;
if (txtr.IsValid())
x24_texObj = g_SimplePool->GetObj({FOURCC('TXTR'), txtr});
x10_remTime = time;
xc_duration = time;
x0_curType = x4_nextType;
x4_nextType = type;
if (type == EFilterType::Passthru) {
if (x0_curType == EFilterType::Multiply)
x1c_nextColor = zeus::skWhite;
else if (x0_curType == EFilterType::Add || x0_curType == EFilterType::Blend)
x1c_nextColor.a() = 0.f;
} else {
if (x0_curType == EFilterType::Passthru) {
if (type == EFilterType::Multiply) {
x18_curColor = zeus::skWhite;
} else if (type == EFilterType::Add || type == EFilterType::Blend) {
x18_curColor = x1c_nextColor;
x18_curColor.a() = 0.f;
x14_prevColor = x18_curColor;
}
}
x0_curType = x4_nextType;
}
}
}
void CCameraFilterPass::DisableFilter(float time) {
SetFilter(EFilterType::Passthru, x8_shape, time, zeus::skWhite, {});
}
void CCameraFilterPass::Draw() {
DrawFilter(x0_curType, x8_shape, x18_curColor, x24_texObj.GetObj(), GetT(x4_nextType == EFilterType::Passthru));
}
float CCameraFilterPass::GetT(bool invert) const {
float tmp;
if (xc_duration == 0.f)
tmp = 1.f;
else
tmp = 1.f - x10_remTime / xc_duration;
if (invert)
return 1.f - tmp;
return tmp;
}
void CCameraFilterPass::DrawFilter(EFilterType type, EFilterShape shape, const zeus::CColor& color, CTexture* tex,
float lod) {
switch (type) {
case EFilterType::Multiply:
g_Renderer->SetBlendMode_ColorMultiply();
break;
case EFilterType::Invert:
g_Renderer->SetBlendMode_InvertDst();
break;
case EFilterType::Add:
g_Renderer->SetBlendMode_AdditiveAlpha();
break;
case EFilterType::Subtract:
CGX::SetBlendMode(GX_BM_SUBTRACT, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR);
break;
case EFilterType::Blend:
g_Renderer->SetBlendMode_AlphaBlended();
break;
case EFilterType::Widescreen:
return;
case EFilterType::SceneAdd:
g_Renderer->SetBlendMode_AdditiveDestColor();
break;
case EFilterType::NoColor:
g_Renderer->SetBlendMode_NoColorWrite();
break;
default:
return;
}
DrawFilterShape(shape, color, tex, lod);
g_Renderer->SetBlendMode_AlphaBlended();
}
void CCameraFilterPass::DrawFullScreenColoredQuad(const zeus::CColor& color) {
SCOPED_GRAPHICS_DEBUG_GROUP("CCameraFilterPass::DrawFullScreenColoredQuad", zeus::skBlue);
const auto [lt, rb] = g_Renderer->SetViewportOrtho(true, -4096.f, 4096.f);
g_Renderer->SetDepthReadWrite(false, false);
g_Renderer->BeginTriangleStrip(4);
g_Renderer->PrimColor(color);
g_Renderer->PrimVertex({lt.x() - 1.f, 0.f, 1.f + rb.y()});
g_Renderer->PrimVertex({lt.x() - 1.f, 0.f, lt.y() - 1.f});
g_Renderer->PrimVertex({1.f + rb.x(), 0.f, 1.f + rb.y()});
g_Renderer->PrimVertex({1.f + rb.x(), 0.f, lt.y() - 1.f});
g_Renderer->EndPrimitive();
}
void CCameraFilterPass::DrawFilterShape(EFilterShape shape, const zeus::CColor& color, CTexture* tex, float lod) {
switch (shape) {
default:
if (tex == nullptr) {
DrawFullScreenColoredQuad(color);
} else {
DrawFullScreenTexturedQuad(color, tex, lod);
}
break;
case EFilterShape::FullscreenQuarters:
if (tex == nullptr) {
DrawFullScreenColoredQuad(color);
} else {
DrawFullScreenTexturedQuadQuarters(color, tex, lod);
}
break;
case EFilterShape::CinemaBars:
DrawWideScreen(color, tex, lod);
break;
case EFilterShape::ScanLinesEven:
DrawScanLines(color, true);
break;
case EFilterShape::ScanLinesOdd:
DrawScanLines(color, false);
break;
case EFilterShape::RandomStatic:
DrawRandomStatic(color, 1.f, false);
break;
case EFilterShape::CookieCutterDepthRandomStatic:
DrawRandomStatic(color, lod, true);
break;
}
}
void CCameraFilterPass::DrawFullScreenTexturedQuadQuarters(const zeus::CColor& color, CTexture* tex, float lod) {
SCOPED_GRAPHICS_DEBUG_GROUP("CCameraFilterPass::DrawFullScreenTexturedQuadQuarters", zeus::skBlue);
const auto [lt, rb] = g_Renderer->SetViewportOrtho(true, -4096.f, 4096.f);
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
g_Renderer->SetDepthReadWrite(false, false);
if (tex != nullptr) {
tex->Load(GX_TEXMAP0, EClampMode::Repeat);
}
CGraphics::SetCullMode(ERglCullMode::None);
for (int i = 0; i < 4; ++i) {
g_Renderer->SetModelMatrix(zeus::CTransform::Scale((i & 1) != 0 ? 1.f : -1.f, 0.f, (i & 2) != 0 ? 1.f : -1.f));
CGraphics::StreamBegin(GX_TRIANGLESTRIP);
CGraphics::StreamColor(color);
CGraphics::StreamTexcoord(lod, lod);
CGraphics::StreamVertex(lt.x(), 0.f, rb.y());
CGraphics::StreamTexcoord(lod, 0.f);
CGraphics::StreamVertex(lt.x(), 0.f, 0.f);
CGraphics::StreamTexcoord(0.f, lod);
CGraphics::StreamVertex(0.f, 0.f, rb.y());
CGraphics::StreamTexcoord(0.f, 0.f);
CGraphics::StreamVertex(0.f, 0.f, 0.f);
CGraphics::StreamEnd();
}
CGraphics::SetCullMode(ERglCullMode::Front);
}
void CCameraFilterPass::DrawFullScreenTexturedQuad(const zeus::CColor& color, CTexture* tex, float lod) {
SCOPED_GRAPHICS_DEBUG_GROUP("CCameraFilterPass::DrawFullScreenTexturedQuad", zeus::skBlue);
const float u = 0.5f - 0.5f * lod;
const float v = 0.5f + 0.5f * lod;
const auto [lt, rb] = g_Renderer->SetViewportOrtho(true, -4096.f, 4096.f);
g_Renderer->SetDepthReadWrite(false, false);
if (tex != nullptr) {
tex->Load(GX_TEXMAP0, EClampMode::Repeat);
}
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
CGraphics::StreamBegin(GX_TRIANGLESTRIP);
CGraphics::StreamColor(color);
CGraphics::StreamTexcoord(u, v);
CGraphics::StreamVertex(lt.x() - 1.f, 0.f, 1.f + rb.y());
CGraphics::StreamTexcoord(u, u);
CGraphics::StreamVertex(lt.x() - 1.f, 0.f, lt.y() - 1.f);
CGraphics::StreamTexcoord(v, v);
CGraphics::StreamVertex(1.f + rb.x(), 0.f, 1.f + rb.y());
CGraphics::StreamTexcoord(v, u);
CGraphics::StreamVertex(1.f + rb.x(), 0.f, lt.y() - 1.f);
CGraphics::StreamEnd();
}
void CCameraFilterPass::DrawRandomStatic(const zeus::CColor& color, float alpha, bool cookieCutterDepth) {
// TODO this shouldn't be here
static CTexture m_randomStatic{ETexelFormat::IA4, 640, 448, 1, "Camera Random Static"};
SCOPED_GRAPHICS_DEBUG_GROUP("CCameraFilterPass::DrawRandomStatic", zeus::skBlue);
const auto [lb, rt] = g_Renderer->SetViewportOrtho(true, 0.f, 1.f);
if (cookieCutterDepth) {
CGraphics::SetAlphaCompare(ERglAlphaFunc::GEqual, static_cast<u8>((1.f - alpha) * 255.f), ERglAlphaOp::And,
ERglAlphaFunc::Always, 0);
g_Renderer->SetDepthReadWrite(true, true);
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
} else {
g_Renderer->SetDepthReadWrite(false, false);
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a6038);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
}
// Upload random static texture (game reads from .text)
const u8* buf = CDvdFile::GetDolBuf() + 0x4f60;
u8* out = m_randomStatic.Lock();
memcpy(out, buf + ROUND_UP_32(rand() & 0x7fff), m_randomStatic.GetMemoryAllocated());
m_randomStatic.UnLock();
m_randomStatic.Load(GX_TEXMAP0, EClampMode::Clamp);
CGraphics::StreamBegin(GX_TRIANGLESTRIP);
CGraphics::StreamColor(color);
CGraphics::StreamTexcoord(0.f, 1.f);
CGraphics::StreamVertex(lb.x() - 1.f, 0.01f, rt.y() + 1.f);
CGraphics::StreamTexcoord(0.f, 0.f);
CGraphics::StreamVertex(lb.x() - 1.f, 0.01f, lb.y() - 1.f);
CGraphics::StreamTexcoord(1.f, 1.f);
CGraphics::StreamVertex(rt.x() + 1.f, 0.01f, rt.y() + 1.f);
CGraphics::StreamTexcoord(1.f, 0.f);
CGraphics::StreamVertex(rt.x() + 1.f, 0.01f, lb.y() - 1.f);
CGraphics::StreamEnd();
if (cookieCutterDepth) {
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
}
}
void CCameraFilterPass::DrawScanLines(const zeus::CColor& color, bool even) {
SCOPED_GRAPHICS_DEBUG_GROUP("CCameraFilterPass::DrawScanLines", zeus::skBlue);
const auto [lt, rb] = g_Renderer->SetViewportOrtho(true, -4096.f, 4096.f);
g_Renderer->SetDepthReadWrite(false, false);
g_Renderer->SetModelMatrix({});
// CGraphics::SetLineWidth(2.f, 5);
// g_Renderer->BeginLines(...);
// TODO
// CGraphics::SetLineWidth(1.f, 5);
}
void CCameraFilterPass::DrawWideScreen(const zeus::CColor& color, CTexture* tex, float lod) {
SCOPED_GRAPHICS_DEBUG_GROUP("CCameraFilterPass::DrawWideScreen", zeus::skBlue);
// const auto vp = g_Renderer->SetViewportOrtho(true, -4096.f, 4096.f);
// float f = -((vp.second.x() - vp.first.x()) * 0.0625f * 9.f - (vp.second.y() - vp.first.y())) * 0.5f;
// g_Renderer->SetDepthReadWrite(false, false);
// g_Renderer->SetModelMatrix({});
// if (tex != nullptr) {
// tex->Load(GX_TEXMAP0, EClampMode::Repeat);
// }
// CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
// CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
// CGraphics::StreamBegin(GX_TRIANGLESTRIP);
// float x = rand() % 4000;
}
void CCameraBlurPass::Draw(bool clearDepth) {
if (x10_curType == EBlurType::NoBlur)
return;
// TODO
// if (x10_curType == EBlurType::Xray) {
// if (!m_xrayShader)
// m_xrayShader.emplace(x0_paletteTex);
// m_xrayShader->draw(x1c_curValue);
// } else {
// if (!m_shader)
// m_shader.emplace();
// m_shader->draw(x1c_curValue, clearDepth);
// if (clearDepth)
// CGraphics::SetDepthRange(DEPTH_NEAR, DEPTH_FAR);
// }
}
void CCameraBlurPass::Update(float dt) {
if (x28_remainingTime > 0.f) {
x28_remainingTime = std::max(x28_remainingTime - dt, 0.f);
x1c_curValue = x18_endValue + (x20_startValue - x18_endValue) * x28_remainingTime / x24_totalTime;
if (x28_remainingTime != 0.f)
return;
x10_curType = x14_endType;
}
}
void CCameraBlurPass::SetBlur(EBlurType type, float amount, float duration, bool usePersistentFb) {
// TODO impl usePersistentFb
if (duration == 0.f) {
x24_totalTime = 0.f;
x28_remainingTime = 0.f;
x18_endValue = amount;
x1c_curValue = amount;
x20_startValue = amount;
if (x10_curType == EBlurType::NoBlur) {
if (type == EBlurType::Xray)
x0_paletteTex = g_SimplePool->GetObj("TXTR_XRayPalette");
}
x14_endType = type;
x10_curType = type;
x2c_usePersistent = usePersistentFb;
} else {
x2c_usePersistent = usePersistentFb;
x24_totalTime = duration;
x28_remainingTime = duration;
x18_endValue = x1c_curValue;
x20_startValue = amount;
if (type != x14_endType) {
if (x10_curType == EBlurType::NoBlur) {
if (type == EBlurType::Xray)
x0_paletteTex = g_SimplePool->GetObj("TXTR_XRayPalette");
x10_curType = type;
}
x14_endType = type;
}
}
}
void CCameraBlurPass::DisableBlur(float duration) { SetBlur(EBlurType::NoBlur, 0.f, duration, x2c_usePersistent); }
} // namespace metaforce