593 lines
19 KiB
C++
593 lines
19 KiB
C++
#ifndef ASSIMP_BUILD_NO_FEZ_IMPORTER
|
|
|
|
#include "FezLoader.h"
|
|
#include <filesystem>
|
|
#include <assimp/Importer.hpp>
|
|
#include <assimp/DefaultLogger.hpp>
|
|
#include <assimp/importerdesc.h>
|
|
#include <assimp/ParsingUtils.h>
|
|
#include <assimp/XmlParser.h>
|
|
#include <assimp/IOSystem.hpp>
|
|
#include <assimp/scene.h>
|
|
#include <Common/StbCommon.h>
|
|
|
|
namespace Assimp {
|
|
|
|
static const aiImporterDesc desc = {
|
|
"FEZ Importer",
|
|
"Kayden",
|
|
"",
|
|
"Unfinished.",
|
|
aiImporterFlags_Experimental | aiImporterFlags_LimitedSupport | aiImporterFlags_SupportTextFlavour,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
"xml",
|
|
};
|
|
|
|
static const aiVector3D gc_normals[] = { {-1.f, 0.f, 0.f}, {0.f, -1.f, 0.f}, {0.f, 0.f, -1.f},
|
|
{1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f} };
|
|
|
|
static const ai_real gc_orient[] = {
|
|
AI_MATH_PI, -AI_MATH_HALF_PI, 0,AI_MATH_HALF_PI,
|
|
};
|
|
|
|
|
|
FezLoader::FezLoader() = default;
|
|
FezLoader::~FezLoader() = default;
|
|
|
|
bool FezLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool) const {
|
|
// TODO: Read single art objects too
|
|
static const char *tokens[] = { "<Level" };
|
|
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
|
}
|
|
|
|
const aiImporterDesc *FezLoader::GetInfo() const {
|
|
return &desc;
|
|
};
|
|
|
|
void FezLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
|
// Store filename
|
|
mFileName = pFile;
|
|
|
|
// Find asset directory (two levels up)
|
|
mFezAssetDir = std::filesystem::path(pFile).parent_path().parent_path();
|
|
|
|
// Open file for reading
|
|
std::unique_ptr<IOStream> levelFile;
|
|
levelFile.reset(pIOHandler->Open(pFile));
|
|
|
|
// generate a XML reader for it
|
|
if (!mLevelParser.parse(levelFile.get())) {
|
|
throw DeadlyImportError("Unable to read level file, malformed XML");
|
|
}
|
|
|
|
// Load trile sets
|
|
auto levelRoot = mLevelParser.getRootNode().child("Level");
|
|
auto levelName = std::string(levelRoot.attribute("name").as_string());
|
|
|
|
// Fill in root node
|
|
pScene->mRootNode = new aiNode(levelName);
|
|
|
|
// Get trile set name in lowercase (all the files from export are lowercased)
|
|
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")));
|
|
|
|
if (!mTrileParser.parse(trileFile.get())) {
|
|
throw DeadlyImportError("Unable to read trile file, malformed XML");
|
|
}
|
|
|
|
ASSIMP_LOG_VERBOSE_DEBUG("Parsed trile set ", mTrileParser.getRootNode().child("TrileSet").attribute("name").as_string());
|
|
|
|
// Place triles and their XML nodes into map
|
|
auto triles = mTrileParser.getRootNode().child("TrileSet").child("Triles");
|
|
for (auto t : triles.children()) {
|
|
if (std::string(t.name()) != "TrileEntry") {
|
|
ASSIMP_LOG_WARN("Unknown tag found in TrileSet XML.");
|
|
continue;
|
|
}
|
|
|
|
auto key = t.attribute("key").as_int(-1);
|
|
if (key == -1) {
|
|
ASSIMP_LOG_ERROR("Trile found with an invalid key or non-int key. This could be bad!");
|
|
continue;
|
|
}
|
|
auto trile = t.child("Trile");
|
|
if (mTriles.count(key)) {
|
|
ASSIMP_LOG_WARN("Duplicate trile key found, skipping...");
|
|
continue;
|
|
}
|
|
mTriles[key] = trile;
|
|
}
|
|
|
|
ASSIMP_LOG_VERBOSE_DEBUG("Loaded ", mTriles.size(), " triles from the set.");
|
|
|
|
// Create children, one for the triles
|
|
auto trileRoot = new aiNode("Triles");
|
|
pScene->mRootNode->addChildren(1, &trileRoot);
|
|
|
|
// Begin filling out trile nodes
|
|
auto xmlTrileT = levelRoot.child("Triles");
|
|
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 aoName = std::string(instance.attribute("name").as_string("INVALID"));
|
|
if (aoName == "INVALID") {
|
|
ASSIMP_LOG_WARN("AO instance found without a valid name!");
|
|
continue;
|
|
}
|
|
|
|
auto meshID = GetArtObjectFromName(aoName, pIOHandler);
|
|
|
|
// Create node, link found mesh
|
|
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 rotate = GetFezQuat(instance.child("Rotation"));
|
|
auto scale = GetFezVec3(instance.child("Scale"));
|
|
|
|
aoNode->mTransformation = aiMatrix4x4 (scale, rotate, pos);
|
|
|
|
aoRoot->addChildren(1, &aoNode);
|
|
}
|
|
|
|
// Create child for background planes
|
|
auto bgpRoot = new aiNode("Background Planes");
|
|
pScene->mRootNode->addChildren(1, &bgpRoot);
|
|
|
|
// For some reason, it needs a positioning adjustment...
|
|
aiMatrix4x4::Translation(aiVector3D(-0.5,-0.5, -0.5), bgpRoot->mTransformation);
|
|
|
|
auto xmlBGPRoot = levelRoot.child("BackgroundPlanes");
|
|
for (auto t : xmlBGPRoot.children()) {
|
|
auto nodeName = std::string(t.name());
|
|
if (nodeName != "Entry") {
|
|
ASSIMP_LOG_WARN("BackgroundPlanes child found that isn't Entry");
|
|
continue;
|
|
}
|
|
|
|
auto instance = t.child("BackgroundPlane");
|
|
auto animated = instance.attribute("animated").as_bool(false);
|
|
if (animated) {
|
|
ASSIMP_LOG_WARN("Animated BackgroundPlane found, skipping");
|
|
continue;
|
|
}
|
|
|
|
auto bgpTexName = std::string(instance.attribute("textureName").as_string());
|
|
|
|
bool found = true;
|
|
auto bgpMesh = GetBackgroundPlaneFromName(bgpTexName, pIOHandler, found);
|
|
auto mesh = mMeshes[bgpMesh];
|
|
auto mat = mMaterials[mesh->mMaterialIndex];
|
|
|
|
if (!found) {
|
|
|
|
auto doubleSided = (int)instance.attribute("doubleSided").as_bool(false);
|
|
mat->AddProperty(&doubleSided, 1, AI_MATKEY_TWOSIDED);
|
|
|
|
auto opacity = instance.attribute("opacity").as_float(1.0);
|
|
mat->AddProperty(&opacity, 1, AI_MATKEY_OPACITY);
|
|
|
|
auto xTexRepeat = (int)(!instance.attribute("xTextureRepeat").as_bool(false));
|
|
mat->AddProperty(&xTexRepeat, 1, AI_MATKEY_MAPPINGMODE_U(aiTextureType_BASE_COLOR, 0));
|
|
|
|
|
|
auto yTexRepeat = (int)(!instance.attribute("yTextureRepeat").as_bool(false));
|
|
mat->AddProperty(&yTexRepeat, 1, AI_MATKEY_MAPPINGMODE_V(aiTextureType_BASE_COLOR, 0));
|
|
|
|
// redundant probably? idk
|
|
// auto clampTex = instance.attribute("clampTexture").as_bool(false);
|
|
}
|
|
|
|
// Create node, link found mesh
|
|
auto bgpNode = new aiNode();
|
|
bgpNode->mNumMeshes = 1;
|
|
bgpNode->mMeshes = new unsigned int[1];
|
|
bgpNode->mMeshes[0] = bgpMesh;
|
|
|
|
bgpNode->mName = aiString("BGP_" + bgpTexName);
|
|
auto pos = GetFezVec3(instance.child("Position"));
|
|
auto rotate = GetFezQuat(instance.child("Rotation"));
|
|
auto scale = GetFezVec3(instance.child("Scale"));
|
|
|
|
// Get scale again from texture {
|
|
aiString texRef;
|
|
mat->Get(AI_MATKEY_TEXTURE(aiTextureType_BASE_COLOR, 0), texRef);
|
|
|
|
unsigned int texId = atoi(texRef.C_Str()+1);
|
|
aiTexture* bgpTex = mTextures[texId];
|
|
|
|
int width;
|
|
int height;
|
|
int comp;
|
|
stbi_info_from_memory(reinterpret_cast<const stbi_uc *>(bgpTex->pcData), (int)bgpTex->mWidth, &width, &height, &comp);
|
|
auto imageScaleVec = aiVector3D(scale.x * (width / 16.0f), scale.y * (height / 16.0f), scale.z * 1);
|
|
|
|
// Create transformation matrix
|
|
aiMatrix4x4 scaling = aiMatrix4x4::Scaling(imageScaleVec, scaling);
|
|
auto rmMatrix = aiMatrix4x4 (aiVector3D (1,1,1), rotate, pos);
|
|
|
|
|
|
bgpNode->mTransformation = rmMatrix * scaling;
|
|
|
|
bgpRoot->addChildren(1, &bgpNode);
|
|
}
|
|
|
|
// Fill in meshes from vector
|
|
pScene->mNumMeshes = mMeshes.size();
|
|
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
|
|
for (int i = 0; i < mMeshes.size(); i++) {
|
|
pScene->mMeshes[i] = mMeshes[i];
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
aiMesh *FezLoader::CreateMesh(const Assimp::XmlNode &xmlSIIP) {
|
|
ASSIMP_LOG_VERBOSE_DEBUG("FEZ CreateMesh called");
|
|
|
|
auto mesh = new aiMesh();
|
|
|
|
auto xmlVerts = xmlSIIP.child("Vertices");
|
|
auto xmlIdx = xmlSIIP.child("Indices");
|
|
|
|
struct vpnti {
|
|
aiVector3D pos;
|
|
int normal;
|
|
aiVector3D texCoord;
|
|
};
|
|
std::vector<vpnti> vertex;
|
|
for (auto v : xmlVerts.children()) {
|
|
auto pos = GetFezVec3(v.child("Position"));
|
|
auto normal = v.child("Normal").text().as_int();
|
|
auto texCoord = GetFezVec3(v.child("TextureCoord").child("Vector2"), true);
|
|
texCoord.y = 1 - texCoord.y;
|
|
vertex.push_back({pos, normal, texCoord});
|
|
}
|
|
|
|
// Collect indices into array
|
|
std::vector<unsigned int> idx;
|
|
for (auto i : xmlIdx.children()) {
|
|
auto id = i.text().as_uint();
|
|
idx.push_back(id);
|
|
}
|
|
|
|
// Populate mFaces with all triangles
|
|
mesh->mNumFaces = idx.size() / 3;
|
|
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
|
// Iterate in sets of 3s.
|
|
for (int i = 0; i < idx.size(); i += 3) {
|
|
mesh->mFaces[i/3].mNumIndices = 3;
|
|
mesh->mFaces[i/3].mIndices = new unsigned int[3] {
|
|
idx.at(i),
|
|
idx.at(i+2),
|
|
idx.at(i+1),
|
|
};
|
|
}
|
|
|
|
// Now populate vertices
|
|
mesh->mNumVertices = vertex.size();
|
|
mesh->mVertices = new aiVector3D[vertex.size()];
|
|
mesh->mNormals = new aiVector3D[vertex.size()];
|
|
mesh->mTextureCoords[0] = new aiVector3D[vertex.size()];
|
|
|
|
for (int i = 0; i < vertex.size(); i++) {
|
|
auto v = vertex.at(i);
|
|
mesh->mVertices[i] = v.pos;
|
|
mesh->mNormals[i] = gc_normals[v.normal];
|
|
mesh->mTextureCoords[0][i] = v.texCoord;
|
|
}
|
|
|
|
return mesh;
|
|
}
|
|
|
|
unsigned int FezLoader::GetTrileMeshFromId(const int trileId, bool &valid) {
|
|
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);
|
|
if (mesh->mNumVertices == 0) {
|
|
valid = false;
|
|
return 0;
|
|
}
|
|
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] = mMeshes.size();
|
|
mMeshes.push_back(mesh);
|
|
|
|
valid = true;
|
|
return mTrileMap[trileId];
|
|
}
|
|
|
|
unsigned int FezLoader::GetBackgroundPlaneFromName(const std::string &name, IOSystem *pIOHandler, bool &found) {
|
|
if (auto search = mBGPMap.find(name); search != mBGPMap.end()) {
|
|
found = true;
|
|
return search->second;
|
|
}
|
|
|
|
found = false;
|
|
|
|
auto BGPTexPath = mFezAssetDir / "background planes" / (ai_tolower(name) + ".png");
|
|
|
|
// Create material, mesh, and texture
|
|
auto myTex = CreateTex(BGPTexPath, pIOHandler);
|
|
auto myMesh = NewBGPlaneMesh();
|
|
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
|
|
myMesh->mMaterialIndex = mMaterials.size();
|
|
mMaterials.push_back(myMat);
|
|
|
|
// Put mesh into vector
|
|
auto i = mMeshes.size();
|
|
mBGPMap[name] = i;
|
|
mMeshes.push_back(myMesh);
|
|
|
|
// Set parameters for material
|
|
int flags = aiTextureFlags_UseAlpha;
|
|
myMat->AddProperty(&flags, 1, AI_MATKEY_TEXFLAGS(aiTextureType_BASE_COLOR, 0));
|
|
flags = aiBlendMode_Default;
|
|
myMat->AddProperty(&flags, 1, AI_MATKEY_BLEND_FUNC);
|
|
|
|
return i;
|
|
}
|
|
|
|
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");
|
|
|
|
std::string myaoname = aoXmlRoot.attribute("name").as_string();
|
|
if (myaoname != name) {
|
|
ASSIMP_LOG_WARN("Art Object name mismatch! ", name, " != ", myaoname);
|
|
}
|
|
|
|
// 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()};
|
|
} else {
|
|
auto c = t.child("Vector3");
|
|
return {c.attribute("x").as_float(), c.attribute("y").as_float(), c.attribute("z").as_float()};
|
|
}
|
|
}
|
|
aiVector2D FezLoader::GetFezVec2(const XmlNode &t, bool direct) {
|
|
if (direct) {
|
|
return {t.attribute("x").as_float(), t.attribute("y").as_float()};
|
|
} else {
|
|
auto c = t.child("Vector2");
|
|
return {c.attribute("x").as_float(), c.attribute("y").as_float()};
|
|
}
|
|
|
|
}
|
|
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;
|
|
}
|
|
|
|
bool valid = true;
|
|
auto meshID = GetTrileMeshFromId(trileID, valid);
|
|
|
|
if (!valid) {
|
|
ASSIMP_LOG_WARN("Trile instance found that's empty!");
|
|
continue;
|
|
}
|
|
|
|
// 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()};
|
|
}
|
|
}
|
|
|
|
static aiFace bgPlaneFaces[4] = {
|
|
|
|
};
|
|
aiMesh *FezLoader::NewBGPlaneMesh() {
|
|
auto myMesh = new aiMesh();
|
|
// Create plane
|
|
|
|
// Two tris
|
|
myMesh->mNumFaces = 2;
|
|
myMesh->mFaces = new aiFace[2];
|
|
myMesh->mFaces[0].mNumIndices = 3;
|
|
myMesh->mFaces[1].mNumIndices = 3;
|
|
myMesh->mFaces[0].mIndices = new unsigned int[3] {0, 2, 1};
|
|
myMesh->mFaces[1].mIndices = new unsigned int[3] {2, 0, 3};
|
|
|
|
// Four verts
|
|
myMesh->mNumVertices = 4;
|
|
myMesh->mVertices = new aiVector3D[4] {
|
|
{-0.5, 0.5, 0},
|
|
{ 0.5, 0.5, 0},
|
|
{0.5, -0.5, 0},
|
|
{-0.5, -0.5, 0},
|
|
};
|
|
|
|
// Texture coords
|
|
myMesh->mTextureCoords[0] = new aiVector3D[4] {
|
|
{0, 1, 0},
|
|
{1, 1, 0},
|
|
{1, 0, 0},
|
|
{0, 0, 0},
|
|
};
|
|
return myMesh;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|