Transition all Textured/ColoredQuad usages

- Upload textures using staging buffer
- Fixes SetOrtho logic
- More work on thermal visor rendering (still WIP)
- Rework Dawn backend initialization
- Support MoltenVK on Metal
- Various fixes & cleanup
This commit is contained in:
Luke Street 2022-05-23 20:26:35 -04:00
parent 36a7bfc464
commit f80813b9cc
65 changed files with 857 additions and 687 deletions

View File

@ -1450,17 +1450,17 @@ void CAutoMapper::Draw(const CStateManager& mgr, const zeus::CTransform& xf, flo
if (IsInMapperState(EAutoMapperState::MapScreen)) {
CAssetId wldMlvl = x24_world->IGetWorldAssetId();
const CMapWorld* mw = x24_world->IGetMapWorld();
std::vector<CTexturedQuadFilter>& hintBeaconFilters = m_hintBeaconFilters;
if (hintBeaconFilters.size() < x1f8_hintLocations.size()) {
hintBeaconFilters.reserve(x1f8_hintLocations.size());
for (u32 i = hintBeaconFilters.size(); i < x1f8_hintLocations.size(); ++i)
hintBeaconFilters.emplace_back(EFilterType::Add, x3c_hintBeacon);
}
// std::vector<CTexturedQuadFilter>& hintBeaconFilters = m_hintBeaconFilters;
// if (hintBeaconFilters.size() < x1f8_hintLocations.size()) {
// hintBeaconFilters.reserve(x1f8_hintLocations.size());
// for (u32 i = hintBeaconFilters.size(); i < x1f8_hintLocations.size(); ++i)
// hintBeaconFilters.emplace_back(EFilterType::Add, x3c_hintBeacon);
// }
auto locIt = x1f8_hintLocations.cbegin();
auto filterIt = hintBeaconFilters.begin();
for (; locIt != x1f8_hintLocations.cend(); ++locIt, ++filterIt) {
// auto filterIt = hintBeaconFilters.begin();
for (; locIt != x1f8_hintLocations.cend(); ++locIt/*, ++filterIt*/) {
const SAutoMapperHintLocation& loc = *locIt;
CTexturedQuadFilter& filter = *filterIt;
// CTexturedQuadFilter& filter = *filterIt;
if (loc.x8_worldId != wldMlvl)
continue;
const CMapArea* mapa = mw->GetMapArea(loc.xc_areaId);
@ -1475,12 +1475,12 @@ void CAutoMapper::Draw(const CStateManager& mgr, const zeus::CTransform& xf, flo
beaconAlpha = loc.x4_beaconAlpha;
}
if (beaconAlpha > 0.f) {
constexpr std::array<CTexturedQuadFilter::Vert, 4> verts{{
{{-4.f, -8.f, 8.f}, {0.f, 1.f}},
{{-4.f, -8.f, 0.f}, {0.f, 0.f}},
{{4.f, -8.f, 8.f}, {1.f, 1.f}},
{{4.f, -8.f, 0.f}, {1.f, 0.f}},
}};
// constexpr std::array<CTexturedQuadFilter::Vert, 4> verts{{
// {{-4.f, -8.f, 8.f}, {0.f, 1.f}},
// {{-4.f, -8.f, 0.f}, {0.f, 0.f}},
// {{4.f, -8.f, 8.f}, {1.f, 1.f}},
// {{4.f, -8.f, 0.f}, {1.f, 0.f}},
// }};
float colorAlpha = beaconAlpha;
if (x1bc_state != EAutoMapperState::MiniMap && x1c0_nextState != EAutoMapperState::MiniMap) {
} else {
@ -1489,7 +1489,8 @@ void CAutoMapper::Draw(const CStateManager& mgr, const zeus::CTransform& xf, flo
colorAlpha *= mapAlpha;
zeus::CColor color = zeus::skWhite;
color.a() = colorAlpha;
filter.drawVerts(color, verts);
// TODO
// filter.drawVerts(color, verts);
}
}
}

View File

@ -133,7 +133,6 @@ private:
bool m_frmeInitialized = false;
TLockedToken<CModel> x30_miniMapSamus;
TLockedToken<CTexture> x3c_hintBeacon;
std::vector<CTexturedQuadFilter> m_hintBeaconFilters;
rstl::reserved_vector<TLockedToken<CTexture>, 5> x48_mapIcons;
CAssetId x74_areaHintDescId;
TLockedToken<CStringTable> x78_areaHintDesc;

View File

@ -167,16 +167,16 @@ void CMappableObject::Draw(int curArea, const CMapWorldInfo& mwInfo, float alpha
iconColor.a() *= alpha;
TLockedToken<CTexture> tex = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), iconRes});
if (!m_texQuadFilter || m_texQuadFilter->GetTex().GetObj() != tex.GetObj()) {
// if (!m_texQuadFilter || m_texQuadFilter->GetTex().GetObj() != tex.GetObj()) {
//m_texQuadFilter.emplace(EFilterType::Add, tex, CTexturedQuadFilter::ZTest::GEqual);
}
// }
constexpr std::array<CTexturedQuadFilter::Vert, 4> verts{{
{{-2.6f, 0.f, 2.6f}, {0.f, 1.f}},
{{-2.6f, 0.f, -2.6f}, {0.f, 0.f}},
{{2.6f, 0.f, 2.6f}, {1.f, 1.f}},
{{2.6f, 0.f, -2.6f}, {1.f, 0.f}},
}};
// constexpr std::array<CTexturedQuadFilter::Vert, 4> verts{{
// {{-2.6f, 0.f, 2.6f}, {0.f, 1.f}},
// {{-2.6f, 0.f, -2.6f}, {0.f, 0.f}},
// {{2.6f, 0.f, 2.6f}, {1.f, 1.f}},
// {{2.6f, 0.f, -2.6f}, {1.f, 0.f}},
// }};
//m_texQuadFilter->drawVerts(iconColor, verts);
}
}

View File

@ -7,7 +7,6 @@
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CLineRenderer.hpp"
#include "Runtime/Graphics/Shaders/CMapSurfaceShader.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/RetroTypes.hpp"
#include <zeus/CAABox.hpp>
@ -67,7 +66,6 @@ private:
, m_outline(CLineRenderer::EPrimitiveMode::LineLoop, 5, {}, false, false, true) {}
};
std::optional<DoorSurface> m_doorSurface;
std::optional<CTexturedQuadFilter> m_texQuadFilter;
zeus::CTransform AdjustTransformForType() const;
std::pair<zeus::CColor, zeus::CColor> GetDoorColors(int idx, const CMapWorldInfo& mwInfo, float alpha) const;

View File

