Import art objects in level

This commit is contained in:
Citlali del Rey 2023-11-20 15:19:07 -08:00
parent 9a197dabe7
commit 0f4f852528
Signed by: nullobsi
GPG Key ID: 933A1F44222C2634
2 changed files with 222 additions and 78 deletions

View File

@ -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<IOStream> 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<IOStream> 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<IOStream> 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<IOStream> 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()};
}
}
}

View File

@ -4,6 +4,8 @@
#include <assimp/BaseImporter.h>
#include <assimp/XmlParser.h>
#include <assimp/mesh.h>
#include <assimp/material.h>
#include <assimp/texture.h>
#include <map>
#include <filesystem>
@ -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<int, XmlNode> mTriles;
std::map<int, unsigned int> mTrileMap;
std::vector<aiMesh*> mTrileMeshes;
std::map<std::string, unsigned int> mAOMap;
std::vector<aiMesh*> mMeshes;
std::vector<aiMaterial*> mMaterials;
std::vector<aiTexture*> mTextures;
unsigned int GetArtObjectFromName(const std::string &name, IOSystem *pIOHandler);
};
}