#pragma once #include #include #include #include #include "DataSpec/DNACommon/CMDL.hpp" #include "DataSpec/DNAMP1/CMDLMaterials.hpp" #include "Runtime/CFactoryMgr.hpp" #include "Runtime/CToken.hpp" #include "Runtime/RetroTypes.hpp" #include "Runtime/Graphics/CTexture.hpp" #include "Runtime/Graphics/Shaders/CModelShaders.hpp" #include #include #include #include namespace metaforce { class CLight; class CModel; class CPoseAsTransforms; class CSkinRules; class IObjectStore; struct CModelFlags { u8 x0_blendMode = 0; /* 2: add color, >6: additive, >4: blend, else opaque */ u8 x1_matSetIdx = 0; EExtendedShader m_extendedShader = EExtendedShader::Lighting; bool m_noCull = false; bool m_noZTest = false; bool m_noZWrite = false; bool m_depthGreater = false; u16 x2_flags = 0; /* Flags */ zeus::CColor x4_color; /* Set into kcolor slot specified by material */ zeus::CColor addColor = zeus::skClear; zeus::CAABox mbShadowBox; constexpr CModelFlags() = default; constexpr CModelFlags(u8 blendMode, u8 shadIdx, u16 flags, const zeus::CColor& col) : x0_blendMode(blendMode), x1_matSetIdx(shadIdx), x2_flags(flags), x4_color(col) { /* Blend mode will override this if the surface's original material is opaque */ m_noZWrite = (x2_flags & 0x2) == 0; m_depthGreater = (x2_flags & 0x8) != 0; } /* Flags 0x1: depth lequal 0x2: depth update 0x4: render without texture lock 0x8: depth greater 0x10: depth non-inclusive */ bool operator==(const CModelFlags& other) const { return x0_blendMode == other.x0_blendMode && x1_matSetIdx == other.x1_matSetIdx && x2_flags == other.x2_flags && x4_color == other.x4_color; } bool operator!=(const CModelFlags& other) const { return !operator==(other); } }; /* metaforce addition: doesn't require hacky stashing of * pointers within loaded CMDL buffer */ struct CBooSurface { DataSpec::DNACMDL::SurfaceHeader_2 m_data; size_t selfIdx; class CBooModel* m_parent = nullptr; CBooSurface* m_next = nullptr; zeus::CAABox GetBounds() const { if (!m_data.aabbSz) return zeus::CAABox(m_data.centroid, m_data.centroid); else return zeus::CAABox(m_data.aabb[0], m_data.aabb[1]); } }; using MaterialSet = DataSpec::DNAMP1::HMDLMaterialSet; struct GeometryUniformLayout { mutable std::vector> m_sharedBuffer; size_t m_geomBufferSize = 0; size_t m_skinBankCount = 0; size_t m_weightVecCount = 0; std::vector m_skinOffs; std::vector m_skinSizes; std::vector m_uvOffs; std::vector m_uvSizes; GeometryUniformLayout(const CModel* model, const MaterialSet* matSet); void Update(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose, const MaterialSet* matSet, const boo::ObjToken& buf, const CBooModel* parent) const; void ReserveSharedBuffers(boo::IGraphicsDataFactory::Context& ctx, int size); boo::ObjToken GetSharedBuffer(int idx) const; }; struct SShader { std::unordered_map> x0_textures; std::unordered_map m_shaders; MaterialSet m_matSet; std::optional m_geomLayout; int m_matSetIdx; explicit SShader(int idx) : m_matSetIdx(idx) { x0_textures.clear(); m_shaders.clear(); } void InitializeLayout(const CModel* model) { m_geomLayout.emplace(model, &m_matSet); } void UnlockTextures(); CModelShaders::ShaderPipelines BuildShader(const hecl::HMDLMeta& meta, const MaterialSet::Material& mat); void BuildShaders(const hecl::HMDLMeta& meta, std::unordered_map& shaders); void BuildShaders(const hecl::HMDLMeta& meta) { BuildShaders(meta, m_shaders); } }; class CBooModel { friend class CBooRenderer; friend class CGameArea; friend class CMetroidModelInstance; friend class CModel; friend class CSkinnedModel; friend struct GeometryUniformLayout; public: enum class ESurfaceSelection { UnsortedOnly, SortedOnly, All }; private: CBooModel* m_next = nullptr; CBooModel* m_prev = nullptr; size_t m_uniUpdateCount = 0; TToken m_modelTok; CModel* m_model; std::vector* x0_surfaces; const MaterialSet* x4_matSet; const GeometryUniformLayout* m_geomLayout; int m_matSetIdx = -1; const std::unordered_map* m_pipelines; std::unordered_map> x1c_textures; zeus::CAABox x20_aabb; CBooSurface* x38_firstUnsortedSurface = nullptr; CBooSurface* x3c_firstSortedSurface = nullptr; bool x40_24_texturesLoaded : 1 = false; bool x40_25_modelVisible : 1 = false; u8 x41_mask; u32 x44_areaInstanceIdx = UINT32_MAX; struct UVAnimationBuffer { static void ProcessAnimation(u8*& bufOut, const MaterialSet::Material::PASS& anim); static void PadOutBuffer(u8*& bufStart, u8*& bufOut); static void Update(u8*& bufOut, const MaterialSet* matSet, const CModelFlags& flags, const CBooModel* parent); }; CModelShaders::LightingUniform m_lightingData; /* metaforce addition: boo! */ size_t m_uniformDataSize = 0; struct ModelInstance { boo::ObjToken m_geomUniformBuffer; boo::ObjToken m_uniformBuffer; std::vector>> m_shaderDataBindings; boo::ObjToken m_dynamicVbo; boo::ObjToken GetBooVBO(const CBooModel& model, boo::IGraphicsDataFactory::Context& ctx); }; std::vector m_instances; ModelInstance m_ballShadowInstance; boo::ObjToken m_staticVbo; boo::ObjToken m_staticIbo; boo::ObjToken m_lastDrawnShadowMap; boo::ObjToken m_lastDrawnOneTexture; boo::ObjToken m_lastDrawnReflectionCube; ModelInstance* PushNewModelInstance(int sharedLayoutBuf = -1, boo::IGraphicsDataFactory::Context* ctx = nullptr); void DrawAlphaSurfaces(const CModelFlags& flags) const; void DrawNormalSurfaces(const CModelFlags& flags) const; void DrawSurfaces(const CModelFlags& flags) const; void DrawSurface(const CBooSurface& surf, const CModelFlags& flags) const; void WarmupDrawSurfaces() const; void WarmupDrawSurface(const CBooSurface& surf) const; static inline zeus::CVector3f g_PlayerPosition; static inline float g_ModSeconds = 0.0f; static inline float g_TransformedTime = 0.0f; static inline float g_TransformedTime2 = 0.0f; static inline CBooModel* g_LastModelCached = nullptr; static inline bool g_DummyTextures = false; static inline bool g_RenderModelBlack = false; public: ~CBooModel(); CBooModel(TToken& token, CModel* parent, std::vector* surfaces, SShader& shader, const boo::ObjToken& vbo, const boo::ObjToken& ibo, const zeus::CAABox& aabb, u8 renderMask, int numInsts); static void MakeTexturesFromMats(const MaterialSet& matSet, std::unordered_map>& toksOut, IObjectStore& store); void MakeTexturesFromMats(std::unordered_map>& toksOut, IObjectStore& store); bool IsOpaque() const { return x3c_firstSortedSurface == nullptr; } void ActivateLights(const std::vector& lights); void SetAmbientColor(const zeus::CColor& color) { m_lightingData.ambient = color; } void DisableAllLights(); void RemapMaterialData(SShader& shader); void RemapMaterialData(SShader& shader, const std::unordered_map& pipelines); bool TryLockTextures(); void UnlockTextures(); void SyncLoadTextures(); void Touch(int shaderIdx); void VerifyCurrentShader(int shaderIdx); boo::ObjToken UpdateUniformData(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose, int sharedLayoutBuf = -1, boo::IGraphicsDataFactory::Context* ctx = nullptr); void DrawAlpha(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose); void DrawNormal(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose); void Draw(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose); void DrawFlat(ESurfaceSelection sel, EExtendedShader extendedIdx) const; void LockParent() { m_modelTok.Lock(); } void UnlockParent() { m_modelTok.Unlock(); } const MaterialSet::Material& GetMaterialByIndex(int idx) const { return x4_matSet->materials.at(idx); } void ClearUniformCounter() { m_uniUpdateCount = 0; } static void ClearModelUniformCounters(); static inline bool g_DrawingOccluders = false; static void SetDrawingOccluders(bool occ) { g_DrawingOccluders = occ; } static void SetNewPlayerPositionAndTime(const zeus::CVector3f& pos); static inline zeus::CVector3f g_ReflectViewPos; static void KillCachedViewDepState(); static void EnsureViewDepStateCached(const CBooModel& model, const CBooSurface* surf, zeus::CMatrix4f* mtxsOut, float& alphaOut); static inline boo::ObjToken g_shadowMap; static inline zeus::CTransform g_shadowTexXf; static void EnableShadowMaps(const boo::ObjToken& map, const zeus::CTransform& texXf); static void DisableShadowMaps(); static inline boo::ObjToken g_disintegrateTexture; static void SetDisintegrateTexture(const boo::ObjToken& map) { g_disintegrateTexture = map; } static inline boo::ObjToken g_reflectionCube; static void SetReflectionCube(const boo::ObjToken& map) { g_reflectionCube = map; } static void SetDummyTextures(bool b) { g_DummyTextures = b; } static void SetRenderModelBlack(bool b) { g_RenderModelBlack = b; } static void Shutdown(); const zeus::CAABox& GetAABB() const { return x20_aabb; } }; class CModel { friend class CBooModel; friend struct GeometryUniformLayout; // std::unique_ptr x0_data; // u32 x4_dataLen; TToken m_selfToken; /* DO NOT LOCK! */ zeus::CAABox m_aabb; u32 m_flags; std::vector x8_surfaces; std::vector x18_matSets; std::unique_ptr x28_modelInst; // CModel* x30_next = nullptr; // CModel* x34_prev = nullptr; int x38_lastFrame; /* metaforce addition: boo! */ boo::ObjToken m_staticVbo; hecl::HMDLMeta m_hmdlMeta; std::unique_ptr m_dynamicVertexData; boo::ObjToken m_ibo; public: using MaterialSet = DataSpec::DNAMP1::HMDLMaterialSet; CModel(std::unique_ptr&& in, u32 dataLen, IObjectStore* store, CObjectReference* selfRef); void DrawSortedParts(const CModelFlags& flags) const; void DrawUnsortedParts(const CModelFlags& flags) const; void Draw(const CModelFlags& flags) const; bool IsLoaded(int shaderIdx) const; void Touch(int shaderIdx) { x28_modelInst->Touch(shaderIdx); } const zeus::CAABox& GetAABB() const { return m_aabb; } CBooModel& GetInstance() { return *x28_modelInst; } const CBooModel& GetInstance() const { return *x28_modelInst; } std::unique_ptr MakeNewInstance(int shaderIdx, int subInsts, bool lockParent = true); void UpdateLastFrame() const { const_cast(*this).x38_lastFrame = CGraphics::GetFrameCounter(); } u32 GetNumMaterialSets() const { return x18_matSets.size(); } size_t GetPoolVertexOffset(size_t idx) const; zeus::CVector3f GetPoolVertex(size_t idx) const; size_t GetPoolNormalOffset(size_t idx) const; zeus::CVector3f GetPoolNormal(size_t idx) const; void ApplyVerticesCPU(const boo::ObjToken& vertBuf, const std::vector>& vn) const; void RestoreVerticesCPU(const boo::ObjToken& vertBuf) const; void _WarmupShaders(); static void WarmupShaders(const SObjectTag& cmdlTag); }; CFactoryFnReturn FModelFactory(const metaforce::SObjectTag& tag, std::unique_ptr&& in, u32 len, const metaforce::CVParamTransfer& vparms, CObjectReference* selfRef); } // namespace metaforce