@ -623,7 +623,7 @@ void CStateManager::DrawE3DeathEffect() {
const float whiteAmt = zeus::clamp(0.f, 1.f - player.x9f4_deathTime / (0.05f * 6.f), 1.f);
zeus::CColor color = zeus::skWhite;
color.a() = whiteAmt;
m_deathWhiteout.draw(color);
CCameraFilterPass::DrawFilter(EFilterType::Add, EFilterShape::Fullscreen, color, nullptr, 1.f);
}
void CStateManager::DrawAdditionalFilters() {
@ -633,7 +633,7 @@ void CStateManager::DrawAdditionalFilters() {
zeus::CColor color = zeus::skWhite;
color.a() = 1.f - xf0c_escapeTimer;
m_escapeWhiteout.draw(color);
CCameraFilterPass::DrawFilter(EFilterType::Add, EFilterShape::Fullscreen, color, nullptr, 1.f);
}
zeus::CFrustum CStateManager::SetupDrawFrustum(const SViewport& vp) const {
@ -674,32 +674,13 @@ zeus::CFrustum CStateManager::SetupViewForDraw(const SViewport& vp) const {
proj.setPersp(zeus::SProjPersp{fov, width / height, cam->GetNearClipDistance(), cam->GetFarClipDistance()});
frustum.updatePlanes(camXf, proj);
g_Renderer->SetClippingPlanes(frustum);
// g_Renderer->PrimColor(zeus::skWhite);
g_Renderer->PrimColor(zeus::skWhite);
CGraphics::SetModelMatrix(zeus::CTransform());
x87c_fluidPlaneManager->StartFrame(false);
g_Renderer->SetDebugOption(IRenderer::EDebugOption::PVSState, int(EPVSVisSetState::NodeFound));
return frustum;
}
zeus::CFrustum CStateManager::SetupViewForCubeFaceDraw(const zeus::CVector3f& pos, int face) const {
const zeus::CTransform mainCamXf = x870_cameraManager->GetCurrentCameraTransform(*this);
const zeus::CTransform camXf = zeus::CTransform(mainCamXf.basis * CGraphics::skCubeBasisMats[face], pos);
g_Renderer->SetWorldViewpoint(camXf);
CCubeModel::SetNewPlayerPositionAndTime(x84c_player->GetTranslation(), CStopwatch::GetGlobalTimerObj());
constexpr float width = CUBEMAP_RES;
g_Renderer->SetViewport(0, 0, width, width);
CGraphics::SetDepthRange(DEPTH_WORLD, DEPTH_FAR);
constexpr float fov = zeus::degToRad(90.f);
g_Renderer->SetPerspective(zeus::radToDeg(fov), width, width, 0.2f, 750.f);
zeus::CFrustum frustum;
zeus::CProjection proj;
proj.setPersp(zeus::SProjPersp{fov, 1.f, 0.2f, 750.f});
frustum.updatePlanes(camXf, proj);
g_Renderer->SetClippingPlanes(frustum);
CGraphics::SetModelMatrix(zeus::CTransform());
return frustum;
}
void CStateManager::ResetViewAfterDraw(const SViewport& backupViewport,
const zeus::CTransform& backupViewMatrix) const {
g_Renderer->SetViewport(backupViewport.x0_left, backupViewport.x4_top, backupViewport.x8_width,
@ -725,8 +706,6 @@ void CStateManager::DrawWorld() {
x850_world->TouchSky();
DrawWorldCubeFaces();
const zeus::CFrustum frustum = SetupViewForDraw(CGraphics::g_Viewport);
const zeus::CTransform backupViewMatrix = CGraphics::g_ViewMatrix;
@ -983,120 +962,6 @@ void CStateManager::DrawWorld() {
DrawAdditionalFilters();
}
void CStateManager::DrawActorCubeFaces(CActor& actor, int& cubeInst) const {
// if (!actor.m_reflectionCube ||
// (!TCastToPtr<CPlayer>(actor) && (!actor.GetActive() || !actor.IsDrawEnabled() || actor.xe4_30_outOfFrustum)))
// return;
//
// const TAreaId visAreaId = actor.GetAreaIdAlways();
// const SViewport backupVp = g_Viewport;
//
// int areaCount = 0;
// std::array<const CGameArea*, 10> areaArr;
// for (const CGameArea& area : *x850_world) {
// if (areaCount == 10) {
// break;
// }
// auto occState = CGameArea::EOcclusionState::Occluded;
// if (area.IsPostConstructed()) {
// occState = area.GetOcclusionState();
// }
// if (occState == CGameArea::EOcclusionState::Visible) {
// areaArr[areaCount++] = &area;
// }
// }
//
// for (int f = 0; f < 6; ++f) {
// SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CStateManager::DrawActorCubeFaces [{}] {} {} {}"), f,
// actor.GetUniqueId(), actor.GetEditorId(), actor.GetName())
// .c_str(),
// zeus::skOrange);
// CGraphics::g_BooMainCommandQueue->setRenderTarget(actor.m_reflectionCube, f);
// SetupViewForCubeFaceDraw(actor.GetRenderBounds().center(), f);
// CGraphics::g_BooMainCommandQueue->clearTarget();
//
// std::sort(areaArr.begin(), areaArr.begin() + areaCount, [visAreaId](const CGameArea* a, const CGameArea* b) {
// if (a->x4_selfIdx == b->x4_selfIdx) {
// return false;
// }
// if (visAreaId == a->x4_selfIdx) {
// return false;
// }
// if (visAreaId == b->x4_selfIdx) {
// return true;
// }
// return CGraphics::g_ViewPoint.dot(a->GetAABB().center()) > CGraphics::g_ViewPoint.dot(b->GetAABB().center());
// });
//
// int pvsCount = 0;
// std::array<CPVSVisSet, 10> pvsArr;
// for (auto area = areaArr.cbegin(); area != areaArr.cbegin() + areaCount; ++area) {
// const CGameArea* areaPtr = *area;
// CPVSVisSet& pvsSet = pvsArr[pvsCount++];
// pvsSet.Reset(EPVSVisSetState::OutOfBounds);
// GetVisSetForArea(areaPtr->x4_selfIdx, visAreaId, pvsSet);
// }
//
// for (int i = areaCount - 1; i >= 0; --i) {
// const CGameArea& area = *areaArr[i];
// SetupFogForArea(area);
// g_Renderer->EnablePVS(pvsArr[i], area.x4_selfIdx);
// g_Renderer->SetWorldLightFadeLevel(area.GetPostConstructed()->x1128_worldLightingLevel);
// g_Renderer->UpdateAreaUniforms(area.x4_selfIdx, EWorldShadowMode::None, true, cubeInst * 6 + f);
// g_Renderer->DrawUnsortedGeometry(area.x4_selfIdx, 0x2, 0x0);
// }
//
// if (!SetupFogForDraw()) {
// g_Renderer->SetWorldFog(ERglFogMode::None, 0.f, 1.f, zeus::skBlack);
// }
//
// x850_world->DrawSky(zeus::CTransform::Translate(CGraphics::g_ViewPoint));
//
// for (int i = 0; i < areaCount; ++i) {
// const CGameArea& area = *areaArr[i];
// CPVSVisSet& pvs = pvsArr[i];
// SetupFogForArea(area);
// g_Renderer->SetWorldLightFadeLevel(area.GetPostConstructed()->x1128_worldLightingLevel);
// g_Renderer->EnablePVS(pvs, area.x4_selfIdx);
// g_Renderer->DrawSortedGeometry(area.x4_selfIdx, 0x2, 0x0);
// }
// }
//
// CGraphics::g_BooMainCommandQueue->generateMipmaps(actor.m_reflectionCube);
//
// CBooRenderer::BindMainDrawTarget();
// g_Renderer->SetViewport(backupVp.x0_left, backupVp.x4_top, backupVp.x8_width, backupVp.xc_height);
//
// ++cubeInst;
}
void CStateManager::DrawWorldCubeFaces() const {
size_t areaCount = 0;
std::array<const CGameArea*, 10> areaArr;
for (const CGameArea& area : *x850_world) {
if (areaCount == areaArr.size()) {
break;
}
auto occState = CGameArea::EOcclusionState::Occluded;
if (area.IsPostConstructed()) {
occState = area.GetOcclusionState();
}
if (occState == CGameArea::EOcclusionState::Visible) {
areaArr[areaCount++] = &area;
}
}
for (size_t ai = 0; ai < areaCount; ++ai) {
const CGameArea& area = *areaArr[ai];
int cubeInst = 0;
for (CEntity* ent : *area.GetAreaObjects()) {
if (const TCastToPtr<CActor> actor = ent) {
DrawActorCubeFaces(*actor, cubeInst);
}
}
}
}
void CStateManager::SetupFogForArea3XRange(TAreaId area) const {
if (area == kInvalidAreaId) {
area = x8cc_nextAreaId;
@ -2490,7 +2355,7 @@ void CStateManager::FrameBegin(s32 frameCount) {
x8d4_inputFrameIdx = frameCount;
CTexture::SetCurrentFrameCount(frameCount);
CGraphicsPalette::SetCurrentFrameCount(frameCount);
//SwapOutTexturesToARAM(2, 0x180000);
// SwapOutTexturesToARAM(2, 0x180000);
}
void CStateManager::InitializeState(CAssetId mlvlId, TAreaId aid, CAssetId mreaId) {

View File

@ -18,7 +18,6 @@
#include "Runtime/Camera/CCameraManager.hpp"
#include "Runtime/Camera/CCameraShakeData.hpp"
#include "Runtime/GameObjectLists.hpp"
#include "Runtime/Graphics/Shaders/CColoredQuadFilter.hpp"
#include "Runtime/Input/CFinalInput.hpp"
#include "Runtime/Input/CRumbleManager.hpp"
#include "Runtime/Weapon/CWeaponMgr.hpp"
@ -211,8 +210,6 @@ private:
bool xf94_29_cinematicPause : 1 = false;
bool xf94_30_fullThreat : 1 = false;
CColoredQuadFilter m_deathWhiteout{EFilterType::Add};
CColoredQuadFilter m_escapeWhiteout{EFilterType::Add};
bool m_warping = false;
std::map<TEditorId, std::set<SConnection>> m_incomingConnections;
@ -258,11 +255,8 @@ public:
void DrawAdditionalFilters();
zeus::CFrustum SetupDrawFrustum(const SViewport& vp) const;
zeus::CFrustum SetupViewForDraw(const SViewport& vp) const;
zeus::CFrustum SetupViewForCubeFaceDraw(const zeus::CVector3f& pos, int face) const;
void ResetViewAfterDraw(const SViewport& backupViewport, const zeus::CTransform& backupViewMatrix) const;
void DrawWorld();
void DrawActorCubeFaces(CActor& actor, int& cubeInst) const;
void DrawWorldCubeFaces() const;
void SetupFogForArea3XRange(TAreaId area) const;
void SetupFogForArea(TAreaId area) const;
void SetupFogForAreaNonCurrent(TAreaId area) const;

View File

@ -4,10 +4,6 @@
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CCubeRenderer.hpp"
#include "Runtime/Graphics/CGraphics.hpp"
#include "Runtime/Graphics/Shaders/CColoredQuadFilter.hpp"
#include "Runtime/Graphics/Shaders/CRandomStaticFilter.hpp"
#include "Runtime/Graphics/Shaders/CScanLinesFilter.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/Graphics/CGX.hpp"
#include <algorithm>

View File

@ -682,16 +682,16 @@ void CCubeRenderer::SetPerspective(float fovy, float width, float height, float
std::pair<zeus::CVector2f, zeus::CVector2f> CCubeRenderer::SetViewportOrtho(bool centered, float znear, float zfar) {
auto left = static_cast<float>(centered ? CGraphics::GetViewportLeft() - CGraphics::GetViewportHalfWidth()
: CGraphics::GetViewportLeft());
auto top = static_cast<float>(centered ? CGraphics::GetViewportTop() - CGraphics::GetViewportHalfHeight()
: CGraphics::GetViewportHeight());
auto bottom = static_cast<float>(centered ? CGraphics::GetViewportTop() - CGraphics::GetViewportHalfHeight()
: CGraphics::GetViewportTop());
auto right = static_cast<float>(CGraphics::GetViewportLeft() +
(centered ? CGraphics::GetViewportWidth() / 2 : CGraphics::GetViewportWidth()));
auto bottom = static_cast<float>(CGraphics::GetViewportTop() +
(centered ? CGraphics::GetViewportHeight() / 2 : CGraphics::GetViewportHeight()));
auto top = static_cast<float>(CGraphics::GetViewportTop() +
(centered ? CGraphics::GetViewportHeight() / 2 : CGraphics::GetViewportHeight()));
CGraphics::SetOrtho(left, right, top, bottom, znear, zfar);
CGraphics::SetViewPointMatrix({});
CGraphics::SetModelMatrix({});
return {{left, top}, {right, bottom}};
return {{left, bottom}, {right, top}};
}
void CCubeRenderer::SetClippingPlanes(const zeus::CFrustum& frustum) { x44_frustumPlanes = frustum; }
@ -896,6 +896,8 @@ void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& co
void CCubeRenderer::SetThermalColdScale(float scale) { x2f8_thermColdScale = zeus::clamp(0.f, scale, 1.f); }
void CCubeRenderer::DoThermalBlendCold() {
SCOPED_GRAPHICS_DEBUG_GROUP("CCubeRenderer::DoThermalBlendCold", zeus::skBlue);
// Capture EFB
x318_26_requestRGBA6 = true;
GXSetAlphaUpdate(true);
@ -908,12 +910,14 @@ void CCubeRenderer::DoThermalBlendCold() {
// GXSetTexCopySrc(left, top, width, height);
// GXSetTexCopyDst(width, height, GX::TF_I4, false);
// GXCopyTex(sSpareTextureData, true);
CGraphics::ResolveSpareTexture(aurora::gfx::ClipRect{
.x = static_cast<int32_t>(left),
.y = static_cast<int32_t>(top),
.width = static_cast<int32_t>(width),
.height = static_cast<int32_t>(height),
}, 0, GX::TF_I4);
CGraphics::ResolveSpareTexture(
aurora::gfx::ClipRect{
.x = static_cast<int32_t>(left),
.y = static_cast<int32_t>(top),
.width = static_cast<int32_t>(width),
.height = static_cast<int32_t>(height),
},
0, GX::TF_I4);
// CGraphics::LoadDolphinSpareTexture(width, height, GX::TF_I4, nullptr, GX::TEXMAP7);
CGraphics::LoadDolphinSpareTexture(0, GX::TF_I4, GX::TEXMAP7);
@ -1019,14 +1023,7 @@ void CCubeRenderer::DoThermalBlendCold() {
}
void CCubeRenderer::DoThermalBlendHot() {
CGX::SetNumIndStages(0);
CGX::SetTevDirect(GX::TEVSTAGE0);
GXSetAlphaUpdate(true);
// CGraphics::SetProjectionState(backupProjectionState);
// CGraphics::SetViewPointMatrix(backupViewMatrix);
CDecal::SetMoveRedToAlphaBuffer(false);
CElementGen::SetMoveRedToAlphaBuffer(false);
return; // TODO
SCOPED_GRAPHICS_DEBUG_GROUP("CCubeRenderer::DoThermalBlendHot", zeus::skRed);
GXSetAlphaUpdate(false);
GXSetDstAlpha(true, 0);
@ -1041,7 +1038,7 @@ void CCubeRenderer::DoThermalBlendHot() {
CGraphics::ResolveSpareTexture(CGraphics::g_Viewport, 0, GX::TF_I4);
x288_thermoPalette.Load();
// CGraphics::LoadDolphinSpareTexture(width, height, GX::TF_C4, GX::TLUT0, nullptr, GX::TEXMAP7);
CGraphics::LoadDolphinSpareTexture(0, GX::TF_C4, GX::TEXMAP7);
CGraphics::LoadDolphinSpareTexture(0, GX_TF_C4, GX_TLUT0, GX::TEXMAP7);
CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_TEXA, GX::CC_TEXC, GX::CC_ZERO);
CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_TEXA);
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0);
@ -1080,7 +1077,14 @@ void CCubeRenderer::DoThermalBlendHot() {
GXTexCoord2f32(1.f, 0.f);
CGX::End();
// move prologue here
// Cleanup
CGX::SetNumIndStages(0);
CGX::SetTevDirect(GX::TEVSTAGE0);
GXSetAlphaUpdate(true);
CGraphics::SetProjectionState(backupProjectionState);
CGraphics::SetViewPointMatrix(backupViewMatrix);
CDecal::SetMoveRedToAlphaBuffer(false);
CElementGen::SetMoveRedToAlphaBuffer(false);
}
u32 CCubeRenderer::GetStaticWorldDataSize() {

View File

@ -316,7 +316,13 @@ public:
}
static void LoadDolphinSpareTexture(int bindIdx, GX::TextureFormat format, GX::TexMapID id) {
GXTexObj obj;
GXInitTexObjResolved(&obj, bindIdx, format, GX_CLAMP, GX_CLAMP);
GXInitTexObjResolved(&obj, bindIdx, format, GX_CLAMP, GX_CLAMP, GX_TLUT0);
GXInitTexObjLOD(&obj, GX_NEAR, GX_NEAR, 0.f, 0.f, 0.f, false, false, GX_ANISO_1);
GXLoadTexObj(&obj, id);
}
static void LoadDolphinSpareTexture(int bindIdx, GXCITexFmt format, GXTlut tlut, GX::TexMapID id) {
GXTexObj obj;
GXInitTexObjResolved(&obj, bindIdx, static_cast<GX::TextureFormat>(format), GX_CLAMP, GX_CLAMP, tlut);
GXInitTexObjLOD(&obj, GX_NEAR, GX_NEAR, 0.f, 0.f, 0.f, false, false, GX_ANISO_1);
GXLoadTexObj(&obj, id);
}

View File

@ -26,8 +26,6 @@ set(GRAPHICS_SOURCES
CRainSplashGenerator.hpp CRainSplashGenerator.cpp
CFont.hpp CFont.cpp
Shaders/CLineRendererShaders.hpp Shaders/CLineRendererShaders.cpp
Shaders/CTexturedQuadFilter.hpp Shaders/CTexturedQuadFilter.cpp
Shaders/CColoredQuadFilter.hpp Shaders/CColoredQuadFilter.cpp
Shaders/CColoredStripShader.hpp Shaders/CColoredStripShader.cpp
Shaders/CModelShaders.hpp Shaders/CModelShaders.cpp
Shaders/CThermalColdFilter.hpp Shaders/CThermalColdFilter.cpp

View File

@ -4,6 +4,7 @@
#include "CDvdRequest.hpp"
#include "Graphics/CGraphics.hpp"
#include "Graphics/CCubeRenderer.hpp"
#include "Graphics/CGX.hpp"
#include "GameGlobalObjects.hpp"
#include <amuse/DSPCodec.hpp>
@ -11,6 +12,110 @@
namespace metaforce {
static void MyTHPYuv2RgbTextureSetup(void* dataY, void* dataU, void* dataV, u16 width, u16 height) {
GXTexObj texV;
GXTexObj texU;
GXTexObj texY;
GXInitTexObj(&texY, dataY, width, height, GX::TF_I8, GX_CLAMP, GX_CLAMP, false);
GXInitTexObjLOD(&texY, GX_NEAR, GX_NEAR, 0.0, 0.0, 0.0, false, false, GX_ANISO_1);
GXLoadTexObj(&texY, GX::TEXMAP0);
GXInitTexObj(&texU, dataU, width / 2, height / 2, GX::TF_I8, GX_CLAMP, GX_CLAMP, false);
GXInitTexObjLOD(&texU, GX_NEAR, GX_NEAR, 0.0, 0.0, 0.0, false, false, GX_ANISO_1);
GXLoadTexObj(&texU, GX::TEXMAP1);
GXInitTexObj(&texV, dataV, width / 2, height / 2, GX::TF_I8, GX_CLAMP, GX_CLAMP, false);
GXInitTexObjLOD(&texV, GX_NEAR, GX_NEAR, 0.0, 0.0, 0.0, false, false, GX_ANISO_1);
GXLoadTexObj(&texV, GX::TEXMAP2);
CTexture::InvalidateTexMap(GX::TEXMAP0);
CTexture::InvalidateTexMap(GX::TEXMAP1);
CTexture::InvalidateTexMap(GX::TEXMAP2);
}
const std::array<u8, 32> InterlaceTex{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0,
};
static void MyTHPGXYuv2RgbSetup(bool interlaced2ndFrame, bool fieldFlip) {
CGX::SetZMode(true, GX::ALWAYS, false);
CGX::SetBlendMode(GX::BM_NONE, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR);
CGX::SetNumChans(0);
CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX2x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY);
CGX::SetTexCoordGen(GX::TEXCOORD1, GX::TG_MTX2x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY);
if (!fieldFlip) {
CGX::SetNumTexGens(3);
CGX::SetTexCoordGen(GX::TEXCOORD2, GX::TG_MTX2x4, GX::TG_POS, GX::TEXMTX0, false, GX::PTIDENTITY);
aurora::Mat4x2<float> mtx;
mtx.m0.x = 0.125f;
mtx.m2.y = 0.25f;
if (interlaced2ndFrame) {
mtx.m3.y = 0.25f;
}
GXLoadTexMtxImm(&mtx, GX::TEXMTX0, GX::MTX2x4);
GXTexObj texObj;
GXInitTexObj(&texObj, InterlaceTex.data(), 8, 4, GX::TF_I8, GX_REPEAT, GX_REPEAT, false);
GXInitTexObjLOD(&texObj, GX_NEAR, GX_NEAR, 0.f, 0.f, 0.f, false, false, GX_ANISO_1);
GXLoadTexObj(&texObj, GX::TEXMAP3);
CTexture::InvalidateTexMap(GX::TEXMAP3);
CGX::SetTevOrder(GX::TEVSTAGE4, GX::TEXCOORD2, GX::TEXMAP3, GX::COLOR_NULL);
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE4);
CGX::SetTevColorIn(GX::TEVSTAGE4, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_CPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE4, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_TEXA);
CGX::SetAlphaCompare(GX::LESS, 128, GX::AOP_AND, GX::ALWAYS, 0);
CGX::SetNumTevStages(5);
} else {
CGX::SetNumTexGens(2);
CGX::SetNumTevStages(4);
}
constexpr std::array vtxDescList{
GX::VtxDescList{GX::VA_POS, GX::DIRECT},
GX::VtxDescList{GX::VA_TEX0, GX::DIRECT},
GX::VtxDescList{},
};
CGX::SetVtxDescv(vtxDescList.data());
GXSetColorUpdate(true);
GXSetAlphaUpdate(false);
GXInvalidateTexAll();
GXSetVtxAttrFmt(GX::VTXFMT7, GX::VA_POS, GX::CLR_RGBA, GX::F32, 0);
GXSetVtxAttrFmt(GX::VTXFMT7, GX::VA_TEX0, GX::CLR_RGBA, GX::RGBX8, 0);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR_NULL);
CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_TEXC, GX::CC_KONST, GX::CC_C0);
CGX::SetTevColorOp(GX::TEVSTAGE0, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, false, GX::TEVPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_TEXA, GX::CA_KONST, GX::CA_A0);
CGX::SetTevAlphaOp(GX::TEVSTAGE0, GX::TEV_SUB, GX::TB_ZERO, GX::CS_SCALE_1, false, GX::TEVPREV);
CGX::SetTevKColorSel(GX::TEVSTAGE0, GX::TEV_KCSEL_K0);
CGX::SetTevKAlphaSel(GX::TEVSTAGE0, GX::TEV_KASEL_K0_A);
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP2, GX::COLOR_NULL);
CGX::SetTevColorIn(GX::TEVSTAGE1, GX::CC_ZERO, GX::CC_TEXC, GX::CC_KONST, GX::CC_CPREV);
CGX::SetTevColorOp(GX::TEVSTAGE1, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_2, false, GX::TEVPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE1, GX::CA_ZERO, GX::CA_TEXA, GX::CA_KONST, GX::CA_APREV);
CGX::SetTevAlphaOp(GX::TEVSTAGE1, GX::TEV_SUB, GX::TB_ZERO, GX::CS_SCALE_1, false, GX::TEVPREV);
CGX::SetTevKColorSel(GX::TEVSTAGE1, GX::TEV_KCSEL_K1);
CGX::SetTevKAlphaSel(GX::TEVSTAGE1, GX::TEV_KASEL_K1_A);
CGX::SetTevOrder(GX::TEVSTAGE2, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL);
CGX::SetTevColorIn(GX::TEVSTAGE2, GX::CC_ZERO, GX::CC_TEXC, GX::CC_ONE, GX::CC_CPREV);
CGX::SetTevColorOp(GX::TEVSTAGE2, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE2, GX::CA_TEXA, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV);
CGX::SetTevAlphaOp(GX::TEVSTAGE2, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
CGX::SetTevOrder(GX::TEVSTAGE3, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL);
CGX::SetTevColorIn(GX::TEVSTAGE3, GX::CC_APREV, GX::CC_CPREV, GX::CC_KONST, GX::CC_ZERO);
CGX::SetTevColorOp(GX::TEVSTAGE3, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
CGX::SetTevAlphaIn(GX::TEVSTAGE3, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO);
CGX::SetTevAlphaOp(GX::TEVSTAGE3, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
CGX::SetTevKColorSel(GX::TEVSTAGE3, GX::TEV_KCSEL_K2);
GXSetTevColorS10(GX::TEVREG0, 0xffa60000ff8e0087u);
CGX::SetTevKColor(GX::KCOLOR0, zeus::Comp32(0x0000e258));
CGX::SetTevKColor(GX::KCOLOR1, zeus::Comp32(0xb30000b6));
CGX::SetTevKColor(GX::KCOLOR2, zeus::Comp32(0xff00ff80));
}
static void MyTHPGXRestore() {
CGX::SetZMode(true, GX::ALWAYS, false);
CGX::SetBlendMode(GX::BM_NONE, GX::BL_ONE, GX::BL_ZERO, GX::LO_SET);
CGX::SetNumTexGens(1);
CGX::SetNumChans(0);
CGX::SetNumTevStages(1);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL);
CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0);
}
/* used in the original to look up fixed-point dividends on a
* MIDI-style volume scale (0-127) -> (n/0x8000) */
static const std::array<u16, 128> StaticVolumeLookup = {
@ -359,29 +464,92 @@ void CMoviePlayer::Rewind() {
xe8_curSeconds = 0.f;
}
void CMoviePlayer::Draw() {
bool CMoviePlayer::DrawVideo() {
// TODO
// if (!xa0_bufferQueue.empty()) {
// return false;
// }
g_Renderer->SetDepthReadWrite(false, false);
g_Renderer->SetViewportOrtho(false, -4096.f, 4096.f);
const s32 vpHeight = CGraphics::GetViewportHeight();
const s32 vpWidth = CGraphics::GetViewportWidth();
const s32 vpTop = CGraphics::GetViewportTop();
const s32 vpLeft = CGraphics::GetViewportLeft();
const s32 vidWidth = x6c_videoInfo.width;
const s32 vidHeight = x6c_videoInfo.height;
const s32 centerX = (vidWidth - vpWidth) / 2;
const s32 centerY = (vidHeight - vpHeight) / 2;
const s32 vl = vpLeft - centerX;
const s32 vr = vpLeft + vpWidth + centerX;
const s32 vb = vpTop + vpHeight + centerY;
const s32 vt = vpTop - centerY;
aurora::Vec3<float> v1;
aurora::Vec3<float> v2;
aurora::Vec3<float> v3;
aurora::Vec3<float> v4;
v1.x = vl;
v1.y = 0.0;
v1.z = vb;
v2.x = vr;
v2.y = 0.0;
v2.z = vb;
v3.x = vl;
v3.y = 0.0;
v3.z = vt;
v4.x = vr;
v4.y = 0.0;
v4.z = vt;
DrawFrame(v1, v2, v3, v4);
return true;
}
void CMoviePlayer::DrawFrame(const zeus::CVector3f& v1, const zeus::CVector3f& v2, const zeus::CVector3f& v3,
const zeus::CVector3f& v4) {
if (xd0_drawTexSlot == UINT32_MAX || !GetIsFullyCached()) {
return;
}
SCOPED_GRAPHICS_DEBUG_GROUP("CMoviePlayer::DrawFrame", zeus::skYellow);
/* Correct movie aspect ratio */
float hPad, vPad;
if (CGraphics::GetViewportAspect() >= 1.78f) {
hPad = 1.78f / CGraphics::GetViewportAspect();
vPad = 1.78f / 1.33f;
} else {
hPad = 1.f;
vPad = CGraphics::GetViewportAspect() / 1.33f;
}
CGraphics::SetUseVideoFilter(xf4_26_fieldFlip);
/* draw appropriate field */
CTHPTextureSet& tex = x80_textures[xd0_drawTexSlot];
aurora::gfx::queue_movie_player(tex.Y[m_deinterlace ? (xfc_fieldIndex != 0) : 0], tex.U, tex.V, hPad, vPad);
/* Correct movie aspect ratio */
// float hPad, vPad;
// if (CGraphics::GetViewportAspect() >= 1.78f) {
// hPad = 1.78f / CGraphics::GetViewportAspect();
// vPad = 1.78f / 1.33f;
// } else {
// hPad = 1.f;
// vPad = CGraphics::GetViewportAspect() / 1.33f;
// }
//
// /* draw appropriate field */
// CTHPTextureSet& tex = x80_textures[xd0_drawTexSlot];
// aurora::gfx::queue_movie_player(tex.Y[m_deinterlace ? (xfc_fieldIndex != 0) : 0], tex.U, tex.V, hPad, vPad);
MyTHPGXYuv2RgbSetup(CGraphics::g_LastFrameUsedAbove, xf4_26_fieldFlip);
uintptr_t planeSize = x6c_videoInfo.width * x6c_videoInfo.height;
uintptr_t planeSizeQuarter = planeSize / 4;
MyTHPYuv2RgbTextureSetup(m_yuvBuf.get(), m_yuvBuf.get() + planeSize, m_yuvBuf.get() + planeSize + planeSizeQuarter,
x6c_videoInfo.width, x6c_videoInfo.height);
CGX::Begin(GX::TRIANGLEFAN, GX::VTXFMT7, 4);
GXPosition3f32(v1);
GXTexCoord2f32(0.f, 0.f);
GXPosition3f32(v3);
GXTexCoord2f32(0.f, 1.f);
GXPosition3f32(v4);
GXTexCoord2f32(1.f, 1.f);
GXPosition3f32(v2);
GXTexCoord2f32(1.f, 0.f);
CGX::End();
MyTHPGXRestore();
/* ensure second field is being displayed by VI to signal advance
* (faked in metaforce with continuous xor) */
if (!xfc_fieldIndex && CGraphics::g_LastFrameUsedAbove)
if (xfc_fieldIndex == 0 && CGraphics::g_LastFrameUsedAbove)
xf4_26_fieldFlip = true;
++xfc_fieldIndex;
@ -487,29 +655,29 @@ void CMoviePlayer::DecodeFromRead(const void* data) {
tjDecompressToYUV(TjHandle, (u8*)inptr, frameHeader.imageSize, m_yuvBuf.get(), 0);
inptr += frameHeader.imageSize;
uintptr_t planeSize = x6c_videoInfo.width * x6c_videoInfo.height;
uintptr_t planeSizeHalf = planeSize / 2;
uintptr_t planeSizeQuarter = planeSizeHalf / 2;
// uintptr_t planeSize = x6c_videoInfo.width * x6c_videoInfo.height;
// uintptr_t planeSizeHalf = planeSize / 2;
// uintptr_t planeSizeQuarter = planeSizeHalf / 2;
if (m_deinterlace) {
/* Deinterlace into 2 discrete 60-fps half-res textures */
auto buffer = std::make_unique<u8[]>(planeSizeHalf);
for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2),
x6c_videoInfo.width);
}
aurora::gfx::write_texture(*tex.Y[0], {buffer.get(), planeSizeHalf});
for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2 + 1),
x6c_videoInfo.width);
}
aurora::gfx::write_texture(*tex.Y[1], {buffer.get(), planeSizeHalf});
} else {
/* Direct planar load */
aurora::gfx::write_texture(*tex.Y[0], {m_yuvBuf.get(), planeSize});
}
aurora::gfx::write_texture(*tex.U, {m_yuvBuf.get() + planeSize, planeSizeQuarter});
aurora::gfx::write_texture(*tex.V, {m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter});
// if (m_deinterlace) {
// /* Deinterlace into 2 discrete 60-fps half-res textures */
// auto buffer = std::make_unique<u8[]>(planeSizeHalf);
// for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
// memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2),
// x6c_videoInfo.width);
// }
// aurora::gfx::write_texture(*tex.Y[0], {buffer.get(), planeSizeHalf});
// for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
// memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2 + 1),
// x6c_videoInfo.width);
// }
// aurora::gfx::write_texture(*tex.Y[1], {buffer.get(), planeSizeHalf});
// } else {
// /* Direct planar load */
// aurora::gfx::write_texture(*tex.Y[0], {m_yuvBuf.get(), planeSize});
// }
// aurora::gfx::write_texture(*tex.U, {m_yuvBuf.get() + planeSize, planeSizeQuarter});
// aurora::gfx::write_texture(*tex.V, {m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter});
break;
}

View File

@ -136,9 +136,12 @@ public:
float GetPlayedSeconds() const { return xdc_frameRem + xe8_curSeconds; }
float GetTotalSeconds() const { return xe4_totalSeconds; }
void SetPlayMode(EPlayMode mode) { xe0_playMode = mode; }
void Draw();
bool DrawVideo();
void DrawFrame(const zeus::CVector3f& v1, const zeus::CVector3f& v2, const zeus::CVector3f& v3,
const zeus::CVector3f& v4);
void Update(float dt);
std::pair<u32, u32> GetVideoDimensions() const { return {x6c_videoInfo.width, x6c_videoInfo.height}; }
u32 GetWidth() const { return x6c_videoInfo.width; }
u32 GetHeight() const { return x6c_videoInfo.width; }
static void Initialize();
static void Shutdown();

View File

@ -19,29 +19,40 @@ zeus::CAABox CSimpleShadow::GetMaxShadowBox(const zeus::CAABox& aabb) const {
zeus::CAABox CSimpleShadow::GetBounds() const {
float extent = x34_radius * x30_scale;
return {{x0_xf.origin.x() - extent, x0_xf.origin.y() - extent, x0_xf.origin.z() - extent},
{x0_xf.origin.x() + extent, x0_xf.origin.y() + extent, x0_xf.origin.z() + extent}};
return {
{x0_xf.origin.x() - extent, x0_xf.origin.y() - extent, x0_xf.origin.z() - extent},
{x0_xf.origin.x() + extent, x0_xf.origin.y() + extent, x0_xf.origin.z() + extent},
};
}
void CSimpleShadow::Render(const TLockedToken<CTexture>& tex) {
void CSimpleShadow::Render(TLockedToken<CTexture>& tex) {
if (!x48_24_collision)
return;
SCOPED_GRAPHICS_DEBUG_GROUP("CSimpleShadow::Render", zeus::skGrey);
CGraphics::DisableAllLights();
CGraphics::SetModelMatrix(x0_xf);
tex->Load(GX::TEXMAP0, EClampMode::Repeat);
//if (!m_filter || m_filter->GetTex().GetObj() != tex.GetObj())
//m_filter.emplace(EFilterType::InvDstMultiply, tex, CTexturedQuadFilter::ZTest::LEqual);
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha,
ERglLogicOp::Clear);
CGraphics::StreamBegin(GX::QUADS);
float radius = x34_radius * x30_scale;
const std::array<CTexturedQuadFilter::Vert, 4> verts{{
{{-radius, 0.f, -radius}, {0.f, 0.f}},
{{radius, 0.f, -radius}, {0.f, 1.f}},
{{-radius, 0.f, radius}, {1.f, 0.f}},
{{radius, 0.f, radius}, {1.f, 1.f}},
}};
//m_filter->drawVerts(zeus::skWhite, verts);
float t = x3c_heightAlpha * x38_userAlpha;
CGraphics::StreamColor(zeus::CColor{t, t} /* TODO double check */);
CGraphics::StreamTexcoord(0.f, 0.f);
CGraphics::StreamVertex(-radius, 0.f, -radius);
CGraphics::StreamTexcoord(0.f, 1.f);
CGraphics::StreamVertex(radius, 0.f, -radius);
CGraphics::StreamTexcoord(1.f, 1.f);
CGraphics::StreamVertex(radius, 0.f, radius);
CGraphics::StreamTexcoord(1.f, 0.f);
CGraphics::StreamVertex(-radius, 0.f, radius);
CGraphics::StreamEnd();
}
void CSimpleShadow::Calculate(const zeus::CAABox& aabb, const zeus::CTransform& xf, const CStateManager& mgr) {

View File

@ -1,8 +1,9 @@
#pragma once
#include <optional>
#include "Runtime/CToken.hpp"
#include "Runtime/Graphics/CTexture.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include <optional>
#include <zeus/CAABox.hpp>
#include <zeus/CTransform.hpp>
@ -22,7 +23,6 @@ class CSimpleShadow {
bool x48_24_collision : 1 = false;
bool x48_25_alwaysCalculateRadius : 1 = true;
bool x48_26_radiusCalculated : 1 = false;
std::optional<CTexturedQuadFilter> m_filter;
public:
CSimpleShadow(float scale, float userAlpha, float maxObjHeight, float displacement);
@ -33,7 +33,7 @@ public:
float GetMaxObjectHeight() const { return x40_maxObjHeight; }
void SetUserAlpha(float a) { x38_userAlpha = a; }
const zeus::CTransform& GetTransform() const { return x0_xf; }
void Render(const TLockedToken<CTexture>& tex);
void Render(TLockedToken<CTexture>& tex);
void Calculate(const zeus::CAABox& aabb, const zeus::CTransform& xf, const CStateManager& mgr);
};
} // namespace metaforce

View File

@ -741,6 +741,19 @@ enum DistAttnFn {
using GXColor = zeus::CColor;
using GXBool = bool;
struct GXColorS10 {
s16 r;
s16 g;
s16 b;
s16 a;
constexpr GXColorS10(u64 c) noexcept
: r(static_cast<s16>((c >> 48) & 0xFFFF))
, g(static_cast<s16>((c >> 32) & 0xFFFF))
, b(static_cast<s16>((c >> 16) & 0xFFFF))
, a(static_cast<s16>(c & 0xFFFF)) {}
};
enum GXTlutFmt {
GX_TL_IA8 = 0x0,
GX_TL_RGB565 = 0x1,
@ -845,7 +858,9 @@ void GXSetCullMode(GX::CullMode mode) noexcept;
void GXSetBlendMode(GX::BlendMode mode, GX::BlendFactor src, GX::BlendFactor dst, GX::LogicOp op) noexcept;
void GXSetZMode(GXBool compare_enable, GX::Compare func, GXBool update_enable) noexcept;
void GXSetTevColor(GX::TevRegID id, const GXColor& color) noexcept;
void GXSetTevColorS10(GX::TevRegID id, const GXColorS10& color) noexcept;
void GXSetTevKColor(GX::TevKColorID id, const GXColor& color) noexcept;
void GXSetColorUpdate(GXBool enabled) noexcept;
void GXSetAlphaUpdate(GXBool enabled) noexcept;
void GXSetDstAlpha(GXBool enabled, u8 value) noexcept;
void GXSetCopyClear(const GXColor& color, float depth) noexcept;
@ -898,7 +913,7 @@ void GXInitTexObj(GXTexObj* obj, const void* data, u16 width, u16 height, GX::Te
GXTexWrapMode wrapT, GXBool mipmap) noexcept;
// Addition for binding render textures
void GXInitTexObjResolved(GXTexObj* obj, u32 bindIdx, GX::TextureFormat format, GXTexWrapMode wrapS,
GXTexWrapMode wrapT);
GXTexWrapMode wrapT, GXTlut tlut);
void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter minFilt, GXTexFilter magFilt, float minLod, float maxLod, float lodBias,
GXBool biasClamp, GXBool doEdgeLod, GXAnisotropy maxAniso) noexcept;
void GXInitTexObjCI(GXTexObj* obj, void* data, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrapS,
@ -912,6 +927,7 @@ void GXSetTexCopyDst(u16 wd, u16 ht, GX::TextureFormat fmt, GXBool mipmap) noexc
u32 GXGetTexBufferSize(u16 width, u16 height, u32 fmt, GXBool mips, u8 maxLod) noexcept;
void GXCopyTex(void* dest, GXBool clear) noexcept;
static inline void GXPixModeSync() noexcept {} // no-op
void GXInvalidateTexAll() noexcept;
void GXSetIndTexMtx(GX::IndTexMtxID id, const void* mtx /* Mat4x2<float> */, s8 scaleExp) noexcept;
void GXSetTevIndirect(GX::TevStageID tevStage, GX::IndTexStageID indStage, GX::IndTexFormat fmt,
GX::IndTexBiasSel biasSel, GX::IndTexMtxID matrixSel, GX::IndTexWrap wrapS, GX::IndTexWrap wrapT,

View File

@ -76,10 +76,10 @@ void CWorldShadowShader::lightenShadow() {
void CWorldShadowShader::blendPreviousShadow() {
SCOPED_GRAPHICS_DEBUG_GROUP("CWorldShadowShader::blendPreviousShadow", zeus::skMagenta);
if (!m_prevQuad)
m_prevQuad.emplace(EFilterType::Blend, m_tex);
zeus::CRectangle rect(0.f, 1.f, 1.f, -1.f);
m_prevQuad->draw({1.f, 0.85f}, 1.f, rect);
// if (!m_prevQuad)
// m_prevQuad.emplace(EFilterType::Blend, m_tex);
// zeus::CRectangle rect(0.f, 1.f, 1.f, -1.f);
// m_prevQuad->draw({1.f, 0.85f}, 1.f, rect);
}
void CWorldShadowShader::resolveTexture() {

View File

@ -3,7 +3,6 @@
#include <optional>
#include "Runtime/GCNTypes.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
//#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
@ -13,8 +12,8 @@
namespace metaforce {
class CWorldShadowShader {
aurora::gfx::TextureHandle m_tex;
std::optional<CTexturedQuadFilter> m_prevQuad;
// aurora::gfx::TextureHandle m_tex;
// std::optional<CTexturedQuadFilter> m_prevQuad;
u32 m_w, m_h;
struct Uniform {
@ -40,7 +39,7 @@ public:
u32 GetWidth() const { return m_w; }
u32 GetHeight() const { return m_h; }
const aurora::gfx::TextureHandle& GetTexture() const { return m_tex; }
// const aurora::gfx::TextureHandle& GetTexture() const { return m_tex; }
};
} // namespace metaforce

View File

@ -4,7 +4,6 @@
#include "Runtime/CToken.hpp"
#include "Runtime/rstl.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/GuiSys/CGuiWidget.hpp"
#include <zeus/CVector2f.hpp>

View File

@ -322,8 +322,9 @@ void CHudDecoInterfaceScan::Update(float dt, const CStateManager& stateMgr) {
}
void CHudDecoInterfaceScan::Draw() {
SCOPED_GRAPHICS_DEBUG_GROUP("CHudDecoInterfaceScan::Draw", zeus::skGreen);
x18_scanDisplay.Draw();
if (x10_loadedScanHudFlat) {
if (x10_loadedScanHudFlat != nullptr) {
x10_loadedScanHudFlat->Draw(CGuiWidgetDrawParms::Default());
}
}

View File

@ -36,23 +36,25 @@ void CScanDisplay::CDataDot::Update(float dt) {
}
void CScanDisplay::CDataDot::Draw(const zeus::CColor& col, float radius) {
if (x24_alpha == 0.f) {
if (x24_alpha == 0.f || x0_dotState == EDotState::Hidden) {
return;
}
if (x0_dotState != EDotState::Hidden) {
const zeus::CTransform xf = zeus::CTransform::Translate(xc_curPos.x(), 0.f, xc_curPos.y());
CGraphics::SetModelMatrix(xf);
zeus::CColor useColor = col;
useColor.a() *= x24_alpha;
const std::array<CTexturedQuadFilter::Vert, 4> verts{{
{{-radius, 0.f, radius}, {0.f, 1.f}},
{{-radius, 0.f, -radius}, {0.f, 0.f}},
{{radius, 0.f, radius}, {1.f, 1.f}},
{{radius, 0.f, -radius}, {1.f, 0.f}},
}};
m_quad.drawVerts(useColor, verts);
}
const zeus::CTransform xf = zeus::CTransform::Translate(xc_curPos.x(), 0.f, xc_curPos.y());
g_Renderer->SetModelMatrix(xf);
CGraphics::StreamBegin(GX::TRIANGLESTRIP);
zeus::CColor useColor = col;
useColor.a() *= x24_alpha;
CGraphics::StreamColor(useColor);
CGraphics::StreamTexcoord(0.f, 1.f);
CGraphics::StreamVertex(-radius, 0.f, radius);
CGraphics::StreamTexcoord(0.f, 0.f);
CGraphics::StreamVertex(-radius, 0.f, -radius);
CGraphics::StreamTexcoord(1.f, 1.f);
CGraphics::StreamVertex(radius, 0.f, radius);
CGraphics::StreamTexcoord(1.f, 0.f);
CGraphics::StreamVertex(radius, 0.f, -radius);
CGraphics::StreamEnd();
}
void CScanDisplay::CDataDot::StartTransitionTo(const zeus::CVector2f& vec, float dur) {
@ -444,10 +446,13 @@ void CScanDisplay::Draw() {
if (!x0_dataDot.IsLoaded()) {
return;
}
SCOPED_GRAPHICS_DEBUG_GROUP("CScanDisplay::Draw", zeus::skGreen);
// No Z-test or write
g_Renderer->SetDepthReadWrite(false, false);
g_Renderer->SetViewportOrtho(true, -4096.f, 4096.f);
// Additive alpha
g_Renderer->SetBlendMode_AdditiveAlpha();
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
x0_dataDot->Load(GX::TEXMAP0, EClampMode::Repeat);
const float vpRatio = CGraphics::GetViewportHeight() / 480.f;
for (CDataDot& dot : xbc_dataDots) {

View File

@ -8,7 +8,6 @@
#include "Runtime/rstl.hpp"
#include "Runtime/Camera/CCameraFilter.hpp"
#include "Runtime/Graphics/CTexture.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include <zeus/CColor.hpp>
#include <zeus/CQuaternion.hpp>
@ -40,10 +39,9 @@ public:
float x20_remTime = 0.f;
float x24_alpha = 0.f;
float x28_desiredAlpha = 0.f;
CTexturedQuadFilter m_quad;
public:
explicit CDataDot(const TLockedToken<CTexture>& dataDotTex) : m_quad(EFilterType::Add, dataDotTex) {}
explicit CDataDot(const TLockedToken<CTexture>& dataDotTex) {}
void Update(float dt);
void Draw(const zeus::CColor& color, float radius);
float GetTransitionFactor() const { return x1c_transDur > 0.f ? x20_remTime / x1c_transDur : 0.f; }

View File

@ -3,7 +3,6 @@
#include "Runtime/CIOWin.hpp"
#include "Runtime/CToken.hpp"
#include "Runtime/Graphics/CTexture.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
namespace metaforce {

View File

@ -198,20 +198,17 @@ CIOWin::EMessageReturn CCredits::ProcessUserInput(const CFinalInput& input) {
}
void CCredits::DrawVideo() {
if (x28_) {
/* Render movie */
x28_->Draw();
if (x5c_27_ || x5c_28_) {
float alpha = x58_ / g_tweakGui->x310_;
if (x5c_27_) {
alpha = 1.f - alpha;
}
alpha = zeus::clamp(0.f, alpha, 1.f);
zeus::CColor filterCol = zeus::skBlack;
filterCol.a() = alpha;
CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::Fullscreen, filterCol, nullptr, 1.f);
/* Render movie */
if (x28_ && x28_->DrawVideo() && (x5c_27_ || x5c_28_)) {
float alpha = x58_ / g_tweakGui->x310_;
if (x5c_27_) {
alpha = 1.f - alpha;
}
alpha = zeus::clamp(0.f, alpha, 1.f);
zeus::CColor filterCol = zeus::skBlack;
filterCol.a() = alpha;
CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::Fullscreen, filterCol, nullptr, 1.f);
}
}

View File

@ -16,30 +16,26 @@ void CFaceplateDecoration::Update(float dt, CStateManager& stateMgr) {
if (xc_ready) {
x4_tex.Unlock();
x0_id = txtrId;
if (m_texFilter)
m_texFilter = std::nullopt;
}
}
if (x0_id != txtrId && txtrId.IsValid()) {
if (m_texFilter)
m_texFilter = std::nullopt;
x0_id = txtrId;
x4_tex = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), txtrId});
xc_ready = true;
x4_tex.Lock();
}
if (!m_texFilter && x4_tex.IsLoaded())
m_texFilter.emplace(EFilterType::Blend, x4_tex);
}
void CFaceplateDecoration::Draw(CStateManager& stateMgr) {
if (xc_ready && m_texFilter) {
if (xc_ready && x4_tex) {
SCOPED_GRAPHICS_DEBUG_GROUP("CFaceplateDecoration::Draw", zeus::skPurple);
zeus::CColor color = zeus::skWhite;
color.a() = stateMgr.GetPlayer().GetVisorSteam().GetAlpha();
m_texFilter->DrawFilter(EFilterShape::FullscreenQuarters, color, 1.f);
float alpha = stateMgr.GetPlayer().GetVisorSteam().GetAlpha();
if (!zeus::close_enough(alpha, 0.f)) {
zeus::CColor color = zeus::skWhite;
color.a() = alpha;
CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::FullscreenQuarters, color, x4_tex.GetObj(), 1.f);
}
}
}

View File

@ -4,7 +4,7 @@
#include "Runtime/CToken.hpp"
#include "Runtime/RetroTypes.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/Graphics/CTexture.hpp"
namespace metaforce {
class CStateManager;
@ -15,7 +15,6 @@ class CFaceplateDecoration {
CAssetId x0_id;
TToken<CTexture> x4_tex;
bool xc_ready = false;
std::optional<CTexturedQuadFilter> m_texFilter;
public:
explicit CFaceplateDecoration(CStateManager& stateMgr);

View File

@ -1805,7 +1805,7 @@ void CFrontEndUI::Draw() {
} else {
if ((xcc_curMoviePtr != nullptr)) {
/* Render movie */
xcc_curMoviePtr->Draw();
xcc_curMoviePtr->DrawVideo();
}
if (x50_curScreen == EScreen::FileSelect && x54_nextScreen == EScreen::FileSelect) {

View File

@ -11,8 +11,6 @@
#include "Runtime/Audio/CSfxManager.hpp"
#include "Runtime/Audio/CStaticAudioPlayer.hpp"
#include "Runtime/Camera/CCameraFilter.hpp"
#include "Runtime/Graphics/Shaders/CColoredQuadFilter.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/GuiSys/CGuiTextSupport.hpp"
#include "Runtime/Input/CRumbleGenerator.hpp"
#include "Runtime/MP1/CGBASupport.hpp"

View File

@ -601,6 +601,7 @@ void CInGameGuiManager::Draw(CStateManager& stateMgr) {
float z = 0.5f * (zT * zT * zT * zT * zT * (CGraphics::GetViewportHeight() - 12.f) + 12.f);
float x = 0.5f * (xT * (CGraphics::GetViewportWidth() - 12.f) + 12.f);
// TODO
// const std::array<CTexturedQuadFilter::Vert, 4> verts{{
// {{-x, 0.f, z}, {0.f, 0.f}},
// {{-x, 0.f, -z}, {0.f, 1.f}},

View File

@ -214,7 +214,8 @@ void CMFGame::Draw() {
if (x1c_flowState == EGameFlowState::CinematicSkip) {
const float c = std::min(1.f, 1.f - x20_cineSkipTime);
m_fadeToBlack.draw(zeus::CColor{c, c, c, c});
CCameraFilterPass::DrawFilter(EFilterType::Multiply, EFilterShape::Fullscreen, zeus::CColor{c, c, c, c}, nullptr,
1.f);
}
}

View File

@ -5,7 +5,6 @@
#include "Runtime/CMFGameBase.hpp"
#include "Runtime/Camera/CCameraFilter.hpp"
#include "Runtime/Graphics/Shaders/CColoredQuadFilter.hpp"
#include "Runtime/MP1/CInGameGuiManager.hpp"
namespace metaforce {
@ -26,8 +25,6 @@ class CMFGame : public CMFGameBase {
bool x2a_24_initialized : 1 = false;
bool x2a_25_samusAlive : 1 = true;
CColoredQuadFilter m_fadeToBlack{EFilterType::Multiply};
bool IsCameraActiveFlow() const {
return (x1c_flowState == EGameFlowState::InGame || x1c_flowState == EGameFlowState::SamusDied);
}

View File

@ -85,12 +85,15 @@ void CPauseScreenBlur::Update(float dt, const CStateManager& stateMgr, bool b) {
void CPauseScreenBlur::Draw(const CStateManager&) {
SCOPED_GRAPHICS_DEBUG_GROUP("CPauseScreenBlur::Draw", zeus::skPurple);
x1c_camBlur.Draw(true);
CGraphics::DisableAllLights();
CGraphics::SetAmbientColor(zeus::skWhite);
const float t = std::fabs(x18_blurAmt);
if (x1c_camBlur.GetCurrType() != EBlurType::NoBlur) {
const auto filterColor = zeus::CColor::lerp(zeus::skWhite, g_tweakGuiColors->GetPauseBlurFilterColor(), t);
m_quarterFilter.DrawFilter(EFilterShape::FullscreenQuarters, filterColor, t);
CCameraFilterPass::DrawFilter(EFilterType::Multiply, EFilterShape::FullscreenQuarters, filterColor,
x4_mapLightQuarter.GetObj(), t);
const auto scanLinesColor = zeus::CColor::lerp(zeus::skWhite, zeus::CColor(0.75f, 1.f), t);
m_linesFilter.draw(scanLinesColor);
CCameraFilterPass::DrawFilter(EFilterType::Multiply, EFilterShape::ScanLinesEven, scanLinesColor, nullptr, t);
}
if (x50_24_blurring /*&& x1c_camBlur.x2d_noPersistentCopy*/) {

View File

@ -3,8 +3,6 @@
#include "Runtime/CToken.hpp"
#include "Runtime/Camera/CCameraFilter.hpp"
#include "Runtime/Graphics/CTexture.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/Graphics/Shaders/CScanLinesFilter.hpp"
#include "Runtime/MP1/CInGameGuiManagerCommon.hpp"
namespace metaforce {
@ -23,9 +21,6 @@ class CPauseScreenBlur {
bool x50_24_blurring : 1 = false;
bool x50_25_gameDraw : 1 = true;
CTexturedQuadFilter m_quarterFilter{EFilterType::Multiply, x4_mapLightQuarter};
CScanLinesFilterEven m_linesFilter{EFilterType::Multiply};
void OnBlurComplete(bool);
void SetState(EState state);

View File

@ -4,9 +4,10 @@
namespace metaforce::MP1 {
const char* kMovies[] = {"Video/wingame.thp", "Video/wingame_good.thp", "Video/wingame_best.thp",
"Video/losegame.thp", "Video/05_tallonText.thp", "Video/AfterCredits.thp",
"Video/SpecialEnding.thp", "Video/creditBG.thp"};
const char* kMovies[] = {
"Video/wingame.thp", "Video/wingame_good.thp", "Video/wingame_best.thp", "Video/losegame.thp",
"Video/05_tallonText.thp", "Video/AfterCredits.thp", "Video/SpecialEnding.thp", "Video/creditBG.thp",
};
bool CPlayMovie::IsResultsScreen(EWhichMovie which) { return int(which) <= 2; }
@ -15,6 +16,7 @@ CPlayMovie::CPlayMovie(EWhichMovie which) : CIOWin("CPlayMovie"), x18_which(whic
CIOWin::EMessageReturn CPlayMovie::OnMessage(const CArchitectureMessage& msg, CArchitectureQueue& queue) {
return EMessageReturn::RemoveIOWinAndExit;
}
void CPlayMovie::Draw() {
if (x14_ != 3) {
return;
@ -28,7 +30,14 @@ void CPlayMovie::Draw() {
}
}
void CPlayMovie::DrawVideo() {}
void CPlayMovie::DrawText() {}
void CPlayMovie::DrawVideo() {
if (x38_moviePlayer) {
x38_moviePlayer->DrawVideo();
}
}
void CPlayMovie::DrawText() {
// TODO
}
} // namespace metaforce::MP1

View File

@ -355,9 +355,6 @@ void CPlayerVisor::DrawScanEffect(const CStateManager& mgr, CTargetingManager* t
rect.x10_height = int(vpH);
CGraphics::ResolveSpareTexture(rect, 0, GX::TF_RGB565);
// TODO hack; figure out why needed
CGraphics::SetCullMode(ERglCullMode::None);
{
SCOPED_GRAPHICS_DEBUG_GROUP("x64_scanDim Draw", zeus::skMagenta);
x64_scanDim.Draw();

View File

@ -4,8 +4,6 @@
#include "Runtime/CPlayerState.hpp"
#include "Runtime/Camera/CCameraFilter.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/Graphics/Shaders/CColoredQuadFilter.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/RetroTypes.hpp"
#include "Runtime/rstl.hpp"

View File

@ -86,7 +86,7 @@ EQuitAction CQuitGameScreen::Update(float dt) {
void CQuitGameScreen::Draw() {
SCOPED_GRAPHICS_DEBUG_GROUP("CQuitGameScreen::Draw", zeus::skPurple);
if (x0_type == EQuitType::QuitGame) {
m_blackScreen->draw(zeus::CColor(0.f, 0.5f));
CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::Fullscreen, zeus::CColor{0.f, 0.5f}, nullptr, 1.f);
}
if (x10_loadedFrame) {
@ -111,10 +111,6 @@ void CQuitGameScreen::ProcessUserInput(const CFinalInput& input) {
}
}
CQuitGameScreen::CQuitGameScreen(EQuitType tp) : x0_type(tp) {
x4_frame = g_SimplePool->GetObj("FRME_QuitScreen");
if (tp == EQuitType::QuitGame)
m_blackScreen.emplace(EFilterType::Blend);
}
CQuitGameScreen::CQuitGameScreen(EQuitType tp) : x0_type(tp) { x4_frame = g_SimplePool->GetObj("FRME_QuitScreen"); }
} // namespace metaforce::MP1

View File

@ -4,7 +4,6 @@
#include "Runtime/CToken.hpp"
#include "Runtime/RetroTypes.hpp"
#include "Runtime/Graphics/Shaders/CColoredQuadFilter.hpp"
#include "Runtime/GuiSys/CGuiFrame.hpp"
namespace metaforce {
@ -25,7 +24,7 @@ class CQuitGameScreen {
CGuiFrame* x10_loadedFrame = nullptr;
CGuiTableGroup* x14_tablegroup_quitgame = nullptr;
EQuitAction x18_action = EQuitAction::None;
std::optional<CColoredQuadFilter> m_blackScreen;
void SetColors();
public:

View File

@ -12,6 +12,7 @@
#include "Runtime/World/CGameLight.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "Runtime/World/CScriptTrigger.hpp"
#include "Runtime/Graphics/CCubeRenderer.hpp"
#include "TCastTo.hpp" // Generated file, do not modify include path
@ -23,8 +24,7 @@ CSamusHud::CSamusHud(CStateManager& stateMgr)
: x8_targetingMgr(stateMgr)
, x258_frmeHelmet(g_SimplePool->GetObj("FRME_Helmet"))
, x268_frmeBaseHud(g_SimplePool->GetObj("FRME_BaseHud"))
, x2e0_27_energyLow(stateMgr.GetPlayer().IsEnergyLow(stateMgr))
, m_energyDrainFilter(g_tweakGui->GetEnergyDrainFilterAdditive() ? EFilterType::Add : EFilterType::Blend) {
, x2e0_27_energyLow(stateMgr.GetPlayer().IsEnergyLow(stateMgr)) {
x33c_lights = std::make_unique<CActorLights>(8, zeus::skZero3f, 4, 1, true, 0, 0, 0.1f);
x340_hudLights.resize(3, SCachedHudLight(zeus::skZero3f, zeus::skWhite, 0.f, 0.f, 0.f, 0.f));
x46c_.resize(3);
@ -1387,7 +1387,8 @@ void CSamusHud::DrawAttachedEnemyEffect(const CStateManager& mgr) {
zeus::CColor filterColor = g_tweakGuiColors->GetEnergyDrainFilterColor();
filterColor.a() *= alpha;
m_energyDrainFilter.draw(filterColor);
EFilterType filterType = g_tweakGui->GetEnergyDrainFilterAdditive() ? EFilterType::Add : EFilterType::Blend;
CCameraFilterPass::DrawFilter(filterType, EFilterShape::Fullscreen, filterColor, nullptr, 1.f);
}
void CSamusHud::Draw(const CStateManager& mgr, float alpha, CInGameGuiManager::EHelmetVisMode helmetVis, bool hudVis,
@ -1408,7 +1409,8 @@ void CSamusHud::Draw(const CStateManager& mgr, float alpha, CInGameGuiManager::E
if (helmetVis != CInGameGuiManager::EHelmetVisMode::ReducedUpdate &&
helmetVis < CInGameGuiManager::EHelmetVisMode::HelmetOnly) {
if (alpha < 1.f) {
m_cookieCutterStatic.draw(zeus::skWhite, 1.f - alpha);
CCameraFilterPass::DrawFilter(EFilterType::NoColor, EFilterShape::CookieCutterDepthRandomStatic, zeus::skWhite,
nullptr, 1.f - alpha);
}
if (x288_loadedSelectedHud) {
@ -1447,8 +1449,10 @@ void CSamusHud::Draw(const CStateManager& mgr, float alpha, CInGameGuiManager::E
}
x2ac_radarIntf->Draw(mgr, t * alpha);
}
// Depth read/write enable
g_Renderer->SetDepthReadWrite(true, true);
}
// TODO timer stuff?
}
void CSamusHud::DrawHelmet(const CStateManager& mgr, float camYOff) {

View File

@ -166,9 +166,6 @@ class CSamusHud {
std::array<float, 32> x72c_camZTweaks;
rstl::reserved_vector<SProfileInfo, 15> x7ac_;
CColoredQuadFilter m_energyDrainFilter;
CCookieCutterDepthRandomStaticFilter m_cookieCutterStatic{EFilterType::NoColor};
static CSamusHud* g_SamusHud;
static rstl::reserved_vector<bool, 4> BuildPlayerHasVisors(const CStateManager& mgr);
static rstl::reserved_vector<bool, 4> BuildPlayerHasBeams(const CStateManager& mgr);

View File

@ -120,15 +120,16 @@ CIOWin::EMessageReturn CSlideShow::OnMessage(const CArchitectureMessage& msg, CA
}
void CSlideShow::SSlideData::Draw() {
if (!IsLoaded()) {
return;
}
const zeus::CRectangle rect;
m_texQuad->draw(x30_mulColor, 1.f, rect);
const zeus::CVector2f centeredOffset((x28_canvasSize.x() - m_texQuad->GetTex()->GetWidth()) * 0.5f,
(x28_canvasSize.y() - m_texQuad->GetTex()->GetHeight()) * 0.5f);
// TODO
// if (!IsLoaded()) {
// return;
// }
//
// const zeus::CRectangle rect;
// m_texQuad->draw(x30_mulColor, 1.f, rect);
//
// const zeus::CVector2f centeredOffset((x28_canvasSize.x() - m_texQuad->GetTex()->GetWidth()) * 0.5f,
// (x28_canvasSize.y() - m_texQuad->GetTex()->GetHeight()) * 0.5f);
}
void CSlideShow::Draw() {

View File

@ -10,7 +10,6 @@
#include "Runtime/RetroTypes.hpp"
#include "Runtime/Audio/CSfxManager.hpp"
#include "Runtime/Camera/CCameraFilter.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/GuiSys/CGuiTextSupport.hpp"
#include <zeus/CColor.hpp>
@ -27,7 +26,6 @@ public:
u32 x4_ = -1;
u32 x8_ = -1;
std::optional<CTexturedQuadFilterAlpha> m_texQuad;
zeus::CVector2f x18_vpOffset;
zeus::CVector2f x20_vpSize;
zeus::CVector2f x28_canvasSize;
@ -35,8 +33,6 @@ public:
explicit SSlideData(CSlideShow& parent) : x0_parent(parent) { x30_mulColor.a() = 0.f; }
void SetTexture(const TLockedToken<CTexture>& tex) { m_texQuad.emplace(EFilterType::Blend, tex); }
bool IsLoaded() const { return m_texQuad && m_texQuad->GetTex().IsLoaded(); }
void Draw();
};

View File

@ -7,6 +7,7 @@
#include "Runtime/CSimplePool.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CCubeRenderer.hpp"
#include "Runtime/Graphics/CGX.hpp"
#include "Runtime/Weapon/CGameProjectile.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "Runtime/World/CScriptEffect.hpp"
@ -42,9 +43,7 @@ COmegaPirate::CFlash::CFlash(TUniqueId uid, const CEntityInfo& info, const zeus:
TLockedToken<CTexture>& thermalSpot, float delay)
: CActor(uid, true, "Omega Pirate Flash", info, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(), {},
CActorParameters::None(), kInvalidUniqueId)
, xf4_delay(delay)
, m_thermalSpotAdd(EFilterType::Add, thermalSpot)
, m_thermalSpotSubtract(EFilterType::Subtract, thermalSpot) {}
, xf4_delay(delay) {}
void COmegaPirate::CFlash::Accept(IVisitor& visitor) { visitor.Visit(this); }
@ -77,9 +76,9 @@ void COmegaPirate::CFlash::Think(float dt, CStateManager& mgr) {
void COmegaPirate::CFlash::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
mgr.RenderLast(GetUniqueId());
// if (xf0_thermalSpot == nullptr && xe8_thermalSpotToken.IsLocked() && xe8_thermalSpotToken.HasReference()) {
// xf0_thermalSpot = xe8_thermalSpotToken.GetObj();
// }
if (xf0_thermalSpot == nullptr && xe8_thermalSpotToken.IsLocked() && xe8_thermalSpotToken.HasReference()) {
xf0_thermalSpot = xe8_thermalSpotToken.GetObj();
}
}
void COmegaPirate::CFlash::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) {}
@ -89,18 +88,17 @@ void COmegaPirate::CFlash::Render(CStateManager& mgr) {
if (visor == CPlayerState::EPlayerVisor::Thermal) {
return;
}
if (xf0_thermalSpot == nullptr || !xe8_thermalSpotToken) {
return;
}
xf0_thermalSpot->Load(GX::TEXMAP0, EClampMode::Repeat);
float sizeMul = 35.f;
CTexturedQuadFilter* filter = nullptr;
if (visor == CPlayerState::EPlayerVisor::XRay) {
// CGraphics::SetBlendMode(ERglBlendMode::Subtract, ERglBlendFactor::One, ERglBlendFactor::Zero,
// ERglLogicOp::Clear);
filter = &m_thermalSpotSubtract;
CGX::SetBlendMode(GX::BM_SUBTRACT, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR);
sizeMul = 60.f;
} else {
// CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One,
// ERglLogicOp::Clear);
filter = &m_thermalSpotAdd;
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, ERglLogicOp::Clear);
}
float size = xfc_size * sizeMul;
@ -109,13 +107,20 @@ void COmegaPirate::CFlash::Render(CStateManager& mgr) {
const auto rvS = GetTranslation() - rightVec;
const auto rvP = GetTranslation() + rightVec;
CGraphics::SetModelMatrix(zeus::CTransform());
const std::array<CTexturedQuadFilter::Vert, 4> verts{{
{rvS + upVec, {0.f, 0.f}},
{rvP + upVec, {0.f, 1.f}},
{rvS - upVec, {1.f, 0.f}},
{rvP - upVec, {1.f, 1.f}},
}};
filter->drawVerts(zeus::CColor{1.f, std::min(1.f, size)}, verts);
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
CGraphics::SetDepthWriteMode(false, ERglEnum::Always, false);
CGraphics::StreamColor(zeus::CColor{1.f, std::min(1.f, size)});
CGraphics::StreamBegin(GX::TRIANGLEFAN);
CGraphics::StreamTexcoord(0.f, 0.f);
CGraphics::StreamVertex(rvS + upVec);
CGraphics::StreamTexcoord(1.f, 0.f);
CGraphics::StreamVertex(rvP + upVec);
CGraphics::StreamTexcoord(1.f, 1.f);
CGraphics::StreamVertex(rvP - upVec);
CGraphics::StreamTexcoord(0.f, 1.f);
CGraphics::StreamVertex(rvS - upVec);
CGraphics::StreamEnd();
}
COmegaPirate::COmegaPirate(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,

View File

@ -7,15 +7,12 @@ class COmegaPirate : public CElitePirate {
private:
class CFlash : public CActor {
private:
// TToken<CTexture> xe8_thermalSpotToken;
// CTexture* xf0_thermalSpot = nullptr;
TToken<CTexture> xe8_thermalSpotToken;
CTexture* xf0_thermalSpot = nullptr;
float xf4_delay;
float xf8_time = 0.f;
float xfc_size = 0.f;
CTexturedQuadFilter m_thermalSpotAdd;
CTexturedQuadFilter m_thermalSpotSubtract;
public:
DEFINE_ENTITY
CFlash(TUniqueId uid, const CEntityInfo& info, const zeus::CVector3f& pos, TLockedToken<CTexture>& thermalSpot,

View File

@ -1386,44 +1386,29 @@ void CThardus::RenderFlare(const CStateManager& mgr, float t) {
if (!x91c_flareTexture) {
return;
}
if (!m_flareFilter) {
m_flareFilter.emplace(EFilterType::Add, x91c_flareTexture);
}
x91c_flareTexture->Load(GX::TEXMAP0, EClampMode::Repeat);
const float scale = 30.f * t;
zeus::CVector3f offset = scale * CGraphics::g_ViewMatrix.basis[2];
zeus::CVector3f max = x92c_currentRockPos + (scale * CGraphics::g_ViewMatrix.basis[0]);
zeus::CVector3f min = x92c_currentRockPos - (scale * CGraphics::g_ViewMatrix.basis[0]);
CGraphics::SetModelMatrix(zeus::CTransform());
const std::array<CTexturedQuadFilter::Vert, 4> verts{{
{{max.x() + offset.x(), max.y() + offset.y(), max.z() + offset.z()}, {0.f, 1.f}},
{{min.x() + offset.x(), min.y() + offset.y(), min.z() + offset.z()}, {0.f, 0.f}},
{{max.x() - offset.x(), max.y() - offset.y(), max.z() - offset.z()}, {1.f, 1.f}},
{{min.x() - offset.x(), min.y() - offset.y(), min.z() - offset.z()}, {1.f, 0.f}},
}};
m_flareFilter->drawVerts({t, t}, verts);
}
#if 0
CGraphics::SetModelMatrix(zeus::CTransform());
CGraphics::SetModelMatrix({});
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::One, ERglLogicOp::Clear);
CGraphics::SetTevOp(0, CGraphics::sTevPass805a5ebc);
CGraphics::SetTevOp(1, CGraphics::skPassThru);
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
CGraphics::SetDepthWriteMode(false, ERglEnum::Always, false);
CGraphics::StreamColor(zeus::CColor(f1, f1));
CGraphics::StreamBegin(0xa0);
CGraphics::StreamTexCoord(0.f, 0.f);
CGraphics::StreamColor({t, t});
CGraphics::StreamBegin(GX::TRIANGLEFAN);
CGraphics::StreamTexcoord(0.f, 0.f);
CGraphics::StreamVertex(min + offset);
CGraphics::StreamTexCoord(1.f, 0.f);
CGraphics::StreamTexcoord(1.f, 0.f);
CGraphics::StreamVertex(min - offset);
CGraphics::StreamTexCoord(1.f, 1.f);
CGraphics::StreamTexcoord(1.f, 1.f);
CGraphics::StreamVertex(max - offset);
CGraphics::StreamTexCoord(0.f, 1.f);
CGraphics::StreamTexcoord(0.f, 1.f);
CGraphics::StreamVertex(max + offset);
CGraphics::StreamEnd();
#endif
}
zeus::CVector3f CThardus::sub801de550(CStateManager& mgr) {

View File

@ -171,8 +171,6 @@ class CThardus : public CPatterned {
zeus::CVector2f GetTargetVector(float arg, CStateManager& mgr);
void sub801dbc40();
std::optional<CTexturedQuadFilter> m_flareFilter;
void DoDoubleSnap(CStateManager& mgr) {
x330_stateMachineState.SetState(mgr, *this, GetStateMachine(), "DoubleSnap"sv);
}

View File

@ -175,8 +175,6 @@ CPlayerGun::CPlayerGun(TUniqueId playerId)
x550_camBob.SetPlayerVelocity(zeus::skZero3f);
x550_camBob.SetBobMagnitude(0.f);
x550_camBob.SetBobTimeScale(0.f);
m_aaboxShader.setAABB(x6c8_hologramClipCube);
}
void CPlayerGun::InitBeamData() {
@ -2140,13 +2138,17 @@ void CPlayerGun::DrawScreenTex(float z) {
// Use CopyScreenTex rendering to draw over framebuffer pixels in front of `z`
// This is accomplished using orthographic projection quad with sweeping `y` coordinates
// Depth is set to GEQUAL to obscure pixels in front rather than behind
// m_screenQuad.draw(zeus::skWhite, 1.f, CTexturedQuadFilter::DefaultRect, z);
// TODO
// m_screenQuad.draw(zeus::skWhite, 1.f, CTexturedQuadFilter::DefaultRect, z);
}
void CPlayerGun::DrawClipCube(const zeus::CAABox& aabb) {
// Render AABB as completely transparent object, only modifying Z-buffer
// AABB has already been set in constructor (since it's constant)
m_aaboxShader.draw(zeus::skClear);
// TODO
// m_aaboxShader.draw(zeus::skClear);
}
void CPlayerGun::Render(const CStateManager& mgr, const zeus::CVector3f& pos, const CModelFlags& flags) {

View File

@ -10,8 +10,6 @@
#include "Runtime/Character/CActorLights.hpp"
#include "Runtime/Character/CModelData.hpp"
#include "Runtime/Graphics/CRainSplashGenerator.hpp"
#include "Runtime/Graphics/Shaders/CAABoxShader.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/Weapon/CAuxWeapon.hpp"
#include "Runtime/Weapon/CFidget.hpp"
@ -255,10 +253,6 @@ private:
bool x835_30_inPhazonPool : 1 = false;
bool x835_31_actorAttached : 1 = false;
// CTexturedQuadFilter m_screenQuad{EFilterType::Blend, CGraphics::g_SpareTexture.get(),
// CTexturedQuadFilter::ZTest::GEqualZWrite};
CAABoxShader m_aaboxShader{true};
void InitBeamData();
void InitBombData();
void InitMuzzleData();

View File

@ -1,7 +1,7 @@
#pragma once
#include "Runtime/RetroTypes.hpp"
#include "Runtime/Graphics/Shaders/CWorldShadowShader.hpp"
#include "Runtime/Graphics/CTexture.hpp"
#include <zeus/CAABox.hpp>
#include <zeus/CTransform.hpp>

View File

@ -194,6 +194,7 @@ void CWorldTransManager::DrawPlatformModels(CActorLights* lights) {
}
void CWorldTransManager::DrawAllModels(CActorLights* lights) {
// TODO this needs reimpl
DrawPlatformModels(lights);
if (!x4_modelData->x1c_samusModelData.IsNull()) {
@ -210,7 +211,6 @@ void CWorldTransManager::DrawAllModels(CActorLights* lights) {
}
void CWorldTransManager::DrawFirstPass(CActorLights* lights) {
// CBooModel::SetReflectionCube(m_reflectionCube[0]);
zeus::CTransform translateXf = zeus::CTransform::Translate(
x4_modelData->x1b4_shakeResult.x(), -3.5f * (1.f - zeus::clamp(0.f, x0_curTime / 10.f, 1.f)) - 3.5f,
x4_modelData->x1b4_shakeResult.y() + 2.f);
@ -228,7 +228,6 @@ void CWorldTransManager::DrawFirstPass(CActorLights* lights) {
}
void CWorldTransManager::DrawSecondPass(CActorLights* lights) {
// CBooModel::SetReflectionCube(m_reflectionCube[1]);
const zeus::CVector3f& samusScale = x4_modelData->x0_samusRes.GetScale();
zeus::CTransform translateXf =
zeus::CTransform::Translate(-0.1f * samusScale.x(), -0.5f * samusScale.y(), 1.5f * samusScale.z());
@ -243,46 +242,7 @@ void CWorldTransManager::DrawEnabled() {
CActorLights lights(0, zeus::skZero3f, 4, 4, 0, 0, 0, 0.1f);
lights.BuildFakeLightList(x4_modelData->x1a0_lights, zeus::CColor{0.1f, 0.1f, 0.1f, 1.0f});
// if (m_reflectionCube[0]) {
// SViewport backupVp = g_Viewport;
// constexpr float width = CUBEMAP_RES;
// CGraphics::g_BooMainCommandQueue->setRenderTarget(m_reflectionCube[0], 0);
// g_Renderer->SetViewport(0, 0, width, width);
// g_Renderer->SetPerspective(90.f, width, width, 0.2f, 750.f);
//
// if (x0_curTime < x4_modelData->x1d4_dissolveEndTime) {
// zeus::CTransform mainCamXf =
// zeus::CTransform::RotateZ(zeus::degToRad(zeus::clamp(0.f, x0_curTime / 25.f, 100.f) * 360.f + 180.f - 90.f));
// for (int face = 0; face < 6; ++face) {
// CGraphics::g_BooMainCommandQueue->setRenderTarget(m_reflectionCube[0], face);
// CGraphics::g_BooMainCommandQueue->clearTarget();
// zeus::CTransform camXf =
// zeus::CTransform(mainCamXf.basis * CGraphics::skCubeBasisMats[face], zeus::CVector3f(0.f, 0.f, 1.5f));
// g_Renderer->SetWorldViewpoint(camXf);
// DrawPlatformModels(&lights);
// }
// CGraphics::g_BooMainCommandQueue->generateMipmaps(m_reflectionCube[0]);
// }
// if (x0_curTime > x4_modelData->x1d0_dissolveStartTime) {
// zeus::CTransform mainCamXf = zeus::CTransform::RotateZ(
// zeus::degToRad(48.f * zeus::clamp(0.f, (x0_curTime - x4_modelData->x1d0_dissolveStartTime + 2.f) / 5.f, 1.f) +
// 180.f - 24.f));
// for (int face = 0; face < 6; ++face) {
// CGraphics::g_BooMainCommandQueue->setRenderTarget(m_reflectionCube[1], face);
// CGraphics::g_BooMainCommandQueue->clearTarget();
// zeus::CTransform camXf =
// zeus::CTransform(mainCamXf.basis * CGraphics::skCubeBasisMats[face], zeus::CVector3f(0.f, 0.f, 1.5f));
// g_Renderer->SetWorldViewpoint(camXf);
// DrawPlatformModels(&lights);
// }
// CGraphics::g_BooMainCommandQueue->generateMipmaps(m_reflectionCube[1]);
// }
//
// CBooRenderer::BindMainDrawTarget();
// g_Renderer->SetViewport(backupVp.x0_left, backupVp.x4_top, backupVp.x8_width, backupVp.xc_height);
// }
float wsAspect = CWideScreenFilter::SetViewportToMatch(1.f);
float wsAspect = 1.7777f; // TODO
g_Renderer->SetPerspective(CCameraManager::FirstPersonFOV(), wsAspect, CCameraManager::NearPlane(),
CCameraManager::FarPlane());
@ -402,13 +362,6 @@ void CWorldTransManager::EnableTransition(const CAnimRes& samusRes, CAssetId pla
x30_type = ETransType::Enabled;
x4_modelData = std::make_unique<SModelDatas>(samusRes);
// if (!m_reflectionCube[0] && hecl::com_cubemaps->toBoolean())
// CGraphics::CommitResources([this](boo::IGraphicsDataFactory::Context& ctx) {
// m_reflectionCube[0] = ctx.newCubeRenderTexture(CUBEMAP_RES, CUBEMAP_MIPS);
// m_reflectionCube[1] = ctx.newCubeRenderTexture(CUBEMAP_RES, CUBEMAP_MIPS);
// return true;
// } BooTrace);
x8_textData.reset();
x20_random.SetSeed(99);

View File

@ -10,9 +10,6 @@
#include "Runtime/Camera/CCameraFilter.hpp"
#include "Runtime/Character/CModelData.hpp"
#include "Runtime/Graphics/CLight.hpp"
#include "Runtime/Graphics/Shaders/CCameraBlurFilter.hpp"
#include "Runtime/Graphics/Shaders/CColoredQuadFilter.hpp"
#include "Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Runtime/GuiSys/CGuiTextSupport.hpp"
#include "Runtime/GuiSys/CStringTable.hpp"

View File

@ -20,8 +20,8 @@ target_include_directories(aurora PRIVATE ../imgui ../extern/imgui)
target_link_libraries(aurora PRIVATE dawn_native dawncpp webgpu_dawn zeus logvisor SDL2-static xxhash
absl::btree absl::flat_hash_map)
if (APPLE)
target_compile_definitions(aurora PRIVATE DAWN_ENABLE_BACKEND_METAL)
target_sources(aurora PRIVATE lib/dawn/MetalBinding.mm)
target_compile_definitions(aurora PRIVATE DAWN_ENABLE_BACKEND_METAL DAWN_ENABLE_BACKEND_VULKAN)
target_sources(aurora PRIVATE lib/dawn/MetalBinding.mm lib/dawn/VulkanBinding.cpp)
set_source_files_properties(lib/dawn/MetalBinding.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
elseif (WIN32)
target_compile_definitions(aurora PRIVATE

View File

@ -30,6 +30,7 @@ struct Vec3 {
constexpr Vec3() = default;
constexpr Vec3(T x, T y, T z) : x(x), y(y), z(z) {}
constexpr Vec3(const zeus::CVector3f& vec) : x(vec.x()), y(vec.y()), z(vec.z()) {}
operator zeus::CVector3f() const { return {x, y, z}; }
bool operator==(const Vec3&) const = default;
};

View File

@ -221,6 +221,30 @@ static bool poll_events() noexcept {
return true;
}
static SDL_Window* create_window(wgpu::BackendType type) {
Uint32 flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
switch (type) {
#ifdef DAWN_ENABLE_BACKEND_VULKAN
case wgpu::BackendType::Vulkan:
flags |= SDL_WINDOW_VULKAN;
break;
#endif
#ifdef DAWN_ENABLE_BACKEND_METAL
case wgpu::BackendType::Metal:
flags |= SDL_WINDOW_METAL;
break;
#endif
#ifdef DAWN_ENABLE_BACKEND_OPENGL
case wgpu::BackendType::OpenGL:
flags |= SDL_WINDOW_OPENGL;
break;
#endif
default:
break;
}
return SDL_CreateWindow("Metaforce", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 960, flags);
}
void app_run(std::unique_ptr<AppDelegate> app, Icon icon, int argc, char** argv) noexcept {
g_AppDelegate = std::move(app);
/* Lets gather arguments skipping the program filename */
@ -244,34 +268,25 @@ void app_run(std::unique_ptr<AppDelegate> app, Icon icon, int argc, char** argv)
/* TODO: Make this an option rather than hard coding it */
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
switch (gpu::preferredBackendType) {
#ifdef DAWN_ENABLE_BACKEND_VULKAN
case wgpu::BackendType::Vulkan:
flags |= SDL_WINDOW_VULKAN;
break;
#endif
#ifdef DAWN_ENABLE_BACKEND_METAL
case wgpu::BackendType::Metal:
flags |= SDL_WINDOW_METAL;
break;
#endif
#ifdef DAWN_ENABLE_BACKEND_OPENGL
case wgpu::BackendType::OpenGL:
flags |= SDL_WINDOW_OPENGL;
break;
#endif
default:
break;
for (const auto backendType : gpu::PreferredBackendOrder) {
auto* window = create_window(backendType);
if (window == nullptr) {
continue;
}
g_window = window;
if (gpu::initialize(window, backendType)) {
break;
}
g_window = nullptr;
SDL_DestroyWindow(window);
}
g_window = SDL_CreateWindow("Metaforce", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 960, flags);
if (g_window == nullptr) {
Log.report(logvisor::Fatal, FMT_STRING("Error creating window: {}"), SDL_GetError());
unreachable();
}
set_window_icon(std::move(icon));
SDL_ShowWindow(g_window);
gpu::initialize(g_window);
gfx::initialize();
imgui::create_context();

View File

@ -1,5 +1,14 @@
#include "BackendBinding.hpp"
#if defined(DAWN_ENABLE_BACKEND_D3D12)
#include <dawn/native/D3D12Backend.h>
#endif
#if defined(DAWN_ENABLE_BACKEND_METAL)
#include <dawn/native/MetalBackend.h>
#endif
#if defined(DAWN_ENABLE_BACKEND_VULKAN)
#include <dawn/native/VulkanBackend.h>
#endif
#if defined(DAWN_ENABLE_BACKEND_OPENGL)
#include <SDL_video.h>
#include <dawn/native/OpenGLBackend.h>
@ -25,23 +34,44 @@ BackendBinding* CreateVulkanBinding(SDL_Window* window, WGPUDevice device);
BackendBinding::BackendBinding(SDL_Window* window, WGPUDevice device) : m_window(window), m_device(device) {}
void DiscoverAdapter(dawn::native::Instance* instance, SDL_Window* window, wgpu::BackendType type) {
if (type == wgpu::BackendType::OpenGL || type == wgpu::BackendType::OpenGLES) {
bool DiscoverAdapter(dawn::native::Instance* instance, SDL_Window* window, wgpu::BackendType type) {
switch (type) {
#if defined(DAWN_ENABLE_BACKEND_D3D12)
case wgpu::BackendType::D3D12: {
dawn::native::d3d12::AdapterDiscoveryOptions options;
return instance->DiscoverAdapters(&options);
}
#endif
#if defined(DAWN_ENABLE_BACKEND_METAL)
case wgpu::BackendType::Metal: {
dawn::native::metal::AdapterDiscoveryOptions options;
return instance->DiscoverAdapters(&options);
}
#endif
#if defined(DAWN_ENABLE_BACKEND_VULKAN)
case wgpu::BackendType::Vulkan: {
dawn::native::vulkan::AdapterDiscoveryOptions options;
return instance->DiscoverAdapters(&options);
}
#endif
#if defined(DAWN_ENABLE_BACKEND_OPENGL)
case wgpu::BackendType::OpenGL:
case wgpu::BackendType::OpenGLES: {
SDL_GL_CreateContext(window);
auto getProc = reinterpret_cast<void* (*)(const char*)>(SDL_GL_GetProcAddress);
if (type == wgpu::BackendType::OpenGL) {
dawn::native::opengl::AdapterDiscoveryOptions adapterOptions;
adapterOptions.getProc = getProc;
instance->DiscoverAdapters(&adapterOptions);
return instance->DiscoverAdapters(&adapterOptions);
} else {
dawn::native::opengl::AdapterDiscoveryOptionsES adapterOptions;
adapterOptions.getProc = getProc;
instance->DiscoverAdapters(&adapterOptions);
return instance->DiscoverAdapters(&adapterOptions);
}
}
#endif
} else {
instance->DiscoverDefaultAdapters();
default:
return false;
}
}

View File

@ -21,7 +21,7 @@ protected:
WGPUDevice m_device = nullptr;
};
void DiscoverAdapter(dawn::native::Instance* instance, SDL_Window* window, wgpu::BackendType type);
bool DiscoverAdapter(dawn::native::Instance* instance, SDL_Window* window, wgpu::BackendType type);
BackendBinding* CreateBinding(wgpu::BackendType type, SDL_Window* window, WGPUDevice device);
} // namespace aurora::gpu::utils

View File

@ -4,7 +4,11 @@
#include <cassert>
#include <dawn/native/VulkanBackend.h>
#include <logvisor/logvisor.hpp>
namespace aurora::gpu::utils {
static logvisor::Module Log("aurora::gpu::utils::VulkanBinding");
class VulkanBinding : public BackendBinding {
public:
VulkanBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
@ -29,7 +33,7 @@ private:
void CreateSwapChainImpl() {
VkSurfaceKHR surface = VK_NULL_HANDLE;
if (SDL_Vulkan_CreateSurface(m_window, dawn::native::vulkan::GetInstance(m_device), &surface) != SDL_TRUE) {
assert(false);
Log.report(logvisor::Fatal, FMT_STRING("Failed to create Vulkan surface: {}"), SDL_GetError());
}
m_swapChainImpl = dawn::native::vulkan::CreateNativeSwapChainImpl(m_device, surface);
}

View File

@ -26,8 +26,10 @@ constexpr uint64_t UniformBufferSize = 3145728; // 3mb
constexpr uint64_t VertexBufferSize = 3145728; // 3mb
constexpr uint64_t IndexBufferSize = 1048576; // 1mb
constexpr uint64_t StorageBufferSize = 8388608; // 8mb
constexpr uint64_t TextureUploadSize = 8388608; // 8mb
constexpr uint64_t StagingBufferSize = UniformBufferSize + VertexBufferSize + IndexBufferSize + StorageBufferSize;
constexpr uint64_t StagingBufferSize =
UniformBufferSize + VertexBufferSize + IndexBufferSize + StorageBufferSize + TextureUploadSize;
struct ShaderState {
movie_player::State moviePlayer;
@ -112,6 +114,7 @@ static ByteBuffer g_uniforms;
static ByteBuffer g_indices;
static ByteBuffer g_storage;
static ByteBuffer g_staticStorage;
static ByteBuffer g_textureUpload;
wgpu::Buffer g_vertexBuffer;
wgpu::Buffer g_uniformBuffer;
wgpu::Buffer g_indexBuffer;
@ -134,6 +137,7 @@ struct RenderPass {
static std::vector<RenderPass> g_renderPasses;
static u32 g_currentRenderPass;
std::vector<TextureHandle> g_resolvedTextures;
std::vector<TextureUpload> g_textureUploads;
static ByteBuffer g_serializedPipelines{};
static u32 g_serializedPipelineCount = 0;
@ -420,6 +424,7 @@ void shutdown() {
gx::shutdown();
g_resolvedTextures.clear();
g_cachedBindGroups.clear();
g_cachedSamplers.clear();
g_pipelines.clear();
@ -464,6 +469,7 @@ void begin_frame() {
mapBuffer(g_uniforms, UniformBufferSize);
mapBuffer(g_indices, IndexBufferSize);
mapBuffer(g_storage, StorageBufferSize);
mapBuffer(g_textureUpload, TextureUploadSize);
g_renderPasses.emplace_back();
g_currentRenderPass = 0;
@ -491,6 +497,23 @@ void end_frame(const wgpu::CommandEncoder& cmd) {
g_lastUniformSize = writeBuffer(g_uniforms, g_uniformBuffer, UniformBufferSize, "Uniform");
g_lastIndexSize = writeBuffer(g_indices, g_indexBuffer, IndexBufferSize, "Index");
g_lastStorageSize = writeBuffer(g_storage, g_storageBuffer, StorageBufferSize, "Storage");
{
// Perform texture copies
for (const auto& item : g_textureUploads) {
const wgpu::ImageCopyBuffer buf{
.layout =
wgpu::TextureDataLayout{
.offset = item.layout.offset + bufferOffset,
.bytesPerRow = ALIGN(item.layout.bytesPerRow, 256),
.rowsPerImage = item.layout.rowsPerImage,
},
.buffer = g_stagingBuffers[currentStagingBuffer],
};
cmd.CopyBufferToTexture(&buf, &item.tex, &item.size);
}
g_textureUploads.clear();
g_textureUpload.clear();
}
currentStagingBuffer = (currentStagingBuffer + 1) % g_stagingBuffers.size();
map_staging_buffer();
}
@ -676,6 +699,18 @@ Range push_static_storage(const uint8_t* data, size_t length) {
range.isStatic = true;
return range;
}
Range push_texture_data(const uint8_t* data, size_t length, u32 bytesPerRow, u32 rowsPerImage) {
// For CopyBufferToTexture, we need an alignment of 256 per row (see Dawn kTextureBytesPerRowAlignment)
const auto copyBytesPerRow = ALIGN(bytesPerRow, 256);
const auto range = map(g_textureUpload, copyBytesPerRow * rowsPerImage, 0);
u8* dst = g_textureUpload.data() + range.offset;
for (u32 i = 0; i < rowsPerImage; ++i) {
memcpy(dst, data, bytesPerRow);
data += bytesPerRow;
dst += copyBytesPerRow;
}
return range;
}
std::pair<ByteBuffer, Range> map_verts(size_t length) {
const auto range = map(g_verts, length, 4);
return {ByteBuffer{g_verts.data() + range.offset, range.size}, range};

View File

@ -125,6 +125,15 @@ extern wgpu::Buffer g_uniformBuffer;
extern wgpu::Buffer g_indexBuffer;
extern wgpu::Buffer g_storageBuffer;
extern size_t g_staticStorageLastSize;
struct TextureUpload {
wgpu::TextureDataLayout layout;
wgpu::ImageCopyTexture tex;
wgpu::Extent3D size;
TextureUpload(wgpu::TextureDataLayout layout, wgpu::ImageCopyTexture tex, wgpu::Extent3D size) noexcept
: layout(std::move(layout)), tex(std::move(tex)), size(std::move(size)) {}
};
extern std::vector<TextureUpload> g_textureUploads;
// TODO this is a bad place for this...
extern std::vector<TextureHandle> g_resolvedTextures;
@ -210,6 +219,7 @@ template <typename T>
static inline Range push_static_storage(const T& data) {
return push_static_storage(reinterpret_cast<const uint8_t*>(&data), sizeof(T));
}
Range push_texture_data(const uint8_t* data, size_t length, u32 bytesPerRow, u32 rowsPerImage);
std::pair<ByteBuffer, Range> map_verts(size_t length);
std::pair<ByteBuffer, Range> map_indices(size_t length);
std::pair<ByteBuffer, Range> map_uniform(size_t length);

View File

@ -515,7 +515,7 @@ void GXInitTexObj(GXTexObj* obj, const void* data, u16 width, u16 height, GX::Te
obj->dataInvalidated = true;
}
void GXInitTexObjResolved(GXTexObj* obj, u32 bindIdx, GX::TextureFormat format, GXTexWrapMode wrapS,
GXTexWrapMode wrapT) {
GXTexWrapMode wrapT, GXTlut tlut) {
const auto& ref = aurora::gfx::g_resolvedTextures[bindIdx];
obj->ref = ref;
obj->data = nullptr;
@ -525,7 +525,8 @@ void GXInitTexObjResolved(GXTexObj* obj, u32 bindIdx, GX::TextureFormat format,
obj->fmt = format;
obj->wrapS = wrapS;
obj->wrapT = wrapT;
obj->hasMips = false; // TODO
obj->hasMips = false;
obj->tlut = tlut;
// TODO default values?
obj->minFilter = GX_LINEAR;
obj->magFilter = GX_LINEAR;
@ -535,7 +536,6 @@ void GXInitTexObjResolved(GXTexObj* obj, u32 bindIdx, GX::TextureFormat format,
obj->biasClamp = false;
obj->doEdgeLod = false;
obj->maxAniso = GX_ANISO_4;
obj->tlut = GX_TLUT0;
obj->dataInvalidated = false;
}
void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter minFilt, GXTexFilter magFilt, float minLod, float maxLod, float lodBias,
@ -545,6 +545,7 @@ void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter minFilt, GXTexFilter magFilt, fl
obj->minLod = minLod;
obj->maxLod = maxLod;
obj->lodBias = lodBias;
obj->biasClamp = biasClamp;
obj->doEdgeLod = doEdgeLod;
obj->maxAniso = maxAniso;
}
@ -611,6 +612,18 @@ void GXInitTlutObj(GXTlutObj* obj, const void* data, GXTlutFmt format, u16 entri
"GXInitTlutObj");
}
void GXLoadTlut(const GXTlutObj* obj, GXTlut idx) noexcept { g_gxState.tluts[idx] = *obj; }
void GXSetColorUpdate(GXBool enabled) noexcept { g_gxState.colorUpdate = enabled; }
void GXSetTevColorS10(GX::TevRegID id, const GXColorS10& color) noexcept {
g_gxState.colorRegs[id] = zeus::CColor{
static_cast<float>(color.r) / 1023.f,
static_cast<float>(color.g) / 1023.f,
static_cast<float>(color.b) / 1023.f,
static_cast<float>(color.a) / 1023.f,
};
}
void GXInvalidateTexAll() noexcept {
// no-op?
}
namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::gx");
@ -771,10 +784,13 @@ static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFacto
};
}
static inline wgpu::ColorWriteMask to_write_mask(bool alphaUpdate) {
auto writeMask = wgpu::ColorWriteMask::Red | wgpu::ColorWriteMask::Green | wgpu::ColorWriteMask::Blue;
static inline wgpu::ColorWriteMask to_write_mask(bool colorUpdate, bool alphaUpdate) {
auto writeMask = wgpu::ColorWriteMask::None;
if (colorUpdate) {
writeMask |= wgpu::ColorWriteMask::Red | wgpu::ColorWriteMask::Green | wgpu::ColorWriteMask::Blue;
}
if (alphaUpdate) {
writeMask = writeMask | wgpu::ColorWriteMask::Alpha;
writeMask |= wgpu::ColorWriteMask::Alpha;
}
return writeMask;
}
@ -791,25 +807,23 @@ static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, GX:
Log.report(logvisor::Fatal, FMT_STRING("Unsupported primitive type {}"), gx_prim);
unreachable();
}
wgpu::FrontFace frontFace = wgpu::FrontFace::CCW;
wgpu::CullMode cullMode = wgpu::CullMode::None;
switch (gx_cullMode) {
case GX::CULL_FRONT:
frontFace = wgpu::FrontFace::CW;
cullMode = wgpu::CullMode::Front;
break;
case GX::CULL_BACK:
cullMode = wgpu::CullMode::Back;
break;
case GX::CULL_ALL:
case GX::CULL_NONE:
break;
default:
Log.report(logvisor::Fatal, FMT_STRING("Unsupported cull mode {}"), gx_cullMode);
unreachable();
default:
break;
}
return {
.topology = primitive,
.frontFace = frontFace,
.frontFace = wgpu::FrontFace::CW,
.cullMode = cullMode,
};
}
@ -827,7 +841,7 @@ wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, const ShaderIn
const std::array colorTargets{wgpu::ColorTargetState{
.format = g_graphicsConfig.colorFormat,
.blend = &blendState,
.writeMask = to_write_mask(config.alphaUpdate),
.writeMask = to_write_mask(config.colorUpdate, config.alphaUpdate),
}};
const auto fragmentState = wgpu::FragmentState{
.module = shader,
@ -888,22 +902,13 @@ void populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive) n
[](const auto type) { return type == GX::INDEX8 || type == GX::INDEX16; });
for (u8 i = 0; i < MaxTextures; ++i) {
const auto& bind = g_gxState.textures[i];
GX::TextureFormat copyFmt, bindFmt;
bool flipUV = false;
if (!bind.texObj.ref) {
config.shaderConfig.textureConfig[i] = {};
continue;
} else if (bind.texObj.ref->isRenderTexture) {
// EFB copy
copyFmt = bind.texObj.ref->gxFormat;
bindFmt = bind.texObj.fmt;
flipUV = true;
} else {
// Loaded texture object, no conversion necessary
copyFmt = InvalidTextureFormat;
bindFmt = bind.texObj.fmt;
TextureConfig texConfig{};
if (bind.texObj.ref) {
texConfig.copyFmt = bind.texObj.ref->gxFormat;
texConfig.loadFmt = bind.texObj.fmt;
texConfig.renderTex = bind.texObj.ref->isRenderTexture;
}
config.shaderConfig.textureConfig[i] = {copyFmt, bindFmt, flipUV};
config.shaderConfig.textureConfig[i] = texConfig;
}
config = {
.shaderConfig = config.shaderConfig,
@ -918,6 +923,7 @@ void populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive) n
.depthCompare = g_gxState.depthCompare,
.depthUpdate = g_gxState.depthUpdate,
.alphaUpdate = g_gxState.alphaUpdate,
.colorUpdate = g_gxState.colorUpdate,
};
}
@ -983,7 +989,7 @@ Range build_uniform(const ShaderInfo& info) noexcept {
const auto& mat = std::get<Mat4x4<float>>(g_gxState.texMtxs[i]);
buf.append(&mat, 64);
} else {
// Log.report(logvisor::Fatal, FMT_STRING("expected 3x4 mtx in idx {}"), i);
Log.report(logvisor::Fatal, FMT_STRING("expected 3x4 mtx in idx {}"), i);
buf.append(&Mat4x4_Identity, 64);
}
break;
@ -1073,28 +1079,28 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
std::array<wgpu::BindGroupEntry, MaxTextures * 2> textureEntries;
u32 samplerCount = 0;
u32 textureCount = 0;
for (u32 texIdx = 0, i = 0; texIdx < info.sampledTextures.size(); ++texIdx) {
if (!info.sampledTextures.test(texIdx)) {
for (u32 i = 0; i < info.sampledTextures.size(); ++i) {
if (!info.sampledTextures.test(i)) {
continue;
}
const auto& tex = g_gxState.textures[texIdx];
const auto& tex = g_gxState.textures[i];
if (!tex) {
Log.report(logvisor::Fatal, FMT_STRING("unbound texture {}"), texIdx);
Log.report(logvisor::Fatal, FMT_STRING("unbound texture {}"), i);
unreachable();
}
samplerEntries[i] = {
.binding = i,
samplerEntries[samplerCount] = {
.binding = samplerCount,
.sampler = sampler_ref(tex.get_descriptor()),
};
++samplerCount;
textureEntries[i] = {
.binding = i,
textureEntries[textureCount] = {
.binding = textureCount,
.textureView = tex.texObj.ref->view,
};
++textureCount;
// Load palette
const auto& texConfig = config.textureConfig[i];
if (texConfig.loadFmt == GX::TF_C4 || texConfig.loadFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2) {
++i;
u32 tlut = tex.texObj.tlut;
if (tlut < GX_TLUT0 || tlut > GX_TLUT7) {
Log.report(logvisor::Fatal, FMT_STRING("tlut out of bounds {}"), tlut);
@ -1103,15 +1109,12 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
Log.report(logvisor::Fatal, FMT_STRING("tlut unbound {}"), tlut);
unreachable();
}
textureEntries[i] = {
.binding = i,
textureEntries[textureCount] = {
.binding = textureCount,
.textureView = g_gxState.tluts[tlut].ref->view,
};
textureCount += 2;
} else {
++textureCount;
}
i++;
}
return {
.uniformBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{
@ -1199,77 +1202,82 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader
sUniformBindGroupLayouts.try_emplace(uniformSizeKey, out.uniformLayout);
}
u32 textureCount = info.sampledTextures.count();
// const auto textureIt = sTextureBindGroupLayouts.find(textureCount);
// if (textureIt != sTextureBindGroupLayouts.end()) {
// const auto& [sl, tl] = textureIt->second;
// out.samplerLayout = sl;
// out.textureLayout = tl;
// } else {
u32 numSamplers = 0;
u32 numTextures = 0;
std::array<wgpu::BindGroupLayoutEntry, MaxTextures> samplerEntries;
std::array<wgpu::BindGroupLayoutEntry, MaxTextures * 2> textureEntries;
for (u32 i = 0, t = 0; i < textureCount; ++i, ++t) {
samplerEntries[i] = {
.binding = i,
// u32 textureCount = info.sampledTextures.count();
// const auto textureIt = sTextureBindGroupLayouts.find(textureCount);
// if (textureIt != sTextureBindGroupLayouts.end()) {
// const auto& [sl, tl] = textureIt->second;
// out.samplerLayout = sl;
// out.textureLayout = tl;
// } else {
u32 numSamplers = 0;
u32 numTextures = 0;
std::array<wgpu::BindGroupLayoutEntry, MaxTextures> samplerEntries;
std::array<wgpu::BindGroupLayoutEntry, MaxTextures * 2> textureEntries;
for (u32 i = 0; i < info.sampledTextures.size(); ++i) {
if (!info.sampledTextures.test(i)) {
continue;
}
samplerEntries[numSamplers] = {
.binding = numSamplers,
.visibility = wgpu::ShaderStage::Fragment,
.sampler = {.type = wgpu::SamplerBindingType::Filtering},
};
++numSamplers;
const auto& texConfig = config.textureConfig[i];
if (texConfig.loadFmt == GX::TF_C4 || texConfig.loadFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2) {
bool isPaletted =
texConfig.copyFmt == GX::TF_C4 || texConfig.copyFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2;
textureEntries[numTextures] = {
.binding = numTextures,
.visibility = wgpu::ShaderStage::Fragment,
.sampler = {.type = wgpu::SamplerBindingType::Filtering},
.texture =
{
.sampleType = isPaletted ? wgpu::TextureSampleType::Sint : wgpu::TextureSampleType::Float,
.viewDimension = wgpu::TextureViewDimension::e2D,
},
};
++numSamplers;
const auto& texConfig = config.textureConfig[i];
if (texConfig.loadFmt == GX::TF_C4 || texConfig.loadFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2) {
textureEntries[t] = {
.binding = t,
.visibility = wgpu::ShaderStage::Fragment,
.texture =
{
.sampleType = wgpu::TextureSampleType::Sint,
.viewDimension = wgpu::TextureViewDimension::e2D,
},
};
++t;
textureEntries[t] = {
.binding = t,
.visibility = wgpu::ShaderStage::Fragment,
.texture =
{
.sampleType = wgpu::TextureSampleType::Float,
.viewDimension = wgpu::TextureViewDimension::e2D,
},
};
numTextures += 2;
} else {
textureEntries[t] = {
.binding = t,
.visibility = wgpu::ShaderStage::Fragment,
.texture =
{
.sampleType = wgpu::TextureSampleType::Float,
.viewDimension = wgpu::TextureViewDimension::e2D,
},
};
++numTextures;
}
}
{
const wgpu::BindGroupLayoutDescriptor descriptor{
.label = "GX Sampler Bind Group",
.entryCount = numSamplers,
.entries = samplerEntries.data(),
++numTextures;
textureEntries[numTextures] = {
.binding = numTextures,
.visibility = wgpu::ShaderStage::Fragment,
.texture =
{
.sampleType = wgpu::TextureSampleType::Float,
.viewDimension = wgpu::TextureViewDimension::e2D,
},
};
out.samplerLayout = g_device.CreateBindGroupLayout(&descriptor);
}
{
const wgpu::BindGroupLayoutDescriptor descriptor{
.label = "GX Texture Bind Group",
.entryCount = numTextures,
.entries = textureEntries.data(),
++numTextures;
} else {
textureEntries[numTextures] = {
.binding = numTextures,
.visibility = wgpu::ShaderStage::Fragment,
.texture =
{
.sampleType = wgpu::TextureSampleType::Float,
.viewDimension = wgpu::TextureViewDimension::e2D,
},
};
out.textureLayout = g_device.CreateBindGroupLayout(&descriptor);
++numTextures;
}
// sTextureBindGroupLayouts.try_emplace(textureCount, out.samplerLayout, out.textureLayout);
// }
}
{
const wgpu::BindGroupLayoutDescriptor descriptor{
.label = "GX Sampler Bind Group Layout",
.entryCount = numSamplers,
.entries = samplerEntries.data(),
};
out.samplerLayout = g_device.CreateBindGroupLayout(&descriptor);
}
{
const wgpu::BindGroupLayoutDescriptor descriptor{
.label = "GX Texture Bind Group Layout",
.entryCount = numTextures,
.entries = textureEntries.data(),
};
out.textureLayout = g_device.CreateBindGroupLayout(&descriptor);
}
// sTextureBindGroupLayouts.try_emplace(textureCount, out.samplerLayout, out.textureLayout);
// }
return out;
}

View File

@ -188,6 +188,7 @@ struct GXState {
std::array<IndTexMtxInfo, MaxIndTexMtxs> indTexMtxs;
bool depthCompare = true;
bool depthUpdate = true;
bool colorUpdate = true;
bool alphaUpdate = true;
u8 numChans = 0;
u8 numIndStages = 0;
@ -202,9 +203,9 @@ void shutdown() noexcept;
const TextureBind& get_texture(GX::TexMapID id) noexcept;
struct TextureConfig {
GX::TextureFormat copyFmt = InvalidTextureFormat; // GXSetTexCopyDst
GX::TextureFormat loadFmt = InvalidTextureFormat; // GXTexObj format
bool flipUV = false; // For render textures
GX::TextureFormat copyFmt = InvalidTextureFormat; // Underlying texture format
GX::TextureFormat loadFmt = InvalidTextureFormat; // Texture format being bound
bool renderTex = false; // Perform conversion / flip UVs
u8 _p1 = 0;
u8 _p2 = 0;
u8 _p3 = 0;
@ -225,7 +226,7 @@ struct ShaderConfig {
};
static_assert(std::has_unique_object_representations_v<ShaderConfig>);
constexpr u32 GXPipelineConfigVersion = 3;
constexpr u32 GXPipelineConfigVersion = 4;
struct PipelineConfig {
u32 version = GXPipelineConfigVersion;
ShaderConfig shaderConfig;
@ -236,8 +237,7 @@ struct PipelineConfig {
GX::BlendFactor blendFacSrc, blendFacDst;
GX::LogicOp blendOp;
u32 dstAlpha;
bool depthCompare, depthUpdate, alphaUpdate;
u8 _pad = 0;
bool depthCompare, depthUpdate, alphaUpdate, colorUpdate;
};
static_assert(std::has_unique_object_representations_v<PipelineConfig>);

View File

@ -564,6 +564,7 @@ static inline std::string vtx_attr(const ShaderConfig& config, GX::Attr attr) {
static inline std::string texture_conversion(const TextureConfig& tex, u32 stageIdx, u32 texMapId) {
std::string out;
if (tex.renderTex)
switch (tex.copyFmt) {
default:
break;
@ -573,13 +574,12 @@ static inline std::string texture_conversion(const TextureConfig& tex, u32 stage
break;
case GX::TF_I4:
case GX::TF_I8:
// Perform intensity conversion
out += fmt::format(
FMT_STRING("\n {{"
"\n var intensity = dot(sampled{0}.rgb, vec3(0.257, 0.504, 0.098)) + 16.0 / 255.0;"
"\n sampled{0} = vec4<f32>(intensity, 0.f, 0.f, 1.f);"
"\n }}"),
stageIdx);
// FIXME HACK
if (tex.loadFmt != GX::TF_C4 && tex.loadFmt != GX::TF_C8 && tex.loadFmt != GX::TF_C14X2) {
// Perform intensity conversion
out += fmt::format(FMT_STRING("\n sampled{0} = vec4<f32>(intensityF32(sampled{0}.rgb), 0.f, 0.f, 1.f);"),
stageIdx);
}
break;
}
switch (tex.loadFmt) {
@ -883,7 +883,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
if (stage.colorOp.clamp) {
op = fmt::format(FMT_STRING("clamp({}, vec3<f32>(0.0), vec3<f32>(1.0))"), op);
}
fragmentFn += fmt::format(FMT_STRING("\n {0} = vec4<f32>({1}, {0}.a);"), outReg, op);
fragmentFn += fmt::format(FMT_STRING("\n // TEV stage {2}\n {0} = vec4<f32>({1}, {0}.a);"), outReg, op, idx);
}
{
std::string outReg;
@ -1033,7 +1033,6 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
Log.report(logvisor::Fatal, FMT_STRING("unhandled tcg src {} for "), tcg.src);
unreachable();
}
// TODO this all assumes MTX3x4 currently
if (tcg.mtx == GX::IDENTITY) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_tmp = tc{0}.xyz;"), i);
} else {
@ -1069,9 +1068,11 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), stage.texCoordId);
// }
if (texConfig.loadFmt == GX::TF_C4 || texConfig.loadFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2) {
bool isPaletted =
texConfig.copyFmt == GX::TF_C4 || texConfig.copyFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2;
fragmentFnPre +=
fmt::format(FMT_STRING("\n var sampled{0} = textureSamplePalette(tex{1}, tex{1}_samp, {2}, tlut{1});"),
i, stage.texMapId, uvIn);
fmt::format(FMT_STRING("\n var sampled{0} = textureSamplePalette{3}(tex{1}, tex{1}_samp, {2}, tlut{1});"),
i, stage.texMapId, uvIn, isPaletted ? ""sv : "RGB"sv);
} else {
fragmentFnPre += fmt::format(
FMT_STRING("\n var sampled{0} = textureSampleBias(tex{1}, tex{1}_samp, {2}, ubuf.tex{1}_lod);"), i,
@ -1111,7 +1112,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
"}";
uniBufAttrs += "\n fog: Fog,";
fragmentFn += "\n var fogF = clamp((ubuf.fog.a / (ubuf.fog.b - in.pos.z)) - ubuf.fog.c, 0.0, 1.0);";
fragmentFn += "\n // Fog\n var fogF = clamp((ubuf.fog.a / (ubuf.fog.b - in.pos.z)) - ubuf.fog.c, 0.0, 1.0);";
switch (config.fogType) {
case GX::FOG_PERSP_LIN:
case GX::FOG_ORTHO_LIN:
@ -1154,9 +1155,11 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
const auto& texConfig = config.textureConfig[i];
if (texConfig.loadFmt == GX::TF_C4 || texConfig.loadFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2) {
bool isPaletted =
texConfig.copyFmt == GX::TF_C4 || texConfig.copyFmt == GX::TF_C8 || texConfig.loadFmt == GX::TF_C14X2;
texBindings += fmt::format(FMT_STRING("\n@group(2) @binding({})\n"
"var tex{}: texture_2d<i32>;"),
texBindIdx, i);
"var tex{}: texture_2d<{}>;"),
texBindIdx, i, isPaletted ? "i32"sv : "f32"sv);
++texBindIdx;
texBindings += fmt::format(FMT_STRING("\n@group(2) @binding({})\n"
"var tlut{}: texture_2d<f32>;"),
@ -1175,6 +1178,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
std::string comp0 = alpha_compare(config.alphaCompare.comp0, config.alphaCompare.ref0, comp0Valid);
std::string comp1 = alpha_compare(config.alphaCompare.comp1, config.alphaCompare.ref1, comp1Valid);
if (comp0Valid || comp1Valid) {
fragmentFn += "\n // Alpha compare";
switch (config.alphaCompare.op) {
case GX::AOP_AND:
fragmentFn += fmt::format(FMT_STRING("\n if (!({} && {})) {{ discard; }}"), comp0, comp1);
@ -1212,17 +1216,48 @@ struct VertexOutput {{
@builtin(position) pos: vec4<f32>,{vtxOutAttrs}
}};
fn intensityF32(rgb: vec3<f32>) -> f32 {{
// RGB to intensity conversion
// https://github.com/dolphin-emu/dolphin/blob/4cd48e609c507e65b95bca5afb416b59eaf7f683/Source/Core/VideoCommon/TextureConverterShaderGen.cpp#L237-L241
return dot(rgb, vec3(0.257, 0.504, 0.098)) + 16.0 / 255.0;
}}
fn intensityI32(rgb: vec3<f32>) -> i32 {{
return i32(dot(rgb, vec3(0.257, 0.504, 0.098)) * 255.f);
}}
fn textureSamplePalette(tex: texture_2d<i32>, samp: sampler, uv: vec2<f32>, tlut: texture_2d<f32>) -> vec4<f32> {{
var f = fract(uv * vec2<f32>(textureDimensions(tex)) + 0.5);
// Gather index values
var i = textureGather(0, tex, samp, uv);
var sX = textureLoad(tlut, vec2<i32>(i.x, 0), 0);
var sY = textureLoad(tlut, vec2<i32>(i.y, 0), 0);
var sZ = textureLoad(tlut, vec2<i32>(i.z, 0), 0);
var sW = textureLoad(tlut, vec2<i32>(i.w, 0), 0);
// Bilinear filtering
var tA = mix(sW, sZ, f.x);
var tB = mix(sX, sY, f.x);
return mix(tA, tB, f.y);
// Load palette colors
var c0 = textureLoad(tlut, vec2<i32>(i[0], 0), 0);
var c1 = textureLoad(tlut, vec2<i32>(i[1], 0), 0);
var c2 = textureLoad(tlut, vec2<i32>(i[2], 0), 0);
var c3 = textureLoad(tlut, vec2<i32>(i[3], 0), 0);
// Perform bilinear filtering
var f = fract(uv * vec2<f32>(textureDimensions(tex)) + 0.5);
var t0 = mix(c3, c2, f.x);
var t1 = mix(c0, c1, f.x);
return mix(t0, t1, f.y);
}}
fn textureSamplePaletteRGB(tex: texture_2d<f32>, samp: sampler, uv: vec2<f32>, tlut: texture_2d<f32>) -> vec4<f32> {{
// Gather RGB channels
var iR = textureGather(0, tex, samp, uv);
var iG = textureGather(1, tex, samp, uv);
var iB = textureGather(2, tex, samp, uv);
// Perform intensity conversion
var i0 = intensityI32(vec3<f32>(iR[0], iG[0], iB[0]));
var i1 = intensityI32(vec3<f32>(iR[1], iG[1], iB[1]));
var i2 = intensityI32(vec3<f32>(iR[2], iG[2], iB[2]));
var i3 = intensityI32(vec3<f32>(iR[3], iG[3], iB[3]));
// Load palette colors
var c0 = textureLoad(tlut, vec2<i32>(i0, 0), 0);
var c1 = textureLoad(tlut, vec2<i32>(i1, 0), 0);
var c2 = textureLoad(tlut, vec2<i32>(i2, 0), 0);
var c3 = textureLoad(tlut, vec2<i32>(i3, 0), 0);
// Perform bilinear filtering
var f = fract(uv * vec2<f32>(textureDimensions(tex)) + 0.5);
var t0 = mix(c3, c2, f.x);
var t1 = mix(c0, c1, f.x);
return mix(t0, t1, f.y);
}}
@stage(vertex)

View File

@ -71,18 +71,20 @@ TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mi
offset + dataSize, data.size());
unreachable();
}
const auto dstView = wgpu::ImageCopyTexture{
auto dstView = wgpu::ImageCopyTexture{
.texture = ref.texture,
.mipLevel = mip,
};
const auto range = push_texture_data(data.data() + offset, dataSize, bytesPerRow, heightBlocks);
const auto dataLayout = wgpu::TextureDataLayout{
.offset = range.offset,
.bytesPerRow = bytesPerRow,
.rowsPerImage = heightBlocks,
};
g_queue.WriteTexture(&dstView, data.data() + offset, dataSize, &dataLayout, &physicalSize);
g_textureUploads.emplace_back(dataLayout, std::move(dstView), physicalSize);
offset += dataSize;
}
if (offset < data.size()) {
if (data.size() != UINT32_MAX && offset < data.size()) {
Log.report(logvisor::Warning, FMT_STRING("new_static_texture_2d[{}]: texture used {} bytes, but given {} bytes"),
label, offset, data.size());
}
@ -112,7 +114,8 @@ TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t m
};
auto texture = g_device.CreateTexture(&textureDescriptor);
auto textureView = texture.CreateView(&textureViewDescriptor);
return std::make_shared<TextureRef>(std::move(texture), std::move(textureView), size, wgpuFormat, mips, format, false);
return std::make_shared<TextureRef>(std::move(texture), std::move(textureView), size, wgpuFormat, mips, format,
false);
}
TextureHandle new_render_texture(uint32_t width, uint32_t height, GX::TextureFormat fmt, zstring_view label) noexcept {
@ -167,18 +170,20 @@ void write_texture(const TextureRef& ref, ArrayRef<uint8_t> data) noexcept {
data.size());
unreachable();
}
const auto dstView = wgpu::ImageCopyTexture{
auto dstView = wgpu::ImageCopyTexture{
.texture = ref.texture,
.mipLevel = mip,
};
const auto range = push_texture_data(data.data() + offset, dataSize, bytesPerRow, heightBlocks);
const auto dataLayout = wgpu::TextureDataLayout{
.offset = range.offset,
.bytesPerRow = bytesPerRow,
.rowsPerImage = heightBlocks,
};
g_queue.WriteTexture(&dstView, data.data() + offset, dataSize, &dataLayout, &physicalSize);
g_textureUploads.emplace_back(dataLayout, std::move(dstView), physicalSize);
offset += dataSize;
}
if (offset < data.size()) {
if (data.size() != UINT32_MAX && offset < data.size()) {
Log.report(logvisor::Warning, FMT_STRING("write_texture: texture used {} bytes, but given {} bytes"), offset,
data.size());
}

View File

@ -50,7 +50,8 @@ TextureWithSampler create_render_texture(bool multisampled) {
}
const auto textureDescriptor = wgpu::TextureDescriptor{
.label = "Render texture",
.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst,
.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst,
.size = size,
.format = format,
.sampleCount = sampleCount,
@ -230,27 +231,54 @@ static void error_callback(WGPUErrorType type, char const* message, void* userda
magic_enum::enum_name(static_cast<wgpu::ErrorType>(type)), message);
}
void initialize(SDL_Window* window) {
Log.report(logvisor::Info, FMT_STRING("Creating Dawn instance"));
g_Instance = std::make_unique<dawn::native::Instance>();
#if !defined(NDEBUG)
// D3D12's debug layer is very slow
if (preferredBackendType != wgpu::BackendType::D3D12) {
g_Instance->EnableBackendValidation(true);
static void device_callback(WGPURequestDeviceStatus status, WGPUDevice device, char const* message, void* userdata) {
if (status == WGPURequestDeviceStatus_Success) {
g_device = wgpu::Device::Acquire(device);
} else {
Log.report(logvisor::Warning, FMT_STRING("Device request failed with message: {}"), message);
}
*static_cast<bool*>(userdata) = true;
}
bool initialize(SDL_Window* window, wgpu::BackendType backendType) {
if (!g_Instance) {
Log.report(logvisor::Info, FMT_STRING("Creating Dawn instance"));
g_Instance = std::make_unique<dawn::native::Instance>();
}
#ifndef NDEBUG
// D3D12's debug layer is very slow
// g_Instance->EnableBackendValidation(backendType != wgpu::BackendType::D3D12);
#endif
utils::DiscoverAdapter(g_Instance.get(), window, preferredBackendType);
if (!utils::DiscoverAdapter(g_Instance.get(), window, backendType)) {
return false;
}
{
std::vector<dawn::native::Adapter> adapters = g_Instance->GetAdapters();
const auto adapterIt = std::find_if(adapters.begin(), adapters.end(), [](const auto& adapter) -> bool {
std::sort(adapters.begin(), adapters.end(), [&](const auto& a, const auto& b) {
wgpu::AdapterProperties propertiesA;
wgpu::AdapterProperties propertiesB;
a.GetProperties(&propertiesA);
b.GetProperties(&propertiesB);
constexpr std::array PreferredTypeOrder{
wgpu::AdapterType::DiscreteGPU,
wgpu::AdapterType::IntegratedGPU,
wgpu::AdapterType::CPU,
};
const auto typeItA = std::find(PreferredTypeOrder.begin(), PreferredTypeOrder.end(), propertiesA.adapterType);
const auto typeItB = std::find(PreferredTypeOrder.begin(), PreferredTypeOrder.end(), propertiesB.adapterType);
if (typeItA == PreferredTypeOrder.end() && typeItB != PreferredTypeOrder.end()) {
return -1;
}
return static_cast<int>(typeItA - typeItB);
});
const auto adapterIt = std::find_if(adapters.begin(), adapters.end(), [=](const auto& adapter) -> bool {
wgpu::AdapterProperties properties;
adapter.GetProperties(&properties);
return properties.backendType == preferredBackendType;
return properties.backendType == backendType;
});
if (adapterIt == adapters.end()) {
Log.report(logvisor::Fatal, FMT_STRING("Failed to find usable graphics backend"));
unreachable();
return false;
}
g_Adapter = *adapterIt;
}
@ -276,9 +304,13 @@ void initialize(SDL_Window* window) {
: supportedLimits.limits.minStorageBufferOffsetAlignment,
},
};
const std::array<wgpu::FeatureName, 1> requiredFeatures{
wgpu::FeatureName::TextureCompressionBC,
};
std::vector<wgpu::FeatureName> features;
const auto supportedFeatures = g_Adapter.GetSupportedFeatures();
for (const auto* const feature : supportedFeatures) {
if (strcmp(feature, "texture-compression-bc") == 0) {
features.push_back(wgpu::FeatureName::TextureCompressionBC);
}
}
const std::array enableToggles {
/* clang-format off */
#if _WIN32
@ -297,11 +329,18 @@ void initialize(SDL_Window* window) {
togglesDescriptor.forceEnabledToggles = enableToggles.data();
const auto deviceDescriptor = wgpu::DeviceDescriptor{
.nextInChain = &togglesDescriptor,
.requiredFeaturesCount = requiredFeatures.size(),
.requiredFeatures = requiredFeatures.data(),
.requiredFeaturesCount = static_cast<uint32_t>(features.size()),
.requiredFeatures = features.data(),
.requiredLimits = &requiredLimits,
};
g_device = wgpu::Device::Acquire(g_Adapter.CreateDevice(&deviceDescriptor));
bool deviceCallbackReceived = false;
g_Adapter.RequestDevice(&deviceDescriptor, &device_callback, &deviceCallbackReceived);
// while (!deviceCallbackReceived) {
// TODO wgpuInstanceProcessEvents
// }
if (!g_device) {
return false;
}
g_device.SetUncapturedErrorCallback(&error_callback, nullptr);
}
g_queue = g_device.GetQueue();
@ -309,8 +348,7 @@ void initialize(SDL_Window* window) {
g_BackendBinding =
std::unique_ptr<utils::BackendBinding>(utils::CreateBinding(g_backendType, window, g_device.Get()));
if (!g_BackendBinding) {
Log.report(logvisor::Fatal, FMT_STRING("Unsupported backend {}"), backendName);
unreachable();
return false;
}
auto swapChainFormat = static_cast<wgpu::TextureFormat>(g_BackendBinding->GetPreferredSwapChainTextureFormat());
@ -341,9 +379,13 @@ void initialize(SDL_Window* window) {
resize_swapchain(size.fb_width, size.fb_height);
g_windowSize = size;
}
return true;
}
void shutdown() {
g_CopyBindGroupLayout = {};
g_CopyPipeline = {};
g_CopyBindGroup = {};
g_frameBuffer = {};
g_frameBufferResolved = {};
g_depthBuffer = {};

View File

@ -31,15 +31,24 @@ struct TextureWithSampler {
wgpu::Sampler sampler;
};
constexpr std::array PreferredBackendOrder{
#ifdef DAWN_ENABLE_BACKEND_D3D12
static const wgpu::BackendType preferredBackendType = wgpu::BackendType::D3D12;
#elif DAWN_ENABLE_BACKEND_VULKAN
static const wgpu::BackendType preferredBackendType = wgpu::BackendType::Vulkan;
#elif DAWN_ENABLE_BACKEND_METAL
static const wgpu::BackendType preferredBackendType = wgpu::BackendType::Metal;
#else
static const wgpu::BackendType preferredBackendType = wgpu::BackendType::OpenGL;
wgpu::BackendType::D3D12,
#endif
#ifdef DAWN_ENABLE_BACKEND_METAL
wgpu::BackendType::Metal,
#endif
#ifdef DAWN_ENABLE_BACKEND_VULKAN
wgpu::BackendType::Vulkan,
#endif
#ifdef DAWN_ENABLE_BACKEND_DESKTOP_GL
wgpu::BackendType::OpenGL,
#endif
#ifdef DAWN_ENABLE_BACKEND_OPENGLES
wgpu::BackendType::OpenGLES,
#endif
};
extern wgpu::Device g_device;
extern wgpu::Queue g_queue;
extern wgpu::SwapChain g_swapChain;
@ -51,7 +60,7 @@ extern TextureWithSampler g_depthBuffer;
extern wgpu::RenderPipeline g_CopyPipeline;
extern wgpu::BindGroup g_CopyBindGroup;
void initialize(SDL_Window* window);
bool initialize(SDL_Window* window, wgpu::BackendType backendType);
void shutdown();
void resize_swapchain(uint32_t width, uint32_t height);
TextureWithSampler create_render_texture(bool multisampled);

View File

@ -98,6 +98,7 @@ if (NOT MSVC)
target_compile_options(SDL2-static PRIVATE -Wno-implicit-fallthrough -Wno-shadow)
endif ()
set(DAWN_ENABLE_VULKAN ON CACHE BOOL "Enable compilation of the Vulkan backend" FORCE)
add_subdirectory(../extern/dawn dawn EXCLUDE_FROM_ALL)
if (DAWN_ENABLE_VULKAN)
target_compile_definitions(dawn_native PRIVATE