mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 19:36:20 +03:00
281 lines
7.8 KiB
C++
281 lines
7.8 KiB
C++
#include "XFileModel.h"
|
|
|
|
#define TINYXLOADER_IMPLEMENTATION
|
|
#include <tinyxfileloader/include/tinyxfileloader.h>
|
|
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
#include "../../Base/Path.h"
|
|
#include "../../Base/File.h"
|
|
#include "../../Base/Log.h"
|
|
|
|
namespace saba
|
|
{
|
|
namespace
|
|
{
|
|
glm::mat4 InvZ(const glm::mat4& m)
|
|
{
|
|
const glm::mat4 invZ = glm::scale(glm::mat4(1), glm::vec3(1, 1, -1));
|
|
return invZ * m * invZ;
|
|
}
|
|
}
|
|
|
|
bool XFileModel::Load(const char* filepath)
|
|
{
|
|
Destroy();
|
|
|
|
TextFileReader textReader;
|
|
if (!textReader.Open(filepath))
|
|
{
|
|
SABA_WARN("Failed to open file.[{}]", filepath);
|
|
return false;
|
|
}
|
|
std::string text = textReader.ReadAll();
|
|
std::stringstream ss(text);
|
|
|
|
tinyxfile::XFile xfile;
|
|
tinyxfile::XFileLoader loader;
|
|
if (!loader.Load(ss, &xfile))
|
|
{
|
|
SABA_WARN("Failed to open file.[{}]", filepath);
|
|
SABA_WARN("XFileLoader message : {}", loader.GetErrorMessage());
|
|
return false;
|
|
}
|
|
|
|
|
|
std::string fileDir = PathUtil::GetDirectoryName(filepath);
|
|
|
|
std::map<Frame*, tinyxfile::Frame*> toXFrameMap;
|
|
std::map<tinyxfile::Frame*, Frame*> fromXFrameMap;
|
|
for (const auto& xfileFrame : xfile.m_frames)
|
|
{
|
|
FrameUPtr newFrame = std::make_unique<Frame>();
|
|
Frame* frame = newFrame.get();
|
|
m_frames.emplace_back(std::move(newFrame));
|
|
|
|
toXFrameMap[frame] = xfileFrame.get();
|
|
fromXFrameMap[xfileFrame.get()] = frame;
|
|
|
|
frame->m_name = xfileFrame->m_name;
|
|
frame->m_parent = nullptr;
|
|
frame->m_child = nullptr;
|
|
frame->m_next = nullptr;
|
|
frame->m_local[0][0] = xfileFrame->m_transform.m[0];
|
|
frame->m_local[0][1] = xfileFrame->m_transform.m[1];
|
|
frame->m_local[0][2] = xfileFrame->m_transform.m[2];
|
|
frame->m_local[0][3] = xfileFrame->m_transform.m[3];
|
|
|
|
frame->m_local[1][0] = xfileFrame->m_transform.m[4];
|
|
frame->m_local[1][1] = xfileFrame->m_transform.m[5];
|
|
frame->m_local[1][2] = xfileFrame->m_transform.m[6];
|
|
frame->m_local[1][3] = xfileFrame->m_transform.m[7];
|
|
|
|
frame->m_local[2][0] = xfileFrame->m_transform.m[8];
|
|
frame->m_local[2][1] = xfileFrame->m_transform.m[9];
|
|
frame->m_local[2][2] = xfileFrame->m_transform.m[10];
|
|
frame->m_local[2][3] = xfileFrame->m_transform.m[11];
|
|
|
|
frame->m_local[3][0] = xfileFrame->m_transform.m[12];
|
|
frame->m_local[3][1] = xfileFrame->m_transform.m[13];
|
|
frame->m_local[3][2] = xfileFrame->m_transform.m[14];
|
|
frame->m_local[3][3] = xfileFrame->m_transform.m[15];
|
|
|
|
frame->m_local = InvZ(frame->m_local);
|
|
|
|
if (xfileFrame->m_mesh.m_positions.size() != 0)
|
|
{
|
|
const auto& xfileMesh = xfileFrame->m_mesh;
|
|
|
|
// check face num
|
|
const size_t numFaces = xfileMesh.m_positionFaces.size();
|
|
if (numFaces != xfileMesh.m_normalFaces.size() || numFaces != xfileMesh.m_faceMaterials.size())
|
|
{
|
|
SABA_ERROR("XFile face size error.");
|
|
return false;
|
|
}
|
|
|
|
// check uv num
|
|
if (xfileMesh.m_positions.size() != xfileMesh.m_textureCoords.size())
|
|
{
|
|
SABA_ERROR("XFile uv size error.");
|
|
return false;
|
|
}
|
|
|
|
MeshUPtr newMesh = std::make_unique<Mesh>();
|
|
Mesh* mesh = newMesh.get();
|
|
m_meshes.emplace_back(std::move(newMesh));
|
|
frame->m_mesh = mesh;
|
|
|
|
mesh->m_name = xfileMesh.m_name;
|
|
|
|
// position
|
|
m_bboxMax = glm::vec3(-std::numeric_limits<float>::max());
|
|
m_bboxMin = glm::vec3(std::numeric_limits<float>::max());
|
|
mesh->m_positions.reserve(xfileMesh.m_positions.size());
|
|
for (const auto& xfilePos : xfileMesh.m_positions)
|
|
{
|
|
auto pos = glm::vec3(xfilePos.x, xfilePos.y, -xfilePos.z) * 10.0f;
|
|
mesh->m_positions.push_back(pos);
|
|
m_bboxMax = glm::max(m_bboxMax, pos);
|
|
m_bboxMin = glm::min(m_bboxMin, pos);
|
|
}
|
|
|
|
// normal
|
|
mesh->m_normals.reserve(xfileMesh.m_normals.size());
|
|
for (const auto& xfileNor : xfileMesh.m_normals)
|
|
{
|
|
mesh->m_normals.emplace_back(glm::vec3(xfileNor.x, xfileNor.y, -xfileNor.z));
|
|
}
|
|
|
|
// uv
|
|
mesh->m_uvs.reserve(xfileMesh.m_textureCoords.size());
|
|
for (const auto& xfileUV : xfileMesh.m_textureCoords)
|
|
{
|
|
mesh->m_uvs.emplace_back(glm::vec2(xfileUV.x, 1.0f - xfileUV.y));
|
|
}
|
|
|
|
// material
|
|
mesh->m_materials.reserve(xfileMesh.m_materials.size());
|
|
for (const auto& xfileMat : xfileMesh.m_materials)
|
|
{
|
|
Material mat;
|
|
mat.m_diffuse = glm::vec4(xfileMat.m_diffuse.r, xfileMat.m_diffuse.g, xfileMat.m_diffuse.b, xfileMat.m_diffuse.a);
|
|
mat.m_specular = glm::vec3(xfileMat.m_specular.r, xfileMat.m_specular.g, xfileMat.m_specular.b);
|
|
mat.m_speculatPower = xfileMat.m_specularPower;
|
|
mat.m_emissive = glm::vec3(xfileMat.m_emissive.r, xfileMat.m_emissive.g, xfileMat.m_emissive.b);
|
|
mat.m_spTextureMode = Material::SpTextureMode::None;
|
|
if (!xfileMat.m_texture.empty())
|
|
{
|
|
auto spPos = xfileMat.m_texture.find('*');
|
|
if (spPos == std::string::npos)
|
|
{
|
|
std::string ext = PathUtil::GetExt(xfileMat.m_texture);
|
|
if (ext == "sph")
|
|
{
|
|
mat.m_spTextureMode = Material::SpTextureMode::Mul;
|
|
mat.m_spTexture = PathUtil::Combine(fileDir, xfileMat.m_texture);
|
|
}
|
|
else if (ext == "spa")
|
|
{
|
|
mat.m_spTextureMode = Material::SpTextureMode::Add;
|
|
mat.m_spTexture = PathUtil::Combine(fileDir, xfileMat.m_texture);
|
|
}
|
|
else
|
|
{
|
|
mat.m_texture = PathUtil::Combine(fileDir, xfileMat.m_texture);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string texture = xfileMat.m_texture.substr(0, spPos);
|
|
std::string spTexture = xfileMat.m_texture.substr(spPos + 1);
|
|
if (!texture.empty())
|
|
{
|
|
mat.m_texture = PathUtil::Combine(fileDir, texture);
|
|
}
|
|
mat.m_spTexture = PathUtil::Combine(fileDir, spTexture);
|
|
|
|
std::string ext = PathUtil::GetExt(spTexture);
|
|
if (ext == "sph")
|
|
{
|
|
mat.m_spTextureMode = Material::SpTextureMode::Mul;
|
|
}
|
|
else if (ext == "spa")
|
|
{
|
|
mat.m_spTextureMode = Material::SpTextureMode::Add;
|
|
}
|
|
}
|
|
}
|
|
mesh->m_materials.emplace_back(mat);
|
|
}
|
|
|
|
// face
|
|
mesh->m_faces.reserve(numFaces);
|
|
for (size_t i = 0; i < numFaces; i++)
|
|
{
|
|
Face face;
|
|
face.m_position[0] = xfileMesh.m_positionFaces[i].v1;
|
|
face.m_position[1] = xfileMesh.m_positionFaces[i].v3;
|
|
face.m_position[2] = xfileMesh.m_positionFaces[i].v2;
|
|
|
|
face.m_normal[0] = xfileMesh.m_normalFaces[i].v1;
|
|
face.m_normal[1] = xfileMesh.m_normalFaces[i].v3;
|
|
face.m_normal[2] = xfileMesh.m_normalFaces[i].v2;
|
|
|
|
face.m_uv[0] = xfileMesh.m_positionFaces[i].v1;
|
|
face.m_uv[1] = xfileMesh.m_positionFaces[i].v3;
|
|
face.m_uv[2] = xfileMesh.m_positionFaces[i].v2;
|
|
|
|
face.m_material = xfileMesh.m_faceMaterials[i];
|
|
|
|
mesh->m_faces.emplace_back(face);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Frame Link
|
|
for (auto& frame : m_frames)
|
|
{
|
|
const auto& xfileFrame = toXFrameMap[frame.get()];
|
|
if (xfileFrame->m_parent != nullptr)
|
|
{
|
|
frame->m_parent = fromXFrameMap[xfileFrame->m_parent];
|
|
}
|
|
for (const auto& xfileChildFrame : xfileFrame->m_childFrames)
|
|
{
|
|
if (frame->m_child == nullptr)
|
|
{
|
|
frame->m_child = fromXFrameMap[xfileChildFrame];
|
|
}
|
|
else
|
|
{
|
|
Frame* child = frame->m_child;
|
|
while (child->m_next != nullptr)
|
|
{
|
|
child = child->m_next;
|
|
}
|
|
child->m_next = fromXFrameMap[xfileChildFrame];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update Global Transfrom
|
|
for (auto& frame : m_frames)
|
|
{
|
|
if (frame->m_parent == nullptr)
|
|
{
|
|
UpdateGlobalTransform(frame.get());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void XFileModel::Destroy()
|
|
{
|
|
m_meshes.clear();
|
|
m_frames.clear();
|
|
}
|
|
|
|
void XFileModel::UpdateGlobalTransform(Frame * frame)
|
|
{
|
|
if (frame->m_parent != nullptr)
|
|
{
|
|
frame->m_global = frame->m_parent->m_global * frame->m_local;
|
|
}
|
|
else
|
|
{
|
|
frame->m_global = frame->m_local;
|
|
}
|
|
|
|
auto child = frame->m_child;
|
|
while (child != nullptr)
|
|
{
|
|
UpdateGlobalTransform(child);
|
|
child = child->m_next;
|
|
}
|
|
}
|
|
}
|