diff --git a/Runtime/Graphics/CCubeMaterial.cpp b/Runtime/Graphics/CCubeMaterial.cpp index 57feb554c..13f6f1cc1 100644 --- a/Runtime/Graphics/CCubeMaterial.cpp +++ b/Runtime/Graphics/CCubeMaterial.cpp @@ -426,4 +426,15 @@ void CCubeMaterial::DoModelShadow(u32 texCount, u32 tcgCount) { // CCubeModel::sShadowTexture->Load(texCount, EClampMode::One); // TODO } + +static GX::TevStageID sCurrentTevStage = GX::NULL_STAGE; +void CCubeMaterial::EnsureTevsDirect() { + if (sCurrentTevStage == GX::NULL_STAGE) { + return; + } + + //CGX::SetNumIndStages(0); + //CGX::SetTevDirect(sCurrentTevStage); + sCurrentTevStage = GX::NULL_STAGE; +} } // namespace metaforce diff --git a/Runtime/Graphics/CCubeMaterial.hpp b/Runtime/Graphics/CCubeMaterial.hpp index f4b8f46d0..c55b29baf 100644 --- a/Runtime/Graphics/CCubeMaterial.hpp +++ b/Runtime/Graphics/CCubeMaterial.hpp @@ -88,6 +88,7 @@ public: static void ResetCachedMaterials(); static void EnsureViewDepStateCached(const CCubeSurface* surface); static void KillCachedViewDepState(); + static void EnsureTevsDirect(); private: void SetCurrentBlack(); diff --git a/Runtime/Graphics/CCubeModel.hpp b/Runtime/Graphics/CCubeModel.hpp index 8415dfc23..97d3ce6b7 100644 --- a/Runtime/Graphics/CCubeModel.hpp +++ b/Runtime/Graphics/CCubeModel.hpp @@ -91,6 +91,12 @@ public: void DrawSurfaceWireframe(const CCubeSurface& surface); void SetArraysCurrent(); void SetUsingPackedLightmaps(bool v); + bool AreaTexturesLoaded() const { return x40_24_texturesLoaded; } + bool IsVisible() const { return x40_25_modelVisible; } + [[nodiscard]] CCubeSurface* GetFirstUnsortedSurface() { return x38_firstUnsortedSurf; } + [[nodiscard]] const CCubeSurface* GetFirstUnsortedSurface() const { return x38_firstUnsortedSurf; } + [[nodiscard]] CCubeSurface* GetFirstSortedSurface() { return x3c_firstSortedSurf; } + [[nodiscard]] const CCubeSurface* GetFirstSortedSurface() const { return x3c_firstSortedSurf; } [[nodiscard]] TVectorRef GetPositions() const { return x0_modelInstance.GetVertexPointer(); } [[nodiscard]] TVectorRef GetNormals() const { return x0_modelInstance.GetNormalPointer(); } diff --git a/Runtime/Graphics/CCubeRenderer.cpp b/Runtime/Graphics/CCubeRenderer.cpp index feb11ffdc..f5c827f8f 100644 --- a/Runtime/Graphics/CCubeRenderer.cpp +++ b/Runtime/Graphics/CCubeRenderer.cpp @@ -2,10 +2,14 @@ #include "Runtime/GameGlobalObjects.hpp" #include "Runtime/Graphics/CDrawable.hpp" +#include "Runtime/Graphics/CMetroidModelInstance.hpp" #include "Runtime/Graphics/CDrawablePlaneObject.hpp" #include "Runtime/Graphics/CLight.hpp" #include "Runtime/Graphics/CModel.hpp" #include "Runtime/Particle/CParticleGen.hpp" +#include "Runtime/Graphics/CCubeModel.hpp" +#include "Runtime/Graphics/CCubeSurface.hpp" +#include "Runtime/Graphics/CCubeMaterial.hpp" namespace metaforce { static logvisor::Module Log("CCubeRenderer"); @@ -169,8 +173,9 @@ void Buckets::Init() { CCubeRenderer::CAreaListItem::CAreaListItem(const std::vector* geom, const CAreaRenderOctTree* octTree, - std::unordered_map>&& textures, - std::vector&& models, int areaIdx) + std::unique_ptr>>&& textures, + std::unique_ptr>>&& models, + int areaIdx) : x0_geometry(geom) , x4_octTree(octTree) , x8_textures(std::move(textures)) @@ -178,9 +183,9 @@ CCubeRenderer::CAreaListItem::CAreaListItem(const std::vector& indTex) {} + +void CCubeRenderer::AddWorldSurfaces(CCubeModel& model) { + for (auto* it = model.GetFirstSortedSurface(); it != nullptr; it = it->GetNextSurface()) { + auto mat = model.GetMaterialByIndex(it->GetMaterialIndex()); + auto blend = mat.GetCompressedBlend(); + auto bounds = it->GetBounds(); + auto pos = bounds.closestPointAlongVector(xb0_viewPlane.normal()); + Buckets::Insert(pos, bounds, EDrawableType::WorldSurface, it, xb0_viewPlane, static_cast(blend == 0x50004)); + } +} void CCubeRenderer::AddStaticGeometry(const std::vector* geometry, - const CAreaRenderOctTree* octTree, int areaIdx) {} + const CAreaRenderOctTree* octTree, int areaIdx) { + auto search = FindStaticGeometry(geometry); + if (search == x1c_areaListItems.end()) { + auto textures = std::make_unique>>(); + auto models = std::make_unique>>(); + if (!geometry->empty()) { + CCubeModel::MakeTexturesFromMats((*geometry)[0].GetMaterialPointer(), *textures.get(), &xc_store, false); + models->reserve(geometry->size()); + int instIdx = 0; + for (const CMetroidModelInstance& inst : *geometry) { + models->emplace_back( + std::make_unique(const_cast*>(inst.GetSurfaces()), textures.get(), + const_cast(inst.GetMaterialPointer()), + const_cast*>(inst.GetVertexPointer()), + const_cast*>(inst.GetColorPointer()), + const_cast*>(inst.GetNormalPointer()), + const_cast*>(inst.GetTCPointer()), + const_cast*>(inst.GetPackedTCPointer()), + inst.GetBoundingBox(), inst.GetFlags(), false, instIdx)); + ++instIdx; + } + } + x1c_areaListItems.emplace_back(geometry, octTree, std::move(textures), std::move(models), areaIdx); + } +} void CCubeRenderer::EnablePVS(const CPVSVisSet& set, u32 areaIdx) { if (!xdc_) { @@ -220,15 +259,32 @@ void CCubeRenderer::DisablePVS() { xc8_pvs.reset(); } void CCubeRenderer::RemoveStaticGeometry(const std::vector* geometry) {} void CCubeRenderer::DrawUnsortedGeometry(int areaIdx, int mask, int targetMask, bool shadowRender) {} void CCubeRenderer::DrawSortedGeometry(int areaIdx, int mask, int targetMask) { - //SetupRenderState(); - //TODO: Loop + SetupRendererStates(true); + const CAreaListItem* item = nullptr; + for (const auto& areaListItem : x1c_areaListItems) { + if (areaIdx == -1 || areaIdx == areaListItem.x18_areaIdx) { + if (areaListItem.x4_octTree != nullptr) { + item = &areaListItem; + } + + for (const auto& model : *areaListItem.x10_models) { + if (model->IsVisible()) { + AddWorldSurfaces(*model); + } + } + } + } Buckets::Sort(); - //RenderBucketItems(items); - //DrawRenderBucketsDebug(); + RenderBucketItems(item); + SetupCGraphicsState(); + DrawRenderBucketsDebug(); Buckets::Clear(); } + void CCubeRenderer::DrawStaticGeometry(int areaIdx, int mask, int targetMask) {} void CCubeRenderer::DrawAreaGeometry(int areaIdx, int mask, int targetMask) {} + +void CCubeRenderer::RenderBucketItems(const CAreaListItem* lights) {} void CCubeRenderer::PostRenderFogs() {} void CCubeRenderer::SetModelMatrix(const zeus::CTransform& xf) { CGraphics::SetModelMatrix(xf); } @@ -300,7 +356,18 @@ void CCubeRenderer::SetPerspective(float fovy, float width, float height, float } std::pair CCubeRenderer::SetViewportOrtho(bool centered, float znear, float zfar) { - return std::pair(); + auto left = static_cast(centered ? CGraphics::GetViewportLeft() - CGraphics::GetViewportWidth() / 2 + : CGraphics::GetViewportLeft()); + auto top = static_cast(centered ? CGraphics::GetViewportTop() - CGraphics::GetViewportHeight() / 2 + : CGraphics::GetViewportHeight()); + auto right = static_cast(CGraphics::GetViewportLeft() + + (centered ? CGraphics::GetViewportWidth() / 2 : CGraphics::GetViewportWidth())); + auto bottom = static_cast(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}}; } void CCubeRenderer::SetClippingPlanes(const zeus::CFrustum& frustum) { x44_frustumPlanes = frustum; } @@ -359,18 +426,31 @@ void CCubeRenderer::SetDebugOption(IRenderer::EDebugOption option, int value) { } } -void CCubeRenderer::BeginPrimitive(IRenderer::EPrimitiveType, int) {} -void CCubeRenderer::BeginLines(int) {} -void CCubeRenderer::BeginLineStrip(int) {} -void CCubeRenderer::BeginTriangles(int) {} -void CCubeRenderer::BeginTriangleStrip(int) {} -void CCubeRenderer::BeginTriangleFan(int) {} -void CCubeRenderer::PrimVertex(const zeus::CVector3f&) {} -void CCubeRenderer::PrimNormal(const zeus::CVector3f&) {} -void CCubeRenderer::PrimColor(float, float, float, float) {} -void CCubeRenderer::PrimColor(const zeus::CColor&) {} -void CCubeRenderer::EndPrimitive() {} -void CCubeRenderer::SetAmbientColor(const zeus::CColor& color) {} +void CCubeRenderer::BeginPrimitive(IRenderer::EPrimitiveType type, s32 nverts) { + x18_primVertCount = nverts; + CGraphics::StreamBegin(GX::Primitive(type)); +} +void CCubeRenderer::BeginLines(s32 nverts) { BeginPrimitive(EPrimitiveType::Lines, nverts); } +void CCubeRenderer::BeginLineStrip(s32 nverts) { BeginPrimitive(EPrimitiveType::LineStrip, nverts); } +void CCubeRenderer::BeginTriangles(s32 nverts) { BeginPrimitive(EPrimitiveType::Triangles, nverts); } +void CCubeRenderer::BeginTriangleStrip(s32 nverts) { BeginPrimitive(EPrimitiveType::TriangleStrip, nverts); } +void CCubeRenderer::BeginTriangleFan(s32 nverts) { BeginPrimitive(EPrimitiveType::TriangleFan, nverts); } +void CCubeRenderer::PrimVertex(const zeus::CVector3f& vertex) { + --x18_primVertCount; + CGraphics::StreamColor(x2e0_primColor); + CGraphics::StreamNormal(x2e4_primNormal); + CGraphics::StreamVertex(vertex); +} +void CCubeRenderer::PrimNormal(const zeus::CVector3f& normal) { x2e4_primNormal = normal; } +void CCubeRenderer::PrimColor(float r, float g, float b, float a) { PrimColor({r, g, b, a}); } +void CCubeRenderer::PrimColor(const zeus::CColor& color) { x2e0_primColor = color; } +void CCubeRenderer::EndPrimitive() { + while (x18_primVertCount > 0) { + PrimVertex(zeus::skZero3f); + } + CGraphics::StreamEnd(); +} +void CCubeRenderer::SetAmbientColor(const zeus::CColor& color) { CGraphics::SetAmbientColor(color); } void CCubeRenderer::DrawString(const char* string, int x, int y) { x10_font.DrawString(string, x, y, zeus::skWhite); } u32 CCubeRenderer::GetFPS() { return CGraphics::GetFPS(); } @@ -406,6 +486,13 @@ void CCubeRenderer::DrawPhazonSuitIndirectEffect(const zeus::CColor& nonIndirect const TLockedToken& indTex, const zeus::CColor& indirectMod, float blurRadius, float scale, float offX, float offY) {} void CCubeRenderer::DrawXRayOutline(const zeus::CAABox& aabb) {} + +std::list::iterator +CCubeRenderer::FindStaticGeometry(const std::vector* geometry) { + return std::find_if(x1c_areaListItems.begin(), x1c_areaListItems.end(), + [&](const CAreaListItem& item) { return item.x0_geometry == geometry; }); +} + void CCubeRenderer::FindOverlappingWorldModels(std::vector& modelBits, const zeus::CAABox& aabb) const {} int CCubeRenderer::DrawOverlappingWorldModelIDs(int alphaVal, const std::vector& modelBits, const zeus::CAABox& aabb) { @@ -413,4 +500,15 @@ int CCubeRenderer::DrawOverlappingWorldModelIDs(int alphaVal, const std::vector< } void CCubeRenderer::DrawOverlappingWorldModelShadows(int alphaVal, const std::vector& modelBits, const zeus::CAABox& aabb, float alpha) {} + +void CCubeRenderer::SetupCGraphicsState() { + CGraphics::DisableAllLights(); + CGraphics::SetModelMatrix({}); + CTevCombiners::ResetStates(); + CGraphics::SetAmbientColor({0.4f}); + // CGX::SetChanMatColor(EChannelId::Channel0, GX::Color{0xFFFFFFFF}); + CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true); + // CGX::SetChanCtrl(EChannelId::Channel1, false, GX::SRC_REG, GX::LIGHT_NULL, GX::DF_NONE, GX::AF_NONE); + CCubeMaterial::EnsureTevsDirect(); +} } // namespace metaforce diff --git a/Runtime/Graphics/CCubeRenderer.hpp b/Runtime/Graphics/CCubeRenderer.hpp index d51207093..fd741d68f 100644 --- a/Runtime/Graphics/CCubeRenderer.hpp +++ b/Runtime/Graphics/CCubeRenderer.hpp @@ -23,15 +23,15 @@ class CCubeRenderer final : public IRenderer { const std::vector* x0_geometry; const CAreaRenderOctTree* x4_octTree; /* originally auto_ptrs of vectors */ - std::unordered_map> x8_textures; - std::vector x10_models; + std::unique_ptr>> x8_textures; + std::unique_ptr>> x10_models; int x18_areaIdx; /* Per-area octree-word major, light bits minor */ std::vector x1c_lightOctreeWords; CAreaListItem(const std::vector* geom, const CAreaRenderOctTree* octTree, - std::unordered_map>&& textures, std::vector&& models, - int areaIdx); + std::unique_ptr>>&& textures, + std::unique_ptr>>&& models, int areaIdx); }; struct CFogVolumeListItem { @@ -53,7 +53,7 @@ private: IFactory& x8_factory; IObjectStore& xc_store; CFont x10_font{1.f}; - // u32 x18_ = 0; + u32 x18_primVertCount = 0; std::list x1c_areaListItems; // TODO x34...x40 zeus::CFrustum x44_frustumPlanes; // {zeus::skIdentityMatrix4f, 1.5707964f, 1.f, 1.f, false, 100.f} @@ -74,8 +74,8 @@ private: std::list x2ac_fogVolumes; std::list> x2c4_spaceWarps; u32 x2dc_reflectionAge = 2; - zeus::CColor x2e0_ = zeus::skWhite; - zeus::CVector3f x2e4_ = zeus::skForward; + zeus::CColor x2e0_primColor = zeus::skWhite; + zeus::CVector3f x2e4_primNormal = zeus::skForward; float x2f0_thermalVisorLevel = 1.f; zeus::CColor x2f4_thermColor{1.f, 0.f, 1.f, 1.f}; float x2f8_thermColdScale = 0.f; // ??? byte in code @@ -107,6 +107,7 @@ public: CCubeRenderer(IObjectStore& store, IFactory& resFac); ~CCubeRenderer() override; + void AddWorldSurfaces(CCubeModel& model); void AddStaticGeometry(const std::vector* geometry, const CAreaRenderOctTree* octTree, int areaIdx) override; void EnablePVS(const CPVSVisSet& set, u32 areaIdx) override; @@ -203,15 +204,21 @@ public: const zeus::CColor& indirectMod, float blurRadius, float scale, float offX, float offY); void DrawXRayOutline(const zeus::CAABox& aabb); + std::list::iterator FindStaticGeometry(const std::vector* geometry); void FindOverlappingWorldModels(std::vector& modelBits, const zeus::CAABox& aabb) const; int DrawOverlappingWorldModelIDs(int alphaVal, const std::vector& modelBits, const zeus::CAABox& aabb); void DrawOverlappingWorldModelShadows(int alphaVal, const std::vector& modelBits, const zeus::CAABox& aabb, float alpha); + void RenderBucketItems(const CAreaListItem* lights); + void DrawRenderBucketsDebug() {} + void SetupRendererStates(bool b) {} // Getters [[nodiscard]] bool IsInAreaDraw() const { return x318_30_inAreaDraw; } [[nodiscard]] bool IsReflectionDirty() const { return x318_24_refectionDirty; } void SetReflectionDirty(bool v) { x318_24_refectionDirty = v; } [[nodiscard]] bool IsThermalVisorActive() const { return x318_29_thermalVisor; } + + static void SetupCGraphicsState(); }; } // namespace metaforce diff --git a/Runtime/Graphics/CMetroidModelInstance.hpp b/Runtime/Graphics/CMetroidModelInstance.hpp index 8131cc3c6..c8eb6a024 100644 --- a/Runtime/Graphics/CMetroidModelInstance.hpp +++ b/Runtime/Graphics/CMetroidModelInstance.hpp @@ -34,6 +34,7 @@ public: [[nodiscard]] u32 GetFlags() const { return x0_visorFlags; } [[nodiscard]] const zeus::CAABox& GetBoundingBox() const { return x34_worldAABB; } + [[nodiscard]] std::vector* GetSurfaces() { return &x50_surfaces; } [[nodiscard]] const std::vector* GetSurfaces() const { return &x50_surfaces; } [[nodiscard]] const u8* GetMaterialPointer() const { return x4c_materialData; } [[nodiscard]] TVectorRef GetVertexPointer() const { return &x60_positions; } diff --git a/Runtime/Graphics/GX.hpp b/Runtime/Graphics/GX.hpp index 8bf40a86f..33f71f242 100644 --- a/Runtime/Graphics/GX.hpp +++ b/Runtime/Graphics/GX.hpp @@ -476,7 +476,8 @@ enum TevStageID { TEVSTAGE13, TEVSTAGE14, TEVSTAGE15, - MAX_TEVSTAGE + MAX_TEVSTAGE, + NULL_STAGE = -1, }; enum IndTexFormat { diff --git a/Runtime/Graphics/IRenderer.hpp b/Runtime/Graphics/IRenderer.hpp index 7b362ed8d..761a9b520 100644 --- a/Runtime/Graphics/IRenderer.hpp +++ b/Runtime/Graphics/IRenderer.hpp @@ -32,7 +32,13 @@ public: enum class EDrawableSorting { SortedCallback, UnsortedCallback }; enum class EDebugOption { Invalid = -1, PVSMode, PVSState, FogDisabled }; - enum class EPrimitiveType {}; + enum class EPrimitiveType { + Triangles = GX::TRIANGLES, + TriangleFan = GX::TRIANGLEFAN, + TriangleStrip = GX::TRIANGLESTRIP, + Lines = GX::LINES, + LineStrip = GX::LINESTRIP, + }; virtual ~IRenderer() = default; virtual void AddStaticGeometry(const std::vector* geometry, const CAreaRenderOctTree* octTree,