diff --git a/DataSpec/DNACommon/CMDL.cpp b/DataSpec/DNACommon/CMDL.cpp index 77852dc68..d4ef9e6b6 100644 --- a/DataSpec/DNACommon/CMDL.cpp +++ b/DataSpec/DNACommon/CMDL.cpp @@ -1664,9 +1664,10 @@ bool WriteHMDLMREASecs(std::vector>& secsOut, const hecl::P struct MaterialPool { std::vector materials; - size_t addMaterial(const Mesh::Material& mat) + size_t addMaterial(const Mesh::Material& mat, bool& newMat) { size_t ret = 0; + newMat = false; for (const Mesh::Material* testMat : materials) { if (mat == *testMat) @@ -1674,6 +1675,7 @@ bool WriteHMDLMREASecs(std::vector>& secsOut, const hecl::P ++ret; } materials.push_back(&mat); + newMat = true; return ret; } } matPool; @@ -1696,9 +1698,10 @@ bool WriteHMDLMREASecs(std::vector>& secsOut, const hecl::P for (const Mesh::Material& mat : mesh.materialSets[0]) { - size_t idx = matPool.addMaterial(mat); + bool newMat; + size_t idx = matPool.addMaterial(mat, newMat); meshToGlobalMats.push_back(idx); - if (idx < matPool.materials.size() - 1) + if (!newMat) continue; for (const hecl::ProjectPath& path : mat.texs) @@ -1736,6 +1739,7 @@ bool WriteHMDLMREASecs(std::vector>& secsOut, const hecl::P /* Iterate meshes */ auto matIt = surfToGlobalMats.cbegin(); + int meshIdx = 0; for (const Mesh& mesh : meshes) { zeus::CTransform meshXf(mesh.sceneXf.val); diff --git a/DataSpec/DNACommon/CRSC.cpp b/DataSpec/DNACommon/CRSC.cpp index 6a7d8432c..c97e814d9 100644 --- a/DataSpec/DNACommon/CRSC.cpp +++ b/DataSpec/DNACommon/CRSC.cpp @@ -322,7 +322,7 @@ bool WriteCRSM(const CRSM& crsm, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } template bool WriteCRSM(const CRSM& crsm, const hecl::ProjectPath& outPath); diff --git a/DataSpec/DNACommon/DGRP.cpp b/DataSpec/DNACommon/DGRP.cpp index 08cf76ac6..f9b64c8da 100644 --- a/DataSpec/DNACommon/DGRP.cpp +++ b/DataSpec/DNACommon/DGRP.cpp @@ -133,7 +133,7 @@ bool WriteDGRP(const DGRP& dgrp, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } template bool WriteDGRP(const DGRP& dgrp, const hecl::ProjectPath& outPath); diff --git a/DataSpec/DNACommon/DNACommon.hpp b/DataSpec/DNACommon/DNACommon.hpp index 96bfec3e6..ac16082f6 100644 --- a/DataSpec/DNACommon/DNACommon.hpp +++ b/DataSpec/DNACommon/DNACommon.hpp @@ -82,7 +82,7 @@ public: } } size_t binarySize(size_t __isz) const - {return __isz + 4;} + {return __isz + 16;} }; using FourCC = hecl::FourCC; diff --git a/DataSpec/DNACommon/DPSC.cpp b/DataSpec/DNACommon/DPSC.cpp index eb9ef0449..a8ac503ef 100644 --- a/DataSpec/DNACommon/DPSC.cpp +++ b/DataSpec/DNACommon/DPSC.cpp @@ -404,7 +404,7 @@ bool WriteDPSM(const DPSM& dpsm, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } template bool WriteDPSM(const DPSM& dpsm, const hecl::ProjectPath& outPath); diff --git a/DataSpec/DNACommon/ELSC.cpp b/DataSpec/DNACommon/ELSC.cpp index 09c59d929..deb08a77f 100644 --- a/DataSpec/DNACommon/ELSC.cpp +++ b/DataSpec/DNACommon/ELSC.cpp @@ -421,7 +421,7 @@ bool WriteELSM(const ELSM& elsm, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } template bool WriteELSM(const ELSM& gpsm, const hecl::ProjectPath& outPath); diff --git a/DataSpec/DNACommon/FONT.cpp b/DataSpec/DNACommon/FONT.cpp index 7145bf3d5..e7e16c233 100644 --- a/DataSpec/DNACommon/FONT.cpp +++ b/DataSpec/DNACommon/FONT.cpp @@ -565,7 +565,7 @@ bool WriteFONT(const FONT& font, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } template bool WriteFONT(const FONT& font, const hecl::ProjectPath& outPath); diff --git a/DataSpec/DNACommon/FSM2.cpp b/DataSpec/DNACommon/FSM2.cpp index b4a7201aa..fbbbdb219 100644 --- a/DataSpec/DNACommon/FSM2.cpp +++ b/DataSpec/DNACommon/FSM2.cpp @@ -1007,7 +1007,7 @@ bool WriteFSM2(const FSM2& fsm2, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } template bool WriteFSM2(const FSM2& fsm2, const hecl::ProjectPath& outPath); diff --git a/DataSpec/DNACommon/OBBTreeBuilder.cpp b/DataSpec/DNACommon/OBBTreeBuilder.cpp index dce9fb3e0..95d18e1c7 100644 --- a/DataSpec/DNACommon/OBBTreeBuilder.cpp +++ b/DataSpec/DNACommon/OBBTreeBuilder.cpp @@ -144,14 +144,10 @@ static void MakeLeaf(const ColMesh& mesh, const std::vector& index, Node& n n.right.reset(); n.isLeaf = true; n.leafData = std::make_unique(); - n.leafData->edgeIndexCount = atUint32(index.size() * 3); - n.leafData->edgeIndices.reserve(n.leafData->edgeIndexCount); + n.leafData->triangleIndexCount = atUint32(index.size()); + n.leafData->triangleIndices.reserve(n.leafData->triangleIndexCount); for (int i : index) - { - const ColMesh::Triangle& T = mesh.trianges[i]; - for (int j = 0; j < 3; ++j) - n.leafData->edgeIndices.push_back(T.edges[j]); - } + n.leafData->triangleIndices.push_back(i); } template diff --git a/DataSpec/DNACommon/PART.cpp b/DataSpec/DNACommon/PART.cpp index 62c6f4867..92aef7acf 100644 --- a/DataSpec/DNACommon/PART.cpp +++ b/DataSpec/DNACommon/PART.cpp @@ -1390,7 +1390,7 @@ bool WriteGPSM(const GPSM& gpsm, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } template bool WriteGPSM(const GPSM& gpsm, const hecl::ProjectPath& outPath); diff --git a/DataSpec/DNACommon/SWHC.cpp b/DataSpec/DNACommon/SWHC.cpp index 7c8ff7ff0..28fd039b2 100644 --- a/DataSpec/DNACommon/SWHC.cpp +++ b/DataSpec/DNACommon/SWHC.cpp @@ -523,7 +523,7 @@ bool WriteSWSH(const SWSH& swsh, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } template bool WriteSWSH(const SWSH& swsh, const hecl::ProjectPath& outPath); diff --git a/DataSpec/DNACommon/Tweaks/TweakWriter.hpp b/DataSpec/DNACommon/Tweaks/TweakWriter.hpp index 2b45e7c1b..9886a6fd4 100644 --- a/DataSpec/DNACommon/Tweaks/TweakWriter.hpp +++ b/DataSpec/DNACommon/Tweaks/TweakWriter.hpp @@ -16,7 +16,7 @@ bool WriteTweak(const T& tweak, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } diff --git a/DataSpec/DNACommon/WPSC.cpp b/DataSpec/DNACommon/WPSC.cpp index 8ad735fd6..7ab11e2e1 100644 --- a/DataSpec/DNACommon/WPSC.cpp +++ b/DataSpec/DNACommon/WPSC.cpp @@ -660,7 +660,7 @@ bool WriteWPSM(const WPSM& wpsm, const hecl::ProjectPath& outPath) int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } template bool WriteWPSM(const WPSM& wpsm, const hecl::ProjectPath& outPath); diff --git a/DataSpec/DNAMP1/CINF.cpp b/DataSpec/DNAMP1/CINF.cpp index a2a16664d..6022143e4 100644 --- a/DataSpec/DNAMP1/CINF.cpp +++ b/DataSpec/DNAMP1/CINF.cpp @@ -135,7 +135,9 @@ CINF::CINF(const Armature& armature, std::unordered_map& i if (bone->children.size()) { int curId = 4; - RecursiveAddArmatureBone(armature, armature.getChild(bone, 0), 3, curId, idMap, nameMap); + const Armature::Bone* child; + for (size_t i=0 ; (child = armature.getChild(bone, i)) ; ++i) + RecursiveAddArmatureBone(armature, child, 3, curId, idMap, nameMap); } bones.emplace_back(); diff --git a/DataSpec/DNAMP1/DCLN.hpp b/DataSpec/DNAMP1/DCLN.hpp index df26183c1..0a2b37474 100644 --- a/DataSpec/DNAMP1/DCLN.hpp +++ b/DataSpec/DNAMP1/DCLN.hpp @@ -53,9 +53,9 @@ struct DCLN : BigDNA struct LeafData : BigDNA { DECL_DNA - Value edgeIndexCount; - Vector edgeIndices; - size_t getMemoryUsage() const { return (((edgeIndices.size() * 2) + 16) + 3) & ~3; } + Value triangleIndexCount; + Vector triangleIndices; + size_t getMemoryUsage() const { return (((triangleIndices.size() * 2) + 16) + 3) & ~3; } }; Value xf[3]; @@ -234,6 +234,10 @@ struct DCLN : BigDNA athena::io::FileWriter w(outPath.getAbsolutePath()); dcln.write(w); + int64_t rem = w.position() % 32; + if (rem) + for (int64_t i=0 ; i<32-rem ; ++i) + w.writeUByte(0xff); return true; } }; diff --git a/DataSpec/DNAMP1/MREA.cpp b/DataSpec/DNAMP1/MREA.cpp index 1019df103..a7bd6decc 100644 --- a/DataSpec/DNAMP1/MREA.cpp +++ b/DataSpec/DNAMP1/MREA.cpp @@ -1,3 +1,5 @@ +#include +#include #include "MREA.hpp" #include "SCLY.hpp" #include "PATH.hpp" @@ -167,8 +169,17 @@ bool MREA::Extract(const SpecBase& dataSpec, rs.seek(secStart + head.secSizes[curSec++], athena::Begin); /* Dump VISI entities */ + secStart = rs.position(); if (head.secSizes[curSec] && rs.readUint32Big() == 'VISI') { + { + rs.seek(secStart, athena::Begin); + auto visiData = rs.readUBytes(head.secSizes[curSec]); + athena::io::FileWriter visiOut(outPath.getWithExtension(_S(".visi"), true).getAbsolutePath()); + visiOut.writeUBytes(visiData.get(), head.secSizes[curSec]); + rs.seek(secStart + 4, athena::Begin); + } + athena::io::YAMLDocWriter visiWriter("VISI"); if (auto __vec = visiWriter.enterSubVector("entities")) { @@ -447,79 +458,121 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath, if (auto __vec = r.enterSubVector("entities", entityCount)) { entities.reserve(entityCount); - uint16_t entityId = r.readUint16(nullptr); - for (const SCLY::ScriptLayer& layer : sclyData.layers) + for (size_t i=0 ; i& obj : layer.objects) + uint16_t entityId = r.readUint16(nullptr); + for (const SCLY::ScriptLayer& layer : sclyData.layers) { - if ((obj->id & 0xffff) == entityId) + for (const std::unique_ptr& obj : layer.objects) { - zeus::CAABox entAABB = obj->getVISIAABB(btok); - if (entAABB.min.x < entAABB.max.x) - entities.emplace_back(entityId, entAABB); + if ((obj->id & 0xffff) == entityId) + { + zeus::CAABox entAABB = obj->getVISIAABB(btok); + if (!entAABB.invalid()) + entities.emplace_back(entityId, entAABB); + } } } } } - hecl::ProjectPath visiIntOut = outPath.getWithExtension(_S(".visiint")); - hecl::ProjectPath visiIn = outPath.getWithExtension(_S(".visi")); - athena::io::FileWriter w(visiIntOut.getAbsolutePath()); - w.writeUint32Big(meshes.size()); - for (const DNACMDL::Mesh& mesh : meshes) + // Check if pre-generated visi exists, recycle if able + hecl::ProjectPath preVisiPath = inPath.getWithExtension(_S(".visi"), true); + if (preVisiPath.getPathType() == hecl::ProjectPath::Type::File) { - w.writeUint32Big(uint32_t(mesh.topology)); - - w.writeUint32Big(mesh.pos.size()); - for (const auto& v : mesh.pos) + athena::io::FileReader preVisiReader(preVisiPath.getAbsolutePath()); + atUint64 preVisiLen = preVisiReader.length(); + if (preVisiLen > 26) { - atVec3f xfPos = hecl::BlenderConnection::DataStream::MtxVecMul4RM(mesh.sceneXf, v); - w.writeVec3fBig(xfPos); - } + auto preVisiData = preVisiReader.readUBytes(preVisiLen); + athena::io::MemoryReader preVisiDataReader(preVisiData.get(), preVisiLen); - w.writeUint32Big(mesh.surfaces.size()); - for (const DNACMDL::Mesh::Surface& surf : mesh.surfaces) - { - w.writeUint32Big(surf.verts.size()); - for (const DNACMDL::Mesh::Surface::Vert& vert : surf.verts) - w.writeUint32Big(vert.iPos); - const DNACMDL::Mesh::Material& mat = mesh.materialSets[0][surf.materialIdx]; - w.writeBool(mat.transparent); + atUint32 preVisiFourCC = preVisiDataReader.readUint32Big(); + atUint32 preVisiVersion = preVisiDataReader.readUint32Big(); + preVisiDataReader.readBool(); + preVisiDataReader.readBool(); + atUint32 preFeatureCount = preVisiDataReader.readUint32Big(); + atUint32 preLightsCount = preVisiDataReader.readUint32Big(); + atUint32 preLayer2LightCount = preVisiDataReader.readUint32Big(); + atUint32 preEntityCount = preVisiDataReader.readUint32Big(); + + if (preVisiFourCC == 'VISI' && preVisiVersion == 2 && + preFeatureCount == meshes.size() + entities.size() && + preLightsCount == lightsVisi[0].size() + lightsVisi[1].size() && + preLayer2LightCount == lightsVisi[1].size() && + preEntityCount == entities.size()) + { + secs.emplace_back(preVisiLen, 0); + memcpy(secs.back().data(), preVisiData.get(), preVisiLen); + visiGood = true; + } } } - w.writeUint32Big(entities.size()); - for (const auto& ent : entities) + if (!visiGood) { - w.writeUint32Big(ent.first); - w.writeVec3fBig(ent.second.min); - w.writeVec3fBig(ent.second.max); - } + hecl::ProjectPath visiIntOut = outPath.getWithExtension(_S(".visiint")); + hecl::ProjectPath visiIn = inPath.getWithExtension(_S(".visi")); + athena::io::FileWriter w(visiIntOut.getAbsolutePath()); + w.writeUint32Big(meshes.size()); + for (const DNACMDL::Mesh& mesh : meshes) + { + w.writeUint32Big(uint32_t(mesh.topology)); - w.writeUint32Big(lightsVisi[0].size() + lightsVisi[1].size()); - w.writeUint32Big(lightsVisi[1].size()); - for (const auto& light : lightsVisi[1]) - w.writeVec3fBig(light); - for (const auto& light : lightsVisi[0]) - w.writeVec3fBig(light); + w.writeUint32Big(mesh.pos.size()); + for (const auto& v : mesh.pos) + { + atVec3f xfPos = hecl::BlenderConnection::DataStream::MtxVecMul4RM(mesh.sceneXf, v); + w.writeVec3fBig(xfPos); + } - w.close(); + w.writeUint32Big(mesh.surfaces.size()); + for (const DNACMDL::Mesh::Surface& surf : mesh.surfaces) + { + w.writeUint32Big(surf.verts.size()); + for (const DNACMDL::Mesh::Surface::Vert& vert : surf.verts) + w.writeUint32Big(vert.iPos); + const DNACMDL::Mesh::Material& mat = mesh.materialSets[0][surf.materialIdx]; + w.writeBool(mat.transparent); + } + } - hecl::SystemString VisiGenPath = ExeDir + _S("/visigen"); + w.writeUint32Big(entities.size()); + for (const auto& ent : entities) + { + w.writeUint32Big(ent.first); + w.writeVec3fBig(ent.second.min); + w.writeVec3fBig(ent.second.max); + } + + w.writeUint32Big(lightsVisi[0].size() + lightsVisi[1].size()); + w.writeUint32Big(lightsVisi[1].size()); + for (const auto& light : lightsVisi[1]) + w.writeVec3fBig(light); + for (const auto& light : lightsVisi[0]) + w.writeVec3fBig(light); + + w.close(); + + hecl::SystemString VisiGenPath = ExeDir + _S("/visigen"); #if _WIN32 - VisiGenPath += _S(".exe"); + VisiGenPath += _S(".exe"); #endif - const hecl::SystemChar* args[] = {VisiGenPath.c_str(), - visiIntOut.getAbsolutePath().c_str(), - visiIn.getAbsolutePath().c_str(), - nullptr}; - if (0 == hecl::RunProcess(VisiGenPath.c_str(), args)) - { - athena::io::FileReader r(visiIn.getAbsolutePath()); - size_t length = r.length(); - secs.emplace_back(length, 0); - r.readBytesToBuf(secs.back().data(), length); - visiGood = true; + char thrIdx[16]; + snprintf(thrIdx, 16, "%d", hecl::ClientProcess::GetThreadWorkerIdx()); + const hecl::SystemChar* args[] = {VisiGenPath.c_str(), + visiIntOut.getAbsolutePath().c_str(), + visiIn.getAbsolutePath().c_str(), + thrIdx, + nullptr}; + if (0 == hecl::RunProcess(VisiGenPath.c_str(), args)) + { + athena::io::FileReader r(visiIn.getAbsolutePath()); + size_t length = r.length(); + secs.emplace_back(length, 0); + r.readBytesToBuf(secs.back().data(), length); + visiGood = true; + } } } } @@ -578,7 +631,7 @@ bool MREA::CookPath(const hecl::ProjectPath& outPath, int64_t rem = w.position() % 32; if (rem) for (int64_t i=0 ; i<32-rem ; ++i) - w.writeBytes((atInt8*)"\xff", 1); + w.writeUByte(0xff); return true; } diff --git a/Editor/ProjectManager.cpp b/Editor/ProjectManager.cpp index 15615a71f..74a9ead6f 100644 --- a/Editor/ProjectManager.cpp +++ b/Editor/ProjectManager.cpp @@ -133,7 +133,26 @@ makeProj: m_mainMP1.emplace(m_factoryMP1, m_objStore, m_vm.m_mainBooFactory, m_vm.m_mainCommandQueue, m_vm.m_renderTex); m_vm.InitMP1(*m_mainMP1); - m_vm.BuildTestPART(); + + // precook + m_precooking = true; + std::vector nonMlvls; + std::vector mlvls; + mlvls.reserve(8); + m_factoryMP1.EnumerateResources([this, &nonMlvls, &mlvls](const SObjectTag& tag) + { + if (tag.type == FOURCC('CMDL') || tag.type == FOURCC('MREA')) + m_factoryMP1.CookResourceAsync(tag); + else if (tag.type != FOURCC('MLVL')) + nonMlvls.push_back(tag); + else // (tag.type == FOURCC('MLVL')) + mlvls.push_back(tag); + return true; + }); + for (const SObjectTag& tag : nonMlvls) + m_factoryMP1.CookResourceAsync(tag); + for (const SObjectTag& tag : mlvls) + m_factoryMP1.CookResourceAsync(tag); if (needsSave) saveProject(); @@ -182,6 +201,14 @@ bool ProjectManager::saveProject() void ProjectManager::mainUpdate() { + if (m_precooking) + { + if (!m_factoryMP1.IsBusy()) + m_precooking = false; + else + return; + } + if (m_mainMP1) { if (m_mainMP1->Proc()) @@ -194,6 +221,9 @@ void ProjectManager::mainUpdate() void ProjectManager::mainDraw() { + if (m_precooking) + return; + if (m_mainMP1) m_mainMP1->Draw(); } diff --git a/Editor/ProjectManager.hpp b/Editor/ProjectManager.hpp index f74f159d8..37ffed62f 100644 --- a/Editor/ProjectManager.hpp +++ b/Editor/ProjectManager.hpp @@ -34,6 +34,7 @@ class ProjectManager ProjectResourceFactoryMP1 m_factoryMP1; ProjectResourcePool m_objStore; std::experimental::optional m_mainMP1; + bool m_precooking = false; public: static ProjectManager* g_SharedManager; diff --git a/Editor/ProjectResourceFactoryBase.cpp b/Editor/ProjectResourceFactoryBase.cpp index 78bde7854..90a76c186 100644 --- a/Editor/ProjectResourceFactoryBase.cpp +++ b/Editor/ProjectResourceFactoryBase.cpp @@ -548,18 +548,23 @@ void ProjectResourceFactoryBase::AsyncTask::CookComplete() xc_targetDataRawPtr, x14_resSize, x14_resOffset); } - else + else if (xc_targetDataPtr || xc_targetObjPtr) { x10_loadBuffer.reset(new u8[x14_resSize]); m_bufTransaction = m_parent.m_clientProc.addBufferTransaction(m_cookedPath, x10_loadBuffer.get(), x14_resSize, x14_resOffset); } + else + { + /* Skip buffer transaction if no target pointers set */ + m_complete = true; + } } bool ProjectResourceFactoryBase::AsyncTask::AsyncPump() { - if (m_failed) + if (m_failed || m_complete) return true; if (m_bufTransaction) @@ -581,14 +586,49 @@ bool ProjectResourceFactoryBase::AsyncTask::AsyncPump() void ProjectResourceFactoryBase::AsyncTask::WaitForComplete() { - using ItType = std::unordered_map>::iterator; - ItType search = m_parent.m_asyncLoadList.find(x0_tag); - if (search == m_parent.m_asyncLoadList.end()) + using ItType = std::unordered_map>::iterator>::iterator; + ItType search = m_parent.m_asyncLoadMap.find(x0_tag); + if (search == m_parent.m_asyncLoadMap.end()) return; for (ItType tmp = search ; !m_parent.AsyncPumpTask(tmp) ; tmp = search) {std::this_thread::sleep_for(std::chrono::milliseconds(2));} } +using AsyncTask = ProjectResourceFactoryBase::AsyncTask; + +std::shared_ptr +ProjectResourceFactoryBase::_AddTask(const std::shared_ptr& ptr) +{ + m_asyncLoadMap.insert({ptr->x0_tag, m_asyncLoadList.insert(m_asyncLoadList.end(), ptr)}); + return ptr; +} + +std::list>::iterator +ProjectResourceFactoryBase::_RemoveTask(std::list>::iterator it) +{ + m_asyncLoadMap.erase((*it)->x0_tag); + return m_asyncLoadList.erase(it); +} + +std::unordered_map>::iterator>::iterator +ProjectResourceFactoryBase::_RemoveTask(std::unordered_map>::iterator>::iterator it) +{ + if (it != m_asyncLoadMap.end()) + { + m_asyncLoadList.erase(it->second); + return m_asyncLoadMap.erase(it); + } + return it; +}; + +std::unordered_map>::iterator>::iterator +ProjectResourceFactoryBase::_RemoveTask(const SObjectTag& tag) +{ + return _RemoveTask(m_asyncLoadMap.find(tag)); +}; + bool ProjectResourceFactoryBase::WaitForTagReady(const urde::SObjectTag& tag, const hecl::ProjectPath*& pathOut) { @@ -687,17 +727,17 @@ std::unique_ptr ProjectResourceFactoryBase::Build(const urde::SObjec const hecl::ProjectPath* resPath = nullptr; if (!WaitForTagReady(tag, resPath)) return {}; - auto asyncSearch = m_asyncLoadList.find(tag); - if (asyncSearch != m_asyncLoadList.end()) + auto asyncSearch = m_asyncLoadMap.find(tag); + if (asyncSearch != m_asyncLoadMap.end()) { /* Async spinloop */ - AsyncTask& task = *asyncSearch->second; + AsyncTask& task = **asyncSearch->second; task.EnsurePath(task.x0_tag, *resPath); /* Pump load pipeline (cooking if needed) */ while (!task.AsyncPump()) {std::this_thread::sleep_for(std::chrono::milliseconds(2));} - if (task.m_complete) + if (task.m_complete && task.x10_loadBuffer) { /* Load complete, build resource */ std::unique_ptr newObj; @@ -714,16 +754,23 @@ std::unique_ptr ProjectResourceFactoryBase::Build(const urde::SObjec *task.xc_targetObjPtr = newObj.get(); Log.report(logvisor::Warning, "spin-built %.4s %08X", - task.x0_tag.type.toString().c_str(), - u32(task.x0_tag.id.Value())); + task.x0_tag.type.toString().c_str(), u32(task.x0_tag.id.Value())); - m_asyncLoadList.erase(asyncSearch); + _RemoveTask(asyncSearch); return newObj; } - Log.report(logvisor::Error, "unable to spin-build %.4s %08X", - task.x0_tag.type.toString().c_str(), - u32(task.x0_tag.id.Value())); - m_asyncLoadList.erase(asyncSearch); + else if (task.m_complete) + { + Log.report(logvisor::Error, "unable to spin-build %.4s %08X; Resource requested as cook-only", + task.x0_tag.type.toString().c_str(), u32(task.x0_tag.id.Value())); + } + else + { + Log.report(logvisor::Error, "unable to spin-build %.4s %08X", + task.x0_tag.type.toString().c_str(), u32(task.x0_tag.id.Value())); + } + + _RemoveTask(asyncSearch); return {}; } @@ -731,16 +778,15 @@ std::unique_ptr ProjectResourceFactoryBase::Build(const urde::SObjec return BuildSync(tag, *resPath, paramXfer, selfRef); } -std::shared_ptr +std::shared_ptr ProjectResourceFactoryBase::BuildAsyncInternal(const urde::SObjectTag& tag, const urde::CVParamTransfer& paramXfer, urde::IObj** objOut, CObjectReference* selfRef) { - if (m_asyncLoadList.find(tag) != m_asyncLoadList.end()) + if (m_asyncLoadMap.find(tag) != m_asyncLoadMap.end()) return {}; - return m_asyncLoadList.emplace(std::make_pair(tag, - std::make_unique(*this, tag, objOut, paramXfer, selfRef))).first->second; + return _AddTask(std::make_unique(*this, tag, objOut, paramXfer, selfRef)); } void ProjectResourceFactoryBase::BuildAsync(const urde::SObjectTag& tag, @@ -772,40 +818,37 @@ u32 ProjectResourceFactoryBase::ResourceSize(const SObjectTag& tag) return fr->length(); } -std::shared_ptr +std::shared_ptr ProjectResourceFactoryBase::LoadResourceAsync(const urde::SObjectTag& tag, std::unique_ptr& target) { if (!tag.id.IsValid()) Log.report(logvisor::Fatal, "attempted to access null id"); - if (m_asyncLoadList.find(tag) != m_asyncLoadList.end()) + if (m_asyncLoadMap.find(tag) != m_asyncLoadMap.end()) return {}; - return m_asyncLoadList.emplace(std::make_pair(tag, - std::make_shared(*this, tag, target))).first->second; + return _AddTask(std::make_shared(*this, tag, target)); } -std::shared_ptr +std::shared_ptr ProjectResourceFactoryBase::LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, std::unique_ptr& target) { if (!tag.id.IsValid()) Log.report(logvisor::Fatal, "attempted to access null id"); - if (m_asyncLoadList.find(tag) != m_asyncLoadList.end()) + if (m_asyncLoadMap.find(tag) != m_asyncLoadMap.end()) return {}; - return m_asyncLoadList.emplace(std::make_pair(tag, - std::make_shared(*this, tag, target, size, off))).first->second; + return _AddTask(std::make_shared(*this, tag, target, size, off)); } -std::shared_ptr +std::shared_ptr ProjectResourceFactoryBase::LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, u8* target) { if (!tag.id.IsValid()) Log.report(logvisor::Fatal, "attempted to access null id"); - if (m_asyncLoadList.find(tag) != m_asyncLoadList.end()) + if (m_asyncLoadMap.find(tag) != m_asyncLoadMap.end()) return {}; - return m_asyncLoadList.emplace(std::make_pair(tag, - std::make_shared(*this, tag, target, size, off))).first->second; + return _AddTask(std::make_shared(*this, tag, target, size, off)); } std::unique_ptr ProjectResourceFactoryBase::LoadResourceSync(const urde::SObjectTag& tag) @@ -847,9 +890,19 @@ std::unique_ptr ProjectResourceFactoryBase::LoadResourcePartSync(const urd return fr->readUBytes(sz); } +std::shared_ptr +ProjectResourceFactoryBase::CookResourceAsync(const urde::SObjectTag& tag) +{ + if (!tag.id.IsValid()) + Log.report(logvisor::Fatal, "attempted to access null id"); + if (m_asyncLoadMap.find(tag) != m_asyncLoadMap.end()) + return {}; + return _AddTask(std::make_shared(*this, tag)); +} + void ProjectResourceFactoryBase::CancelBuild(const urde::SObjectTag& tag) { - m_asyncLoadList.erase(tag); + _RemoveTask(tag); } bool ProjectResourceFactoryBase::CanBuild(const urde::SObjectTag& tag) @@ -961,12 +1014,12 @@ void ProjectResourceFactoryBase::EnumerateNamedResources( } } -bool ProjectResourceFactoryBase::AsyncPumpTask( - std::unordered_map>::iterator& it) +template +bool ProjectResourceFactoryBase::AsyncPumpTask(ItType& it) { /* Ensure requested resource is in the index */ std::unique_lock lk(m_backgroundIndexMutex); - AsyncTask& task = *it->second; + AsyncTask& task = _GetAsyncTask(it); auto search = m_tagToPath.find(task.x0_tag); if (search == m_tagToPath.end()) { @@ -974,7 +1027,7 @@ bool ProjectResourceFactoryBase::AsyncPumpTask( { Log.report(logvisor::Error, _S("unable to find async load resource (%s, %08X)"), task.x0_tag.type.toString().c_str(), task.x0_tag.id); - it = m_asyncLoadList.erase(it); + it = _RemoveTask(it); } return true; } @@ -1025,13 +1078,19 @@ bool ProjectResourceFactoryBase::AsyncPumpTask( } } - it = m_asyncLoadList.erase(it); + it = _RemoveTask(it); return true; } ++it; return false; } +template bool ProjectResourceFactoryBase::AsyncPumpTask>::iterator>( + std::list>::iterator& it); +template bool ProjectResourceFactoryBase::AsyncPumpTask>::iterator>::iterator>( + std::unordered_map>::iterator>::iterator& it); + void ProjectResourceFactoryBase::AsyncIdle() { /* Consume completed transactions, they will be processed this cycle at the latest */ diff --git a/Editor/ProjectResourceFactoryBase.hpp b/Editor/ProjectResourceFactoryBase.hpp index de24cf8e5..4a2a24ac5 100644 --- a/Editor/ProjectResourceFactoryBase.hpp +++ b/Editor/ProjectResourceFactoryBase.hpp @@ -60,6 +60,10 @@ public: IObj** ptr, const CVParamTransfer& xfer, CObjectReference* selfRef) : m_parent(parent), x0_tag(tag), xc_targetObjPtr(ptr), x18_cvXfer(xfer), m_selfRef(selfRef) {} + /* Cook only */ + AsyncTask(ProjectResourceFactoryBase& parent, const SObjectTag& tag) + : m_parent(parent), x0_tag(tag) {} + void EnsurePath(const urde::SObjectTag& tag, const hecl::ProjectPath& path); void CookComplete(); @@ -85,7 +89,27 @@ protected: std::mutex m_backgroundIndexMutex; bool m_backgroundRunning = false; - std::unordered_map> m_asyncLoadList; + std::list> m_asyncLoadList; + std::unordered_map>::iterator> m_asyncLoadMap; + std::shared_ptr + _AddTask(const std::shared_ptr& ptr); + std::list>::iterator + _RemoveTask(std::list>::iterator it); + std::unordered_map>::iterator>::iterator + _RemoveTask(std::unordered_map>::iterator>::iterator it); + std::unordered_map>::iterator>::iterator + _RemoveTask(const SObjectTag& tag); + + static AsyncTask& _GetAsyncTask(std::list>::iterator it) + { + return **it; + } + static AsyncTask& _GetAsyncTask( + std::unordered_map>::iterator>::iterator it) + { + return **it->second; + } bool WaitForTagReady(const urde::SObjectTag& tag, const hecl::ProjectPath*& pathOut); bool @@ -141,9 +165,13 @@ public: std::unique_ptr LoadResourceSync(const urde::SObjectTag& tag); std::unique_ptr LoadResourcePartSync(const urde::SObjectTag& tag, u32 size, u32 off); - bool AsyncPumpTask(std::unordered_map>::iterator& it); + std::shared_ptr CookResourceAsync(const urde::SObjectTag& tag); + + template + bool AsyncPumpTask(ItType& it); void AsyncIdle(); - void Shutdown() {CancelBackgroundIndex();} + void Shutdown() { CancelBackgroundIndex(); } + bool IsBusy() const { return m_asyncLoadMap.size() != 0; } SObjectTag TagFromPath(const hecl::SystemChar* path) const { diff --git a/Editor/ViewManager.cpp b/Editor/ViewManager.cpp index 628831a76..fa93ceba9 100644 --- a/Editor/ViewManager.cpp +++ b/Editor/ViewManager.cpp @@ -25,8 +25,11 @@ using YAMLNode = athena::io::YAMLNode; namespace urde { -void ViewManager::BuildTestPART() +void ViewManager::InitMP1(MP1::CMain& main) { + main.Init(m_fileStoreManager, m_mainWindow.get(), m_voiceEngine.get(), *m_amuseAllocWrapper); + main.WarmupShaders(); + m_testGameView.reset(new TestGameView(*this, m_viewResources, *m_rootView)); m_rootView->accessContentViews().clear(); @@ -34,12 +37,6 @@ void ViewManager::BuildTestPART() m_rootView->updateSize(); } -void ViewManager::InitMP1(MP1::CMain& main) -{ - main.Init(m_fileStoreManager, m_mainWindow.get(), m_voiceEngine.get(), *m_amuseAllocWrapper); - main.WarmupShaders(); -} - void ViewManager::TestGameView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) { specter::View::resized(root, sub); @@ -48,7 +45,6 @@ void ViewManager::TestGameView::resized(const boo::SWindowRect& root, const boo: void ViewManager::TestGameView::draw(boo::IGraphicsCommandQueue* gfxQ) { - gfxQ->clearTarget(true, true); m_vm.m_projManager.mainDraw(); } diff --git a/Editor/ViewManager.hpp b/Editor/ViewManager.hpp index 61a6fb4ad..e28793ec0 100644 --- a/Editor/ViewManager.hpp +++ b/Editor/ViewManager.hpp @@ -143,7 +143,6 @@ class ViewManager : public specter::IViewManager unsigned m_editorFrames = 120; void FadeInEditors() {m_editorFrames = 0;} - void BuildTestPART(); void InitMP1(MP1::CMain& main); Space* m_deferSplit = nullptr; diff --git a/Runtime/AutoMapper/CMapArea.cpp b/Runtime/AutoMapper/CMapArea.cpp index cdee5a13a..d64d058e8 100644 --- a/Runtime/AutoMapper/CMapArea.cpp +++ b/Runtime/AutoMapper/CMapArea.cpp @@ -28,7 +28,7 @@ void CMapArea::PostConstruct() { x38_moStart = x44_buf.get(); x3c_vertexStart = x38_moStart + (x28_mappableObjCount * 0x50); - x40_surfaceStart = x40_surfaceStart + (x2c_vertexCount * 12); + x40_surfaceStart = x3c_vertexStart + (x2c_vertexCount * 12); m_mappableObjects.reserve(x28_mappableObjCount); for (u32 i = 0, j=0 ; iGetObj({'MAPA', x0_hexagonId}); + x4_hexagonToken = g_SimplePool->GetObj({FOURCC('MAPA'), x0_hexagonId}); u32 count = in.readUint32Big(); x10_worldDatas.reserve(count); for (u32 i = 0 ; i= 0) selector ^= 1 << r19[i]; - float hiT = (i < r17-1) ? hiT = r20[r19[i+1]] : hiT = hT; + float hiT = (i < r17-1) ? r20[r19[i+1]] : hT; if (hiT > lowT && loT <= hiT) { Node child = GetChild(selector); if (child.x20_nodeType != ETreeType::Invalid) - LineTestExInternal(line, filter, res, loT, hiT, maxT, vec); + child.LineTestExInternal(line, filter, res, loT, hiT, maxT, vec); if (res.x10_surface) if (res.x3c_t > highT) res = SRayResult(); diff --git a/Runtime/Graphics/CMetroidModelInstance.hpp b/Runtime/Graphics/CMetroidModelInstance.hpp index f44af73d4..bc80eeee0 100644 --- a/Runtime/Graphics/CMetroidModelInstance.hpp +++ b/Runtime/Graphics/CMetroidModelInstance.hpp @@ -5,6 +5,7 @@ #include "RetroTypes.hpp" #include "zeus/CTransform.hpp" #include "zeus/CAABox.hpp" +#include "hecl/Runtime.hpp" namespace urde { @@ -21,9 +22,21 @@ class CMetroidModelInstance zeus::CAABox x34_aabb; std::vector m_surfaces; std::unique_ptr m_instance; + hecl::HMDLMeta m_hmdlMeta; + std::vector> m_shaders; public: CMetroidModelInstance() = default; CMetroidModelInstance(CMetroidModelInstance&&) = default; + void Clear() + { + x0_visorFlags = 0; + x4_xf = {}; + x34_aabb = {}; + m_surfaces.clear(); + m_instance.reset(); + m_hmdlMeta = {}; + m_shaders.clear(); + } }; } diff --git a/Runtime/Graphics/CModel.hpp b/Runtime/Graphics/CModel.hpp index 6d3b7161e..c4d4fb438 100644 --- a/Runtime/Graphics/CModel.hpp +++ b/Runtime/Graphics/CModel.hpp @@ -88,6 +88,11 @@ public: int m_matSetIdx; SShader(int idx) : m_matSetIdx(idx) {} void UnlockTextures(); + std::shared_ptr + BuildShader(const hecl::HMDLMeta& meta, const MaterialSet::Material& mat); + void BuildShaders(const hecl::HMDLMeta& meta, + std::vector>& shaders); + void BuildShaders(const hecl::HMDLMeta& meta) { BuildShaders(meta, m_shaders); } }; enum class ESurfaceSelection @@ -101,7 +106,8 @@ private: CBooModel* m_next = nullptr; CBooModel* m_prev = nullptr; size_t m_uniUpdateCount = 0; - TLockedToken m_model; + TToken m_modelTok; + CModel* m_model; std::vector* x0_surfaces; const MaterialSet* x4_matSet; int m_matSetIdx = -1; @@ -161,9 +167,11 @@ private: static float g_TransformedTime2; static CBooModel* g_LastModelCached; + static bool g_DummyTextures; + public: ~CBooModel(); - CBooModel(TToken& token, std::vector* surfaces, SShader& shader, + CBooModel(TToken& token, CModel* parent, std::vector* surfaces, SShader& shader, boo::IVertexFormat* vtxFmt, boo::IGraphicsBufferS* vbo, boo::IGraphicsBufferS* ibo, const zeus::CAABox& aabb, u8 renderMask, int numInsts, boo::ITexture* txtrOverrides[8]); @@ -178,6 +186,8 @@ public: void ActivateLights(const std::vector& lights); void DisableAllLights(); void RemapMaterialData(SShader& shader); + void RemapMaterialData(SShader& shader, + const std::vector>& pipelines); bool TryLockTextures() const; void UnlockTextures() const; void SyncLoadTextures() const; @@ -197,6 +207,9 @@ public: const CPoseAsTransforms* pose) const; void DrawFlat(ESurfaceSelection sel, EExtendedShader extendedIdx) const; + void LockParent() { m_modelTok.Lock(); } + void UnlockParent() { m_modelTok.Unlock(); } + const MaterialSet::Material& GetMaterialByIndex(int idx) const { @@ -220,6 +233,8 @@ public: static zeus::CTransform g_shadowTexXf; static void EnableShadowMaps(boo::ITexture* map, const zeus::CTransform& texXf); static void DisableShadowMaps(); + + static void SetDummyTextures(bool b) { g_DummyTextures = true; } }; class CModel @@ -258,7 +273,9 @@ public: 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, boo::ITexture* txtrOverrides[8] = nullptr); + std::unique_ptr MakeNewInstance(int shaderIdx, int subInsts, + boo::ITexture* txtrOverrides[8] = nullptr, + bool lockParent = true); void UpdateLastFrame() const { const_cast(*this).x38_lastFrame = CGraphics::GetFrameCounter(); } size_t GetPoolVertexOffset(size_t idx) const; diff --git a/Runtime/Graphics/CModelBoo.cpp b/Runtime/Graphics/CModelBoo.cpp index 9bbdf46c1..11153d885 100644 --- a/Runtime/Graphics/CModelBoo.cpp +++ b/Runtime/Graphics/CModelBoo.cpp @@ -46,6 +46,8 @@ void CBooModel::KillCachedViewDepState() g_LastModelCached = nullptr; } +bool CBooModel::g_DummyTextures = false; + zeus::CVector3f CBooModel::g_ReflectViewPos = {}; static const zeus::CMatrix4f ReflectBaseMtx = @@ -146,13 +148,13 @@ CBooModel::~CBooModel() g_FirstModel = m_next; } -CBooModel::CBooModel(TToken& token, std::vector* surfaces, SShader& shader, +CBooModel::CBooModel(TToken& token, CModel* parent, std::vector* surfaces, SShader& shader, boo::IVertexFormat* vtxFmt, boo::IGraphicsBufferS* vbo, boo::IGraphicsBufferS* ibo, const zeus::CAABox& aabb, u8 renderMask, int numInsts, boo::ITexture* txtrOverrides[8]) -: m_model(token), x0_surfaces(surfaces), x4_matSet(&shader.m_matSet), m_matSetIdx(shader.m_matSetIdx), - m_pipelines(&shader.m_shaders), x1c_textures(shader.x0_textures), x20_aabb(aabb), - x40_24_texturesLoaded(false), x40_25_modelVisible(0), x41_mask(renderMask), +: m_modelTok(token), m_model(parent), x0_surfaces(surfaces), x4_matSet(&shader.m_matSet), + m_matSetIdx(shader.m_matSetIdx), m_pipelines(&shader.m_shaders), x1c_textures(shader.x0_textures), + x20_aabb(aabb), x40_24_texturesLoaded(false), x40_25_modelVisible(0), x41_mask(renderMask), m_staticVtxFmt(vtxFmt), m_staticVbo(vbo), m_staticIbo(ibo) { if (txtrOverrides) @@ -224,7 +226,7 @@ boo::IVertexFormat* CBooModel::ModelInstance::GetBooVtxFmt(const CBooModel& mode CBooModel::ModelInstance* CBooModel::PushNewModelInstance() { - if (!x40_24_texturesLoaded) + if (!x40_24_texturesLoaded && !g_DummyTextures) return nullptr; if (m_instances.size() >= 256) @@ -233,7 +235,7 @@ CBooModel::ModelInstance* CBooModel::PushNewModelInstance() ModelInstance& newInst = m_instances.back(); size_t skinBankCount = 0; size_t weightVecCount = 0; - if (const CModel* model = m_model.GetObj()) + if (const CModel* model = m_model) { skinBankCount = model->m_hmdlMeta.bankCount; weightVecCount = model->m_hmdlMeta.weightCount; @@ -276,6 +278,7 @@ CBooModel::ModelInstance* CBooModel::PushNewModelInstance() } /* Animated UV transform matrices */ + size_t matCount = x4_matSet->materials.size(); for (const MaterialSet::Material& mat : x4_matSet->materials) { size_t thisSz = ROUND_UP_256(/*mat.uvAnims.size()*/ 8 * (sizeof(zeus::CMatrix4f) * 2)); @@ -341,6 +344,10 @@ CBooModel::ModelInstance* CBooModel::PushNewModelInstance() { texs[texCount++] = overtex; } + else if (g_DummyTextures) + { + texs[texCount++] = g_Renderer->x220_sphereRamp; + } else { TCachedToken& tex = x1c_textures[idx]; @@ -472,6 +479,17 @@ void CBooModel::RemapMaterialData(SShader& shader) m_instances.clear(); } +void CBooModel::RemapMaterialData(SShader& shader, + const std::vector>& pipelines) +{ + x4_matSet = &shader.m_matSet; + m_matSetIdx = shader.m_matSetIdx; + x1c_textures = shader.x0_textures; + m_pipelines = &pipelines; + x40_24_texturesLoaded = false; + m_instances.clear(); +} + bool CBooModel::TryLockTextures() const { if (!x40_24_texturesLoaded) @@ -614,13 +632,10 @@ void CBooModel::WarmupDrawSurface(const CBooSurface& surf) const return; const ModelInstance& inst = m_instances[m_uniUpdateCount-1]; - for (const std::vector& extendeds : inst.m_shaderDataBindings) + for (boo::IShaderDataBinding* binding : inst.m_shaderDataBindings[surf.selfIdx]) { - for (boo::IShaderDataBinding* binding : extendeds) - { - CGraphics::SetShaderDataBinding(binding); - CGraphics::DrawArrayIndexed(surf.m_data.idxStart, std::min(u32(3), surf.m_data.idxCount)); - } + CGraphics::SetShaderDataBinding(binding); + CGraphics::DrawArrayIndexed(surf.m_data.idxStart, std::min(u32(3), surf.m_data.idxCount)); } } @@ -816,7 +831,7 @@ boo::IGraphicsBufferD* CBooModel::UpdateUniformData(const CModelFlags& flags, { size_t skinBankCount = 0; size_t weightVecCount = 0; - if (const CModel* model = m_model.GetObj()) + if (const CModel* model = m_model) { skinBankCount = model->m_hmdlMeta.bankCount; weightVecCount = model->m_hmdlMeta.weightCount; @@ -1024,13 +1039,44 @@ static const u8* MemoryFromPartData(const u8*& dataCur, const u32*& secSizeCur) return ret; } -std::unique_ptr CModel::MakeNewInstance(int shaderIdx, int subInsts, boo::ITexture* txtrOverrides[8]) +std::unique_ptr CModel::MakeNewInstance(int shaderIdx, int subInsts, + boo::ITexture* txtrOverrides[8], + bool lockParent) { if (shaderIdx >= x18_matSets.size()) shaderIdx = 0; - return std::make_unique(m_selfToken, &x8_surfaces, x18_matSets[shaderIdx], + auto ret = std::make_unique(m_selfToken, this, &x8_surfaces, x18_matSets[shaderIdx], m_staticVtxFmt, m_staticVbo, m_ibo, m_aabb, (m_flags & 0x2) != 0, subInsts, txtrOverrides); + if (lockParent) + ret->LockParent(); + return ret; +} + +std::shared_ptr +CBooModel::SShader::BuildShader(const hecl::HMDLMeta& meta, const MaterialSet::Material& mat) +{ + hecl::Backend::ReflectionType reflectionType; + if (mat.flags.samusReflectionIndirectTexture()) + reflectionType = hecl::Backend::ReflectionType::Indirect; + else if (mat.flags.samusReflection()) + reflectionType = hecl::Backend::ReflectionType::Simple; + else + reflectionType = hecl::Backend::ReflectionType::None; + hecl::Runtime::ShaderTag tag(mat.heclIr, + meta.colorCount, meta.uvCount, meta.weightCount, + meta.weightCount * 4, 8, boo::Primitive(meta.topology), + reflectionType, true, true, true); + return CModelShaders::g_ModelShaders->buildExtendedShader + (tag, mat.heclIr, "CMDL", *CGraphics::g_BooFactory); +} + +void CBooModel::SShader::BuildShaders(const hecl::HMDLMeta& meta, + std::vector>& shaders) +{ + shaders.reserve(m_matSet.materials.size()); + for (const MaterialSet::Material& mat : m_matSet.materials) + shaders.push_back(BuildShader(meta, mat)); } CModel::CModel(std::unique_ptr&& in, u32 /* dataLen */, IObjectStore* store, CObjectReference* selfRef) @@ -1072,25 +1118,7 @@ CModel::CModel(std::unique_ptr&& in, u32 /* dataLen */, IObjectStore* stor const u8* surfInfo = MemoryFromPartData(dataCur, secSizeCur); for (CBooModel::SShader& matSet : x18_matSets) - { - matSet.m_shaders.reserve(matSet.m_matSet.materials.size()); - for (const MaterialSet::Material& mat : matSet.m_matSet.materials) - { - hecl::Backend::ReflectionType reflectionType; - if (mat.flags.samusReflectionIndirectTexture()) - reflectionType = hecl::Backend::ReflectionType::Indirect; - else if (mat.flags.samusReflection()) - reflectionType = hecl::Backend::ReflectionType::Simple; - else - reflectionType = hecl::Backend::ReflectionType::None; - hecl::Runtime::ShaderTag tag(mat.heclIr, - m_hmdlMeta.colorCount, m_hmdlMeta.uvCount, m_hmdlMeta.weightCount, - m_hmdlMeta.weightCount * 4, 8, boo::Primitive(m_hmdlMeta.topology), - reflectionType, true, true, true); - matSet.m_shaders.push_back(CModelShaders::g_ModelShaders->buildExtendedShader - (tag, mat.heclIr, "CMDL", *CGraphics::g_BooFactory)); - } - } + matSet.BuildShaders(m_hmdlMeta); m_gfxToken = CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { @@ -1131,7 +1159,7 @@ CModel::CModel(std::unique_ptr&& in, u32 /* dataLen */, IObjectStore* stor const float* aabbPtr = reinterpret_cast(data.get() + 0xc); m_aabb = zeus::CAABox(hecl::SBig(aabbPtr[0]), hecl::SBig(aabbPtr[1]), hecl::SBig(aabbPtr[2]), hecl::SBig(aabbPtr[3]), hecl::SBig(aabbPtr[4]), hecl::SBig(aabbPtr[5])); - x28_modelInst = MakeNewInstance(0, 1); + x28_modelInst = MakeNewInstance(0, 1, nullptr, false); } void CBooModel::SShader::UnlockTextures() @@ -1228,6 +1256,7 @@ void CModel::ApplyVerticesCPU(boo::IGraphicsBufferD* vertBuf, void CModel::_WarmupShaders() { + CBooModel::SetDummyTextures(true); CBooModel::EnableShadowMaps(g_Renderer->x220_sphereRamp, zeus::CTransform::Identity()); CGraphics::CProjectionState backupProj = CGraphics::GetProjectionState(); zeus::CTransform backupViewPoint = CGraphics::g_ViewMatrix; @@ -1239,7 +1268,6 @@ void CModel::_WarmupShaders() for (CBooModel::SShader& shader : x18_matSets) { GetInstance().RemapMaterialData(shader); - GetInstance().SyncLoadTextures(); GetInstance().UpdateUniformData(defaultFlags, nullptr, nullptr); GetInstance().WarmupDrawSurfaces(); } @@ -1247,6 +1275,7 @@ void CModel::_WarmupShaders() CGraphics::SetViewPointMatrix(backupViewPoint); CGraphics::SetModelMatrix(backupModel); CBooModel::DisableShadowMaps(); + CBooModel::SetDummyTextures(false); } void CModel::WarmupShaders(const SObjectTag& cmdlTag) diff --git a/Runtime/Graphics/Shaders/CAABoxShaderMetal.cpp b/Runtime/Graphics/Shaders/CAABoxShaderMetal.cpp index 7542c6cbb..a1f1e8d1f 100644 --- a/Runtime/Graphics/Shaders/CAABoxShaderMetal.cpp +++ b/Runtime/Graphics/Shaders/CAABoxShaderMetal.cpp @@ -28,7 +28,7 @@ static const char* VS = "{\n" " VertToFrag vtf;\n" " vtf.color = bu.color;\n" -" vtf.pos = bu.xf * vec4(v.posIn.xyz, 1.0);\n" +" vtf.pos = bu.xf * float4(v.posIn.xyz, 1.0);\n" " return vtf;\n" "}\n"; diff --git a/Runtime/Graphics/Shaders/CModelShaders.hpp b/Runtime/Graphics/Shaders/CModelShaders.hpp index 31d687f17..0dde8ef14 100644 --- a/Runtime/Graphics/Shaders/CModelShaders.hpp +++ b/Runtime/Graphics/Shaders/CModelShaders.hpp @@ -33,7 +33,6 @@ class CModelShaders { friend class CModel; hecl::Runtime::ShaderCacheManager m_shaderCache; - static std::experimental::optional g_ModelShaders; static hecl::Runtime::ShaderCacheExtensions GetShaderExtensions(boo::IGraphicsDataFactory::Platform plat); static hecl::Runtime::ShaderCacheExtensions GetShaderExtensionsGLSL(boo::IGraphicsDataFactory::Platform plat); static hecl::Runtime::ShaderCacheExtensions GetShaderExtensionsHLSL(boo::IGraphicsDataFactory::Platform plat); @@ -42,6 +41,8 @@ class CModelShaders static const hecl::Backend::TextureInfo BallFadeTextures[]; static const hecl::Backend::TextureInfo WorldShadowTextures[]; public: + static std::experimental::optional g_ModelShaders; + struct Light { zeus::CVector3f pos; diff --git a/Runtime/Graphics/Shaders/CModelShadersGLSL.cpp b/Runtime/Graphics/Shaders/CModelShadersGLSL.cpp index ec5090ad0..4b5c97a30 100644 --- a/Runtime/Graphics/Shaders/CModelShadersGLSL.cpp +++ b/Runtime/Graphics/Shaders/CModelShadersGLSL.cpp @@ -248,15 +248,7 @@ CModelShaders::GetShaderExtensionsGLSL(boo::IGraphicsDataFactory::Platform plat) hecl::Backend::BlendFactor::SrcAlpha, hecl::Backend::BlendFactor::InvSrcAlpha, hecl::Backend::ZTest::Equal, - false, false, false, true); - - /* MorphBall shadow shading */ - ext.registerExtensionSlot({}, {MBShadowPostGLSL, "MBShadowPostFunc"}, - 3, MBShadowBlockNames, 3, BallFadeTextures, - hecl::Backend::BlendFactor::SrcAlpha, - hecl::Backend::BlendFactor::InvSrcAlpha, - hecl::Backend::ZTest::Equal, - false, false, false, true); + false, false, false, true, true); /* World shadow shading (modified lighting) */ ext.registerExtensionSlot({LightingShadowGLSL, "LightingShadowFunc"}, {MainPostGLSL, "MainPostFunc"}, diff --git a/Runtime/Graphics/Shaders/CModelShadersHLSL.cpp b/Runtime/Graphics/Shaders/CModelShadersHLSL.cpp index 0a2b87d4e..eaf3c2690 100644 --- a/Runtime/Graphics/Shaders/CModelShadersHLSL.cpp +++ b/Runtime/Graphics/Shaders/CModelShadersHLSL.cpp @@ -231,7 +231,7 @@ CModelShaders::GetShaderExtensionsHLSL(boo::IGraphicsDataFactory::Platform plat) hecl::Backend::BlendFactor::SrcAlpha, hecl::Backend::BlendFactor::InvSrcAlpha, hecl::Backend::ZTest::Equal, - false, false, false, true); + false, false, false, true, true); /* World shadow shading (modified lighting) */ ext.registerExtensionSlot({LightingShadowHLSL, "LightingShadowFunc"}, {MainPostHLSL, "MainPostFunc"}, diff --git a/Runtime/Graphics/Shaders/CModelShadersMetal.cpp b/Runtime/Graphics/Shaders/CModelShadersMetal.cpp index 57a7805fd..27ae6f559 100644 --- a/Runtime/Graphics/Shaders/CModelShadersMetal.cpp +++ b/Runtime/Graphics/Shaders/CModelShadersMetal.cpp @@ -126,7 +126,7 @@ static const char* ThermalPostMetal = " float4 tmulColor;\n" " float4 addColor;\n" "};\n" -"static float4 ThermalPostFunc(thread VertToFrag& vtf, constant ThermalUniform& lu, texture2d extTex7, float4 colorIn)\n" +"static float4 EXTThermalPostFunc(thread VertToFrag& vtf, constant ThermalUniform& lu, texture2d extTex7, float4 colorIn)\n" "{\n" " return float4(extTex7.sample(samp, vtf.extTcgs0).rrr * lu.tmulColor.rgb + lu.addColor.rgb, 1.0);\n" "}\n" @@ -149,8 +149,8 @@ static const char* MBShadowPostMetal = " float4 shadowUp;\n" " float shadowId;\n" "};\n" -"static float4 MBShadowPostFunc(thread VertToFrag& vtf, constant MBShadowUniform& su,\n" -" texture2d extTex0, texture2d extTex1, texture2d extTex2, float4 colorIn)\n" +"static float4 EXTMBShadowPostFunc(thread VertToFrag& vtf, constant MBShadowUniform& su,\n" +" texture2d extTex0, texture2d extTex1, texture2d extTex2, float4 colorIn)\n" "{\n" " float idTexel = extTex0.sample(samp, vtf.extTcgs0).a;\n" " float sphereTexel = extTex1.sample(samp, vtf.extTcgs1).a;\n" @@ -179,7 +179,7 @@ CModelShaders::GetShaderExtensionsMetal(boo::IGraphicsDataFactory::Platform plat false, false, false, true); /* Thermal Visor shading */ - ext.registerExtensionSlot({}, {ThermalPostMetal, "ThermalPostFunc"}, 1, ThermalBlockNames, + ext.registerExtensionSlot({}, {ThermalPostMetal, "EXTThermalPostFunc"}, 1, ThermalBlockNames, 1, ThermalTextures, hecl::Backend::BlendFactor::One, hecl::Backend::BlendFactor::One, hecl::Backend::ZTest::Original, false, false, false, true); @@ -233,12 +233,12 @@ CModelShaders::GetShaderExtensionsMetal(boo::IGraphicsDataFactory::Platform plat false, true, true, false); /* MorphBall shadow shading */ - ext.registerExtensionSlot({}, {MBShadowPostMetal, "MBShadowPostFunc"}, + ext.registerExtensionSlot({}, {MBShadowPostMetal, "EXTMBShadowPostFunc"}, 1, MBShadowBlockNames, 3, BallFadeTextures, hecl::Backend::BlendFactor::SrcAlpha, hecl::Backend::BlendFactor::InvSrcAlpha, hecl::Backend::ZTest::Equal, - false, false, false, true); + false, false, false, true, true); /* World shadow shading (modified lighting) */ ext.registerExtensionSlot({LightingShadowMetal, "EXTLightingShadowFunc"}, {MainPostMetal, "MainPostFunc"}, diff --git a/Runtime/Graphics/Shaders/CParticleSwooshShadersGLSL.cpp b/Runtime/Graphics/Shaders/CParticleSwooshShadersGLSL.cpp index 88fe99026..19c17fe2a 100644 --- a/Runtime/Graphics/Shaders/CParticleSwooshShadersGLSL.cpp +++ b/Runtime/Graphics/Shaders/CParticleSwooshShadersGLSL.cpp @@ -73,7 +73,7 @@ struct OGLParticleSwooshDataBindingFactory : TShader::ID CSwooshDescription* desc = gen.GetDesc(); CUVElement* texr = desc->x3c_TEXR.get(); - boo::ITexture* textures[] = {texr->GetValueTexture(0).GetObj()->GetBooTexture()}; + boo::ITexture* textures[] = {texr ? texr->GetValueTexture(0).GetObj()->GetBooTexture() : nullptr}; const boo::VertexElementDescriptor VtxFmt[] = { diff --git a/Runtime/Graphics/Shaders/CParticleSwooshShadersHLSL.cpp b/Runtime/Graphics/Shaders/CParticleSwooshShadersHLSL.cpp index 64e1d3810..4d240cd8c 100644 --- a/Runtime/Graphics/Shaders/CParticleSwooshShadersHLSL.cpp +++ b/Runtime/Graphics/Shaders/CParticleSwooshShadersHLSL.cpp @@ -71,7 +71,7 @@ struct D3DParticleSwooshDataBindingFactory : TShader::ID CSwooshDescription* desc = gen.GetDesc(); CUVElement* texr = desc->x3c_TEXR.get(); - boo::ITexture* textures[] = {texr->GetValueTexture(0).GetObj()->GetBooTexture()}; + boo::ITexture* textures[] = {texr ? texr->GetValueTexture(0).GetObj()->GetBooTexture() : nullptr}; boo::IGraphicsBuffer* uniforms[] = {gen.m_uniformBuf}; gen.m_dataBind = ctx.newShaderDataBinding(shaders.m_pipeline, CParticleSwooshShaders::m_vtxFormat, diff --git a/Runtime/Graphics/Shaders/CParticleSwooshShadersMetal.cpp b/Runtime/Graphics/Shaders/CParticleSwooshShadersMetal.cpp index f775ff8d9..48a8a94ae 100644 --- a/Runtime/Graphics/Shaders/CParticleSwooshShadersMetal.cpp +++ b/Runtime/Graphics/Shaders/CParticleSwooshShadersMetal.cpp @@ -77,7 +77,7 @@ struct MetalParticleSwooshDataBindingFactory : TShader:: CSwooshDescription* desc = gen.GetDesc(); CUVElement* texr = desc->x3c_TEXR.get(); - boo::ITexture* textures[] = {texr->GetValueTexture(0).GetObj()->GetBooTexture()}; + boo::ITexture* textures[] = {texr ? texr->GetValueTexture(0).GetObj()->GetBooTexture() : nullptr}; boo::IGraphicsBuffer* uniforms[] = {gen.m_uniformBuf}; gen.m_dataBind = ctx.newShaderDataBinding(shaders.m_pipeline, CParticleSwooshShaders::m_vtxFormat, diff --git a/Runtime/Graphics/Shaders/CPhazonSuitFilterMetal.cpp b/Runtime/Graphics/Shaders/CPhazonSuitFilterMetal.cpp index 5d34e4935..e4eace7c1 100644 --- a/Runtime/Graphics/Shaders/CPhazonSuitFilterMetal.cpp +++ b/Runtime/Graphics/Shaders/CPhazonSuitFilterMetal.cpp @@ -116,9 +116,9 @@ static const char* BlurVS = "vertex VertToFrag vmain(VertData v [[ stage_in ]], constant PhazonSuitBlurUniform& psu [[ buffer(2) ]])\n" "{\n" " VertToFrag vtf;\n" -" vtf.uv = uvIn.xy;\n" -" vtf.blurDir = blurDir.xy;\n" -" vtf.position = float4(posIn.xyz, 1.0);\n" +" vtf.uv = v.uvIn.xy;\n" +" vtf.blurDir = psu.blurDir.xy;\n" +" vtf.position = float4(v.posIn.xyz, 1.0);\n" " return vtf;\n" "}\n"; diff --git a/Runtime/MP1/MP1.cpp b/Runtime/MP1/MP1.cpp index f06ef2519..f0c2f0ecf 100644 --- a/Runtime/MP1/MP1.cpp +++ b/Runtime/MP1/MP1.cpp @@ -270,6 +270,21 @@ void CMain::InitializeSubsystems(const hecl::Runtime::FileStoreManager& storeMgr CGBASupport::Initialize(); } +void CMain::MemoryCardInitializePump() +{ + if (!g_MemoryCardSys) + { + std::unique_ptr& memSys = x128_globalObjects.x0_memoryCardSys; + if (!memSys) + memSys.reset(new CMemoryCardSys()); + if (memSys->InitializePump()) + { + g_MemoryCardSys = memSys.get(); + g_GameState->InitializeMemoryStates(); + } + } +} + void CMain::FillInAssetIDs() { } @@ -326,6 +341,7 @@ void CMain::WarmupShaders() if (m_warmupTags.size()) return; + m_needsWarmupClear = true; size_t modelCount = 0; g_ResFactory->EnumerateResources([&](const SObjectTag& tag) { @@ -376,6 +392,11 @@ void CMain::Draw() // Warmup cycle overrides draw if (m_warmupTags.size()) { + if (m_needsWarmupClear) + { + CGraphics::g_BooMainCommandQueue->clearTarget(true, true); + m_needsWarmupClear = false; + } auto startTime = std::chrono::steady_clock::now(); while (m_warmupIt != m_warmupTags.end()) { @@ -400,6 +421,7 @@ void CMain::Draw() return; } + CGraphics::g_BooMainCommandQueue->clearTarget(true, true); x164_archSupport->Draw(); } diff --git a/Runtime/MP1/MP1.hpp b/Runtime/MP1/MP1.hpp index 7b3c90232..3ffdd3861 100644 --- a/Runtime/MP1/MP1.hpp +++ b/Runtime/MP1/MP1.hpp @@ -243,6 +243,7 @@ private: // Warmup state std::vector m_warmupTags; std::vector::iterator m_warmupIt; + bool m_needsWarmupClear = false; void InitializeSubsystems(const hecl::Runtime::FileStoreManager& storeMgr); @@ -269,20 +270,7 @@ public: void Shutdown(); boo::IWindow* GetMainWindow() const; - void MemoryCardInitializePump() - { - if (!g_MemoryCardSys) - { - std::unique_ptr& memSys = x128_globalObjects.x0_memoryCardSys; - if (!memSys) - memSys.reset(new CMemoryCardSys()); - if (memSys->InitializePump()) - { - g_MemoryCardSys = memSys.get(); - g_GameState->InitializeMemoryStates(); - } - } - } + void MemoryCardInitializePump(); bool CheckReset() { return false; } bool CheckTerminate() { return false; } diff --git a/Runtime/MkCastTo.py b/Runtime/MkCastTo.py index ce6a38809..b163552ed 100644 --- a/Runtime/MkCastTo.py +++ b/Runtime/MkCastTo.py @@ -168,13 +168,13 @@ namespace urde { template -TCastToPtr::TCastToPtr(CEntity* p) { p->Accept(*this); } +TCastToPtr::TCastToPtr(CEntity* p) { if (p) p->Accept(*this); else ptr = nullptr; } template TCastToPtr::TCastToPtr(CEntity& p) { p.Accept(*this); } template -TCastToPtr& TCastToPtr::operator=(CEntity* p) { p->Accept(*this); return *this; } +TCastToPtr& TCastToPtr::operator=(CEntity* p) { if (p) p->Accept(*this); else ptr = nullptr; return *this; } template TCastToPtr& TCastToPtr::operator=(CEntity& p) { p.Accept(*this); return *this; } diff --git a/Runtime/World/CGameArea.cpp b/Runtime/World/CGameArea.cpp index 80b611b77..83bfcc236 100644 --- a/Runtime/World/CGameArea.cpp +++ b/Runtime/World/CGameArea.cpp @@ -414,16 +414,16 @@ CGameArea::CGameArea(CInputStream& in, int idx, int mlvlVersion) CGameArea::CGameArea(CAssetId mreaId) : x84_mrea(mreaId) { - while (StartStreamingMainArea()) {} - - for (auto& req : xf8_loadTransactions) - req->WaitForComplete(); + while (StartStreamingMainArea()) + for (auto& req : xf8_loadTransactions) + req->WaitForComplete(); MREAHeader header = VerifyHeader(); - x12c_postConstructed->x4c_insts.reserve(header.modelCount); + x12c_postConstructed->x4c_insts.resize(header.modelCount); - FillInStaticGeometry(); + FillInStaticGeometry(false); + CBooModel::SetDummyTextures(true); CBooModel::EnableShadowMaps(g_Renderer->x220_sphereRamp, zeus::CTransform::Identity()); CGraphics::CProjectionState backupProj = CGraphics::GetProjectionState(); zeus::CTransform backupViewPoint = CGraphics::g_ViewMatrix; @@ -434,7 +434,6 @@ CGameArea::CGameArea(CAssetId mreaId) for (CMetroidModelInstance& inst : x12c_postConstructed->x4c_insts) { CGraphics::SetModelMatrix(zeus::CTransform::Translate(-inst.x34_aabb.center())); - inst.m_instance->SyncLoadTextures(); inst.m_instance->UpdateUniformData(defaultFlags, nullptr, nullptr); inst.m_instance->WarmupDrawSurfaces(); } @@ -442,6 +441,7 @@ CGameArea::CGameArea(CAssetId mreaId) CGraphics::SetViewPointMatrix(backupViewPoint); CGraphics::SetModelMatrix(backupModel); CBooModel::DisableShadowMaps(); + CBooModel::SetDummyTextures(false); } bool CGameArea::IGetScriptingMemoryAlways() const @@ -932,7 +932,7 @@ void CGameArea::PostConstructArea() u32 sec = 3; /* Models */ - x12c_postConstructed->x4c_insts.reserve(header.modelCount); + x12c_postConstructed->x4c_insts.resize(header.modelCount); for (u32 i=0 ; i((secIt+4)->first)); @@ -1051,26 +1051,28 @@ void CGameArea::PostConstructArea() } } -void CGameArea::FillInStaticGeometry() +void CGameArea::FillInStaticGeometry(bool textures) { - x12c_postConstructed->x4c_insts.clear(); + if (!x12c_postConstructed->x4c_insts.empty()) + for (CMetroidModelInstance& inst : x12c_postConstructed->x4c_insts) + inst.Clear(); /* Materials */ + CBooModel::SShader& matSet = x12c_postConstructed->m_materialSet; auto secIt = m_resolvedBufs.begin() + 2; { athena::io::MemoryReader r(secIt->first, secIt->second); - x12c_postConstructed->m_materialSet.m_matSet.read(r); + matSet.m_matSet.read(r); + if (textures) + CBooModel::MakeTexturesFromMats(matSet.m_matSet, matSet.x0_textures, *g_SimplePool); ++secIt; } x12c_postConstructed->m_gfxToken = CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { /* Models */ - for (u32 i=0 ; ix4c_insts.capacity() ; ++i) + for (CMetroidModelInstance& inst : x12c_postConstructed->x4c_insts) { - x12c_postConstructed->x4c_insts.emplace_back(); - CMetroidModelInstance& inst = x12c_postConstructed->x4c_insts.back(); - { DataSpec::DNAMP1::MREA::MeshHeader header; athena::io::MemoryReader r(secIt->first, secIt->second); @@ -1081,30 +1083,31 @@ void CGameArea::FillInStaticGeometry() ++secIt; } - hecl::HMDLMeta hmdlMeta; { athena::io::MemoryReader r(secIt->first, secIt->second); - hmdlMeta.read(r); + inst.m_hmdlMeta.read(r); } ++secIt; boo::IGraphicsBufferS* vbo; boo::IGraphicsBufferS* ibo; boo::IVertexFormat* vtxFmt; - vbo = ctx.newStaticBuffer(boo::BufferUse::Vertex, secIt->first, hmdlMeta.vertStride, hmdlMeta.vertCount); + vbo = ctx.newStaticBuffer(boo::BufferUse::Vertex, secIt->first, inst.m_hmdlMeta.vertStride, + inst.m_hmdlMeta.vertCount); ++secIt; - ibo = ctx.newStaticBuffer(boo::BufferUse::Index, secIt->first, 4, hmdlMeta.indexCount); + ibo = ctx.newStaticBuffer(boo::BufferUse::Index, secIt->first, 4, inst.m_hmdlMeta.indexCount); ++secIt; - vtxFmt = hecl::Runtime::HMDLData::NewVertexFormat(ctx, hmdlMeta, vbo, ibo); + vtxFmt = hecl::Runtime::HMDLData::NewVertexFormat(ctx, inst.m_hmdlMeta, vbo, ibo); u32 surfCount = hecl::SBig(*reinterpret_cast(secIt->first)); inst.m_surfaces.reserve(surfCount); + inst.m_shaders.resize(matSet.m_matSet.materials.size()); ++secIt; - for (u32 i=0 ; ifirst, secIt->second); surf.m_data.read(r); ++secIt; @@ -1112,13 +1115,24 @@ void CGameArea::FillInStaticGeometry() TToken nullModel; inst.m_instance = std::make_unique - (nullModel, &inst.m_surfaces, x12c_postConstructed->m_materialSet, vtxFmt, vbo, ibo, - inst.x34_aabb, inst.x0_visorFlags, 1, nullptr); + (nullModel, nullptr, &inst.m_surfaces, matSet, vtxFmt, vbo, ibo, + inst.x34_aabb, inst.x0_visorFlags, 0, nullptr); } return true; }); + for (CMetroidModelInstance& inst : x12c_postConstructed->x4c_insts) + { + for (CBooSurface& surf : inst.m_surfaces) + { + auto& shad = inst.m_shaders[surf.m_data.matIdx]; + if (!shad) + shad = matSet.BuildShader(inst.m_hmdlMeta, matSet.m_matSet.materials[surf.m_data.matIdx]); + } + inst.m_instance->RemapMaterialData(matSet, inst.m_shaders); + } + x12c_postConstructed->x1108_25_modelsConstructed = true; } diff --git a/Runtime/World/CGameArea.hpp b/Runtime/World/CGameArea.hpp index cbe2bb63f..b1c8b582c 100644 --- a/Runtime/World/CGameArea.hpp +++ b/Runtime/World/CGameArea.hpp @@ -340,7 +340,7 @@ public: void LoadScriptObjects(CStateManager& mgr); std::pair GetLayerScriptBuffer(int layer); void PostConstructArea(); - void FillInStaticGeometry(); + void FillInStaticGeometry(bool textures = true); void VerifyTokenList(CStateManager& stateMgr); void ClearTokenList(); u32 GetPreConstructedSize() const; diff --git a/Runtime/rstl.hpp b/Runtime/rstl.hpp index 789a9dcb6..309d650ec 100644 --- a/Runtime/rstl.hpp +++ b/Runtime/rstl.hpp @@ -364,7 +364,7 @@ public: if (size > base::x0_size) { for (size_t i = base::x0_size; i < size; ++i) - ::new (static_cast(std::addressof(base::_value(i)))) T; + ::new (static_cast(std::addressof(base::_value(i)))) T(); base::x0_size = size; } else if (size < base::x0_size) @@ -428,7 +428,7 @@ class prereserved_vector : public _reserved_vector_base void _init() { for (auto& i : base::x4_data) - ::new (static_cast(std::addressof(i._value))) T; + ::new (static_cast(std::addressof(i._value))) T(); } void _deinit() { diff --git a/hecl b/hecl index f949aabf5..84393676f 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit f949aabf5c4632df97746c273cab27a1ea1bffe4 +Subproject commit 84393676f125f87c443b770738b552015998228d diff --git a/visigen/MainMac.mm b/visigen/MainMac.mm index b8cb79390..94c4c9baf 100644 --- a/visigen/MainMac.mm +++ b/visigen/MainMac.mm @@ -59,20 +59,29 @@ static void UpdatePercent(float percent) VISIRenderer* m_renderer; NSWindow* m_window; NSOpenGLView* m_glView; + int m_instanceIdx; } -- (id)initWithRenderer:(VISIRenderer*)renderer; +- (id)initWithRenderer:(VISIRenderer*)renderer instIdx:(int)instIdx; @end @implementation AppDelegate -- (id)initWithRenderer:(VISIRenderer*)renderer +- (id)initWithRenderer:(VISIRenderer*)renderer instIdx:(int)instIdx { self = [super init]; m_renderer = renderer; + m_instanceIdx = instIdx; return self; } - (void)applicationDidFinishLaunching:(NSNotification*)notification { - NSRect cRect = NSMakeRect(100, 100, 768, 512); + int x = 0; + int y = 0; + if (m_instanceIdx != -1) + { + x = (m_instanceIdx & 1) != 0; + y = (m_instanceIdx & 2) != 0; + } + NSRect cRect = NSMakeRect(x * 768, y * 534, 768, 512); m_window = [[NSWindow alloc] initWithContentRect:cRect styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable backing:NSBackingStoreBuffered @@ -109,12 +118,15 @@ int main(int argc, const char** argv) logvisor::RegisterConsoleLogger(); atSetExceptionHandler(AthenaExc); VISIRenderer renderer(argc, argv); + int instIdx = -1; + if (argc > 3) + instIdx = atoi(argv[3]); @autoreleasepool { [[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular]; /* Delegate (OS X callbacks) */ - AppDelegate* appDelegate = [[AppDelegate alloc] initWithRenderer:&renderer]; + AppDelegate* appDelegate = [[AppDelegate alloc] initWithRenderer:&renderer instIdx:instIdx]; [[NSApplication sharedApplication] setDelegate:appDelegate]; [[NSApplication sharedApplication] run]; } diff --git a/visigen/MainWin.cpp b/visigen/MainWin.cpp index e88538d83..496e079f6 100644 --- a/visigen/MainWin.cpp +++ b/visigen/MainWin.cpp @@ -56,6 +56,10 @@ int wmain(int argc, const hecl::SystemChar** argv) VISIRenderer renderer(argc, argv); s_Renderer = &renderer; + int instIdx = -1; + if (argc > 3) + instIdx = _wtoi(argv[3]); + WNDCLASS wndClass = { CS_NOCLOSE, @@ -74,8 +78,16 @@ int wmain(int argc, const hecl::SystemChar** argv) RECT clientRect = {0, 0, 768, 512}; AdjustWindowRect(&clientRect, dwStyle, FALSE); + int x = 0; + int y = 0; + if (instIdx != -1) + { + x = (instIdx & 1) != 0; + y = (instIdx & 2) != 0; + } + HWND window = CreateWindowW(L"VISIGenWindow", L"VISIGen", dwStyle, - 100, 100, + x, y, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, NULL, NULL, NULL, NULL); diff --git a/visigen/MainXlib.cpp b/visigen/MainXlib.cpp index f6dbf2f45..5f42709f2 100644 --- a/visigen/MainXlib.cpp +++ b/visigen/MainXlib.cpp @@ -194,7 +194,19 @@ int main(int argc, const char** argv) swa.border_pixmap = 0; swa.event_mask = 0; - windowId = XCreateWindow(xDisp, screen->root, 0, 0, 768, 512, 10, + int instIdx = -1; + if (argc > 3) + instIdx = atoi(argv[3]); + + int x = 0; + int y = 0; + if (instIdx != -1) + { + x = (instIdx & 1) != 0; + y = (instIdx & 2) != 0; + } + + windowId = XCreateWindow(xDisp, screen->root, x, y, 768, 512, 10, CopyFromParent, CopyFromParent, selectedVisual, CWBorderPixel | CWEventMask | CWColormap, &swa); diff --git a/visigen/VISIBuilder.cpp b/visigen/VISIBuilder.cpp index a337198eb..be1138e93 100644 --- a/visigen/VISIBuilder.cpp +++ b/visigen/VISIBuilder.cpp @@ -1,6 +1,11 @@ #include "VISIBuilder.hpp" #include +#ifndef _WIN32 +#include +#include +#endif + #define VISI_MAX_LEVEL 10 #define VISI_MIN_LENGTH 8.0 @@ -31,8 +36,8 @@ const VISIBuilder::Leaf& VISIBuilder::PVSRenderCache::GetLeaf(const zeus::CVecto { const VISIRenderer::RGBA8& pixel = RGBABuf[i]; uint32_t id = (pixel.b << 16) | (pixel.g << 8) | pixel.r; - if (id != 0xffffff) - leafOut->setBit(id); + if (id != 0) + leafOut->setBit(id - 1); } auto setBitLambda = [&](int idx) { leafOut->setBit(idx); }; @@ -51,16 +56,16 @@ const VISIBuilder::Leaf& VISIBuilder::PVSRenderCache::GetLeaf(const zeus::CVecto void VISIBuilder::Progress::report(int divisions) { m_prog += 1.f / divisions; - printf(" %g%% \r", m_prog * 100.f); - fflush(stdout); + //printf(" %g%% \r", m_prog * 100.f); + //fflush(stdout); if (m_updatePercent) m_updatePercent(m_prog); } void VISIBuilder::Node::buildChildren(int level, int divisions, const zeus::CAABox& curAabb, - PVSRenderCache& rc, Progress& prog, const bool& terminate) + PVSRenderCache& rc, Progress& prog, const std::function& terminate) { - if (terminate) + if (terminate()) return; // Recurse in while building node structure @@ -316,9 +321,10 @@ std::vector VISIBuilder::build(const zeus::CAABox& fullAabb, renderCache.m_lightMetaBit = featureCount; Progress prog(updatePercent); - bool& terminate = renderCache.m_renderer.m_terminate; + pid_t parentPid = getppid(); + auto terminate = [this, parentPid]() { return renderCache.m_renderer.m_terminate || kill(parentPid, 0); }; rootNode.buildChildren(0, 1, fullAabb, renderCache, prog, terminate); - if (terminate) + if (terminate()) return {}; // Lights cache their CPVSVisSet result enum as 2 bits @@ -365,7 +371,6 @@ std::vector VISIBuilder::build(const zeus::CAABox& fullAabb, w.seekAlign32(); - printf("\n"); Log.report(logvisor::Info, "Finished!"); return dataOut; } diff --git a/visigen/VISIBuilder.hpp b/visigen/VISIBuilder.hpp index c9ae9e54a..cab507fa4 100644 --- a/visigen/VISIBuilder.hpp +++ b/visigen/VISIBuilder.hpp @@ -105,7 +105,7 @@ struct VISIBuilder uint8_t flags = 0; void buildChildren(int level, int divisions, const zeus::CAABox& curAabb, - PVSRenderCache& rc, Progress& prog, const bool& terminate); + PVSRenderCache& rc, Progress& prog, const std::function& terminate); void calculateSizesAndOffs(size_t& cur, size_t leafSz); void writeNodes(athena::io::MemoryWriter& w, size_t leafBytes) const; diff --git a/visigen/VISIRenderer.cpp b/visigen/VISIRenderer.cpp index 6932f81f4..4c2d87d42 100644 --- a/visigen/VISIRenderer.cpp +++ b/visigen/VISIRenderer.cpp @@ -110,8 +110,6 @@ bool VISIRenderer::SetupShaders() glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_aabbIBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 20 * 4, AABBIdxs, GL_STATIC_DRAW); - glGenQueries(1, &m_query); - return true; } @@ -138,6 +136,7 @@ std::vector VISIRenderer::AABBToVerts(const zeus::CAA static zeus::CColor ColorForIndex(int i) { + i += 1; return zeus::CColor((i & 0xff) / 255.f, ((i >> 8) & 0xff) / 255.f, ((i >> 16) & 0xff) / 255.f, @@ -202,6 +201,11 @@ bool VISIRenderer::SetupVertexBuffersAndFormats() glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), (void*)16); } + m_queryCount = m_models.size() + m_entities.size() + m_lights.size(); + m_queries.reset(new GLuint[m_queryCount]); + m_queryBools.reset(new bool[m_queryCount]); + glGenQueries(GLsizei(m_queryCount), m_queries.get()); + return true; } @@ -277,7 +281,7 @@ void VISIRenderer::RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bo glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); - glClearColor(1.f, 1.f, 1.f, 1.f); + glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); for (int j=0 ; j<6 ; ++j) @@ -297,26 +301,6 @@ void VISIRenderer::RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bo zeus::CFrustum frustum; frustum.updatePlanes(mv, g_Proj); - // Fill depth buffer with backfaces initially - glCullFace(GL_FRONT); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - - for (const Model& model : m_models) - { - if (!frustum.aabbFrustumTest(model.aabb)) - continue; - glBindVertexArray(model.vao); - for (const Model::Surface& surf : model.surfaces) - { - // Non-transparents first - if (!surf.transparent) - glDrawElements(model.topology, surf.count, GL_UNSIGNED_INT, - reinterpret_cast(uintptr_t(surf.first * 4))); - else - needTransparent = true; - } - } - // Draw frontfaces glCullFace(GL_BACK); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -362,6 +346,8 @@ void VISIRenderer::RenderPVSTransparent(const std::function& passFunc zeus::CFrustum frustum; frustum.updatePlanes(mv, g_Proj); + memset(m_queryBools.get(), 0, m_queryCount); + int idx = 0; for (const Model& model : m_models) { @@ -371,23 +357,29 @@ void VISIRenderer::RenderPVSTransparent(const std::function& passFunc continue; } glBindVertexArray(model.vao); + glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, m_queries[idx]); + m_queryBools[idx] = true; for (const Model::Surface& surf : model.surfaces) { // transparents if (surf.transparent) - { - glBeginQuery(GL_ANY_SAMPLES_PASSED, m_query); glDrawElements(model.topology, surf.count, GL_UNSIGNED_INT, reinterpret_cast(uintptr_t(surf.first * 4))); - glEndQuery(GL_ANY_SAMPLES_PASSED); - GLint res; - glGetQueryObjectiv(m_query, GL_QUERY_RESULT, &res); - if (res) - passFunc(idx); - } } + glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE); ++idx; } + + for (int i=0 ; i& pa zeus::CFrustum frustum; frustum.updatePlanes(mv, g_Proj); + memset(m_queryBools.get(), 0, m_queryCount); + int idx = m_models.size(); for (const Entity& ent : m_entities) { @@ -423,36 +417,56 @@ void VISIRenderer::RenderPVSEntitiesAndLights(const std::function& pa continue; } glBindVertexArray(ent.vao); - glBeginQuery(GL_ANY_SAMPLES_PASSED, m_query); + m_queryBools[idx] = true; + glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, m_queries[idx]); glDrawElements(GL_TRIANGLE_STRIP, 20, GL_UNSIGNED_INT, 0); - glEndQuery(GL_ANY_SAMPLES_PASSED); - GLint res; - glGetQueryObjectiv(m_query, GL_QUERY_RESULT, &res); - if (res) - passFunc(idx); + glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE); + ++idx; + } + + for (const Light& light : m_lights) + { + if (!frustum.pointFrustumTest(light.point)) + { + ++idx; + continue; + } + glBindVertexArray(light.vao); + m_queryBools[idx] = true; + glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, m_queries[idx]); + glDrawArrays(GL_POINTS, 0, 1); + glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE); + ++idx; + } + + idx = m_models.size(); + for (const Entity& ent : m_entities) + { + if (m_queryBools[idx]) + { + GLint res; + glGetQueryObjectiv(m_queries[idx], GL_QUERY_RESULT, &res); + if (res) + passFunc(idx); + } ++idx; } int lightIdx = 0; for (const Light& light : m_lights) { - if (!frustum.pointFrustumTest(light.point)) + if (m_queryBools[idx]) { - ++lightIdx; - continue; + GLint res; + glGetQueryObjectiv(m_queries[idx], GL_QUERY_RESULT, &res); + EPVSVisSetState state = m_totalAABB.pointInside(light.point) ? + EPVSVisSetState::EndOfTree : EPVSVisSetState::OutOfBounds; + if (res && state == EPVSVisSetState::EndOfTree) + state = EPVSVisSetState::NodeFound; + lightPassFunc(lightIdx, state); } - glBindVertexArray(light.vao); - glBeginQuery(GL_ANY_SAMPLES_PASSED, m_query); - glDrawArrays(GL_POINTS, 0, 1); - glEndQuery(GL_ANY_SAMPLES_PASSED); - GLint res; - glGetQueryObjectiv(m_query, GL_QUERY_RESULT, &res); - EPVSVisSetState state = m_totalAABB.pointInside(light.point) ? - EPVSVisSetState::EndOfTree : EPVSVisSetState::OutOfBounds; - if (res && state == EPVSVisSetState::EndOfTree) - state = EPVSVisSetState::NodeFound; - lightPassFunc(lightIdx, state); ++lightIdx; + ++idx; } } } diff --git a/visigen/VISIRenderer.hpp b/visigen/VISIRenderer.hpp index 916160ba0..33189860e 100644 --- a/visigen/VISIRenderer.hpp +++ b/visigen/VISIRenderer.hpp @@ -78,7 +78,9 @@ class VISIRenderer std::vector m_lights; bool SetupVertexBuffersAndFormats(); - GLuint m_query; + size_t m_queryCount; + std::unique_ptr m_queries; + std::unique_ptr m_queryBools; FPercent m_updatePercent;