diff --git a/code/AssetLib/FEZ/FezLoader.cpp b/code/AssetLib/FEZ/FezLoader.cpp index 861d91b66..9dc92c396 100644 --- a/code/AssetLib/FEZ/FezLoader.cpp +++ b/code/AssetLib/FEZ/FezLoader.cpp @@ -72,6 +72,22 @@ void FezLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSyst auto trileSetName = std::string(levelRoot.attribute("trileSetName").as_string()); trileSetName = ai_tolower(trileSetName); + // Create material for triles + auto myMat = new aiMaterial(); + aiString matName("TrileSet"); + myMat->AddProperty(&matName, AI_MATKEY_NAME); + + // Embed texture for triles + auto myTex = CreateTex(std::string(mFezAssetDir / "trile sets" / (trileSetName + ".png")), pIOHandler); + mTextures.push_back(myTex); + + // Put tex ref into material + aiString tName("*0"); + myMat->AddProperty(&tName, AI_MATKEY_TEXTURE(aiTextureType_BASE_COLOR, 0)); + + //store material in scene + mMaterials.push_back(myMat); + // Find and read trile set XML file std::unique_ptr trileFile; trileFile.reset(pIOHandler->Open(mFezAssetDir / "trile sets" / (trileSetName + ".xml"))); @@ -109,107 +125,83 @@ void FezLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSyst auto trileRoot = new aiNode("Triles"); pScene->mRootNode->addChildren(1, &trileRoot); - // Begin filling out trile emplacements + // Begin filling out trile nodes auto xmlTrileT = levelRoot.child("Triles"); - for (auto t : xmlTrileT.children()) { - if (std::string(t.name()) != "Entry") { - ASSIMP_LOG_WARN("Unknown tag found in Level Triles XML."); + AddTrileInstances(xmlTrileT, trileRoot); + + // Create child for art objects + auto aoRoot = new aiNode("Art Objects"); + pScene->mRootNode->addChildren(1, &aoRoot); + + // For some reason, it needs a positioning adjustment... + aiMatrix4x4::Translation(aiVector3D(-0.5,-0.5, -0.5), aoRoot->mTransformation); + + // Begin filling out art objects + auto xmlAoRoot = levelRoot.child("ArtObjects"); + for (auto t : xmlAoRoot.children()) { + XmlNode instance; + if (std::string(t.name()) == "Entry") { + instance = t.child("ArtObjectInstance"); + } else if (std::string(t.name()) == "ArtObjectInstance") { + instance = t; + } else { + ASSIMP_LOG_WARN("AO instance not found in a node."); continue; } - auto instance = t.child("TrileInstance"); - if (instance.empty()) { - ASSIMP_LOG_WARN("Trile instance not found in a node."); + auto aoName = std::string(instance.attribute("name").as_string("INVALID")); + if (aoName == "INVALID") { + ASSIMP_LOG_WARN("AO instance found without a valid name!"); continue; } - auto trileID = instance.attribute("trileId").as_int(-1); - if (trileID == -1) { - ASSIMP_LOG_WARN("Trile instance found without a valid trileId!"); - continue; - } - - auto meshID = GetTrileMeshFromId(trileID); + auto meshID = GetArtObjectFromName(aoName, pIOHandler); // Create node, link found mesh - auto trileNode = new aiNode(); - trileNode->mNumMeshes = 1; - trileNode->mMeshes = new unsigned int[1]; - trileNode->mMeshes[0] = meshID; + auto aoNode = new aiNode(); + aoNode->mNumMeshes = 1; + aoNode->mMeshes = new unsigned int[1]; + aoNode->mMeshes[0] = meshID; + aoNode->mName = aiString("AO_" + aoName); auto pos = GetFezVec3(instance.child("Position")); - auto orient = instance.attribute("orientation").as_int(0); + auto rotate = GetFezQuat(instance.child("Rotation")); + auto scale = GetFezVec3(instance.child("Scale")); - // Create transformation matrix - aiMatrix4x4 transform = aiMatrix4x4::Translation(pos, transform); - aiMatrix4x4 rotate = aiMatrix4x4::RotationY(gc_orient[orient], rotate); + aoNode->mTransformation = aiMatrix4x4 (scale, rotate, pos); - trileNode->mTransformation = transform * rotate; - - trileRoot->addChildren(1, &trileNode); + aoRoot->addChildren(1, &aoNode); } - // Fill in meshes from vector - pScene->mNumMeshes = mTrileMeshes.size(); + pScene->mNumMeshes = mMeshes.size(); pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; - for (int i = 0; i < mTrileMeshes.size(); i++) { - pScene->mMeshes[i] = mTrileMeshes[i]; + for (int i = 0; i < mMeshes.size(); i++) { + pScene->mMeshes[i] = mMeshes[i]; } - // Create material - pScene->mNumMaterials = 1; - pScene->mMaterials = new aiMaterial * [1]; + // Fill in materials from vector + pScene->mNumMaterials = mMaterials.size(); + pScene->mMaterials = new aiMaterial * [mMaterials.size()]; + for (int i = 0; i < mMaterials.size(); i++) { + pScene->mMaterials[i] = mMaterials.at(i); + } - auto myMat = new aiMaterial(); - aiString matName("TrileSet"); - myMat->AddProperty(&matName, AI_MATKEY_NAME); - aiString texturePath(std::string(mFezAssetDir / "trile sets" / (trileSetName + ".png"))); + // Fill in textures from vector + pScene->mNumTextures = mTextures.size(); + pScene->mTextures = new aiTexture *[mTextures.size()]; + for (int i = 0; i < mTextures.size(); i++) { + pScene->mTextures[i] = mTextures.at(i); + } - - // Create embedded texture ref - auto trileTex = new aiTexture(); - trileTex->mFilename = texturePath; - - // PNG file, compressed - strcpy(trileTex->achFormatHint, "png"); - trileTex->mHeight = 0; - - // Open texture file for reading - std::unique_ptr texFile; - texFile.reset(pIOHandler->Open(mFezAssetDir / "trile sets" / (trileSetName + ".png"))); - - // Create buffer, read data, store into texture instance - auto texDat = new unsigned char[texFile->FileSize()]; - trileTex->mWidth = texFile->FileSize(); - texFile->Read(texDat, 1, texFile->FileSize()); - trileTex->pcData = (aiTexel*)texDat; - - // Store embedded texture into scene - pScene->mNumTextures = 1; - pScene->mTextures = new aiTexture *[1]; - pScene->mTextures[0] = trileTex; - - // Put ref into material - aiString tName("*0"); - myMat->AddProperty(&tName, AI_MATKEY_TEXTURE(aiTextureType_BASE_COLOR, 0)); - - //store material in scene - pScene->mMaterials[0] = myMat; } -unsigned int FezLoader::GetTrileMeshFromId(const int trileId) { - if (auto search = mTrileMap.find(trileId); search != mTrileMap.end()) { - return search->second; - } - // We need to create an aiMesh instance and add it to the vector. - auto trileXML = mTriles.at(trileId); +aiMesh *FezLoader::CreateMesh(const Assimp::XmlNode &xmlSIIP) { + ASSIMP_LOG_VERBOSE_DEBUG("FEZ CreateMesh called"); + auto mesh = new aiMesh(); - auto xmlSIIP = trileXML.child("Geometry").child("ShaderInstancedIndexedPrimitives"); - // TODO: check type="TriangleList" - auto xmlVerts = xmlSIIP.child("Vertices"); auto xmlIdx = xmlSIIP.child("Indices"); @@ -261,15 +253,81 @@ unsigned int FezLoader::GetTrileMeshFromId(const int trileId) { mesh->mTextureCoords[0][i] = v.texCoord; } + return mesh; +} + +unsigned int FezLoader::GetTrileMeshFromId(const int trileId) { + if (auto search = mTrileMap.find(trileId); search != mTrileMap.end()) { + return search->second; + } + + // We need to create an aiMesh instance and add it to the vector. + auto trileXML = mTriles.at(trileId); + auto xmlSIIP = trileXML.child("Geometry").child("ShaderInstancedIndexedPrimitives"); + + // Create mesh + auto mesh = CreateMesh(xmlSIIP); + mesh->mName = "Trile#" + std::to_string(trileId); + // Only one material for all triles. mesh->mMaterialIndex = 0; // Add entry to trile map and add mesh to vector - mTrileMap[trileId] = mTrileMeshes.size(); - mTrileMeshes.push_back(mesh); + mTrileMap[trileId] = mMeshes.size(); + mMeshes.push_back(mesh); return mTrileMap[trileId]; } + +unsigned int FezLoader::GetArtObjectFromName(const std::string &name, IOSystem *pIOHandler) { + if (auto search = mAOMap.find(name); search != mAOMap.end()) { + return search->second; + } + + auto AOXmlPath = mFezAssetDir / "art objects" / (ai_tolower(name) + ".xml"); + + if (!pIOHandler->Exists(AOXmlPath)) { + ASSIMP_LOG_ERROR("Art Object specified that doesn't exist: ", name); + return 0; + } + + std::unique_ptr aoXmlFile; + aoXmlFile.reset(pIOHandler->Open(AOXmlPath)); + + XmlParser p; + p.parse(aoXmlFile.get()); + + XmlNode aoXmlRoot = p.getRootNode().child("ArtObject"); + + if (std::string(aoXmlRoot.name()) != name) { + ASSIMP_LOG_WARN("Art Object name mismatch! ", name, " != ", aoXmlRoot.name()); + } + + // Create mesh + aiMesh* m = CreateMesh(aoXmlRoot.child("ShaderInstancedIndexedPrimitives")); + m->mName = "AO_" + name; + + // Load texture + auto myTex = CreateTex(mFezAssetDir / "art objects" / (ai_tolower(name) + ".png"), pIOHandler); + + // Create material + auto myMat = new aiMaterial(); + + // Put tex ref into material + aiString tName('*' + std::to_string(mMaterials.size())); + myMat->AddProperty(&tName, AI_MATKEY_TEXTURE(aiTextureType_BASE_COLOR, 0)); + mTextures.push_back(myTex); + + // Put material ref into mesh + m->mMaterialIndex = mMaterials.size(); + mMaterials.push_back(myMat); + + auto i = mMeshes.size(); + mAOMap[name] = i; + mMeshes.push_back(m); + return i; +} + aiVector3D FezLoader::GetFezVec3(const XmlNode &t, bool direct) { if (direct) { return {t.attribute("x").as_float(), t.attribute("y").as_float(), t.attribute("z").as_float()}; @@ -287,6 +345,80 @@ aiVector2D FezLoader::GetFezVec2(const XmlNode &t, bool direct) { } } +void FezLoader::AddTrileInstances(const XmlNode &tis, aiNode *trileRoot) { + for (auto t : tis.children()) { + XmlNode instance; + if (std::string(t.name()) == "Entry") { + instance = t.child("TrileInstance"); + } else if (std::string(t.name()) == "TrileInstance") { + instance = t; + } else { + ASSIMP_LOG_WARN("Trile instance not found in a node."); + continue; + } + + auto trileID = instance.attribute("trileId").as_int(-1); + if (trileID == -1) { + ASSIMP_LOG_WARN("Trile instance found without a valid trileId!"); + continue; + } + + auto meshID = GetTrileMeshFromId(trileID); + + // Create node, link found mesh + auto trileNode = new aiNode(); + trileNode->mNumMeshes = 1; + trileNode->mMeshes = new unsigned int[1]; + trileNode->mMeshes[0] = meshID; + + trileNode->mName = aiString("Trile_ID#" + std::to_string(trileID)); + auto pos = GetFezVec3(instance.child("Position")); + auto orient = instance.attribute("orientation").as_int(0); + + // Create transformation matrix + aiMatrix4x4 transform = aiMatrix4x4::Translation(pos, transform); + aiMatrix4x4 rotate = aiMatrix4x4::RotationY(gc_orient[orient], rotate); + + trileNode->mTransformation = transform * rotate; + + trileRoot->addChildren(1, &trileNode); + + auto overlapped = instance.child("OverlappedTriles"); + if (!overlapped.empty()) { + AddTrileInstances(overlapped, trileRoot); + } + } +} + +aiTexture *FezLoader::CreateTex(const std::string &path, IOSystem *pIOHandler) { + // Create embedded texture ref + auto myTex = new aiTexture(); + myTex->mFilename = path; + + // PNG file, compressed + strcpy(myTex->achFormatHint, "png"); + myTex->mHeight = 0; + + // Open texture file for reading + std::unique_ptr texFile; + texFile.reset(pIOHandler->Open(path)); + + // Create buffer, read data, store into texture instance + auto texDat = new unsigned char[texFile->FileSize()]; + myTex->mWidth = texFile->FileSize(); + texFile->Read(texDat, 1, texFile->FileSize()); + myTex->pcData = (aiTexel*)texDat; + + return myTex; +} +aiQuaternion FezLoader::GetFezQuat(const XmlNode &t, bool direct) { + if (direct) { + return {t.attribute("w").as_float(), t.attribute("x").as_float(), t.attribute("y").as_float(), t.attribute("z").as_float()}; + } else { + auto c = t.child("Quaternion"); + return {c.attribute("w").as_float(), c.attribute("x").as_float(), c.attribute("y").as_float(), c.attribute("z").as_float()}; + } +} } diff --git a/code/AssetLib/FEZ/FezLoader.h b/code/AssetLib/FEZ/FezLoader.h index 21b366b6f..ddc47de11 100644 --- a/code/AssetLib/FEZ/FezLoader.h +++ b/code/AssetLib/FEZ/FezLoader.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -23,8 +25,14 @@ protected: unsigned int GetTrileMeshFromId(const int trileId); aiVector3D GetFezVec3(const XmlNode &t, bool direct = false); + aiQuaternion GetFezQuat(const XmlNode &t, bool direct = false); aiVector2D GetFezVec2(const XmlNode &t, bool direct = false); + void AddTrileInstances(const XmlNode &tis, aiNode *trileRoot); + + aiMesh *CreateMesh(const XmlNode &xmlSIIP); + + aiTexture *CreateTex(const std::string &path, IOSystem *pIOHandler); private: std::filesystem::path mFezAssetDir; std::string mFileName; @@ -33,7 +41,11 @@ private: std::map mTriles; std::map mTrileMap; - std::vector mTrileMeshes; + std::map mAOMap; + std::vector mMeshes; + std::vector mMaterials; + std::vector mTextures; + unsigned int GetArtObjectFromName(const std::string &name, IOSystem *pIOHandler); }; }