#include "IO/Model/Model.h" namespace lwe { Model::Model() { AddType("Model"); } Model::Model(const Str_8& filePath) { AddType("Model"); File file(filePath, Mode::READ, Disposition::OPEN); hashId = file.GetName().Hash_64(); id = file.GetName(); if (file.GetExtension() == "ehm") { FromEHM(file); } } Model::Model(Str_8 id, Array meshes, Bone skeleton, Array animations) : Resource(std::move(id)), meshes(std::move(meshes)), skeleton(std::move(skeleton)), animations(std::move(animations)) { AddType("Model"); } Model::Model(Str_8 id, Array meshes, Bone skeleton) : Resource(std::move(id)), meshes(std::move(meshes)), skeleton(std::move(skeleton)) { AddType("Model"); } Model::Model(Str_8 id, Array meshes) : Resource(std::move(id)), meshes(std::move(meshes)) { AddType("Model"); } Model::Model(Model&& model) noexcept : Resource(std::move(model)), meshes(std::move(model.meshes)), skeleton(std::move(model.skeleton)), animations(std::move(model.animations)) { } Model& Model::operator=(Model&& model) noexcept { if (this == &model) return *this; hashId = model.hashId; id = std::move(model.id); meshes = std::move(model.meshes); skeleton = std::move(model.skeleton); animations = std::move(model.animations); model.hashId = 0; return *this; } bool Model::UploadToGpu(GpuCmdBuffer* cmdBuffer) { for (UInt_64 i = 0; i < meshes.Size(); ++i) if (!meshes[i].UploadToGpu(cmdBuffer)) return false; return true; } bool Model::PostGpuUpload() { bool result = true; for (UInt_64 i = 0; i < meshes.Size(); ++i) if (!meshes[i].PostGpuUpload()) result = false; return result; } bool Model::ReleaseFromGpu() { bool result = true; for (UInt_64 i = 0; i < meshes.Size(); ++i) if (!meshes[i].ReleaseFromGpu()) result = false; return result; } bool Model::IsUploaded() const { return meshes[0].IsUploaded(); } void Model::Draw(GpuCmdBuffer* cmdBuffer, const UInt_32 instances) { for (UInt_64 i = 0; i < meshes.Size(); ++i) { meshes[i].Bind(cmdBuffer); meshes[i].Draw(cmdBuffer, instances); } } Array Model::GetMeshes() const { return meshes; } Array& Model::GetMeshes() { return meshes; } Mesh* Model::GetMesh(const UInt_64 hashId) { for (UInt_64 i = 0; i < meshes.Size(); ++i) if (meshes[i].GetHashId() == hashId) return &meshes[i]; return nullptr; } Mesh* Model::GetMesh(const Str_8& id) { return GetMesh(id.Hash_64()); } Bone Model::GetSkeleton() const { return skeleton; } Bone& Model::GetSkeleton() { return skeleton; } Animation* Model::GetAnimation(const UInt_64 hashId) { for (UInt_64 i = 0; i < animations.Size(); ++i) if (animations[i].GetHashId() == hashId) return &animations[i]; return nullptr; } Array Model::GetAnimations() const { return animations; } Array& Model::GetAnimations() { return animations; } void Model::Calculate() { for (UInt_64 i = 0; i < meshes.Size(); ++i) meshes[i].Calculate(); } void Model::Export(const Str_8& filePath, const ModelEncoding encoding) { File file(filePath, Mode::WRITE, Disposition::OPEN_PERSISTENT); switch (encoding) { case ModelEncoding::EHM: { ToEHM(file); break; } } } void Model::ToEHM(File& file) { Serializer data(Endianness::LE); data.WriteVersion({1, 0, 0}); data.Write(meshes.Size()); for (UInt_64 i = 0; i < meshes.Size(); ++i) { data.WriteStr(meshes[i].GetId()); Array vertices = meshes[i].GetVertices(); data.Write(vertices.Size()); for (UInt_64 v = 0; v < vertices.Size(); ++v) { data.WriteVec3(vertices[v].pos); data.WriteVec3(vertices[v].normal); data.WriteVec2(vertices[v].uv); } } file.WriteSerializer_64(data); file.Truncate(data.Size()); } void Model::FromEHM(File& file) { Serializer data = file.ReadSerializer_64(Endianness::LE, file.Size()); Version ver = data.ReadVersion(); if (ver != Version(1, 0, 0)) { LWE_LOG_INT("Error", 0, "Cannot decode EHM file version " + Str_8::FromNum(ver.major) + "." + Str_8::FromNum(ver.minor) + "." + Str_8::FromNum(ver.patch) + ", must be version 0.0.0."); return; } meshes.Resize(data.Read()); for (UInt_64 i = 0; i < meshes.Size(); ++i) { meshes[i].SetId(data.ReadStr()); meshes[i].SetParent(this); Array& vertices = meshes[i].GetVertices(); vertices.Resize(data.Read()); for (UInt_64 v = 0; v < vertices.Size(); ++v) { vertices[v].pos = data.ReadVec3(); vertices[v].normal = data.ReadVec3(); vertices[v].uv = data.ReadVec2(); vertices[v].bones = data.ReadVec4(); vertices[v].weights = data.ReadVec4(); } meshes[i].SetIndices(data.ReadArray()); UInt_8 boneCount = data.Read(); for (UInt_8 b = 0; b < boneCount; ++b) { Str_8 name = data.ReadStr(); UInt_8 parentId = data.Read(); Mat4_f localBindTrans = data.ReadMat4(); Mat4_f invBindTrans = data.ReadMat4(); if (b == 0) { skeleton = {name, b, localBindTrans, invBindTrans}; } else { Bone* parent = skeleton.GetBone(parentId); if (!parent) { LWE_LOG_INT("Error", 0, "Invalid bone order."); return; } parent->AddBone({name, b, localBindTrans, invBindTrans}); } } animations = Array(data.Read()); for (UInt_64 a = 0; a < animations.Size(); ++a) { Str_8 animId = data.ReadStr(); float duration = data.Read(); animations[a] = Animation(animId, duration, data.Read()); Array& animated = animations[a].GetAnimated(); for (UInt_8 ba = 0; ba < (UInt_8)animated.Size(); ++ba) { UInt_8 boneId = data.Read(); animated[ba] = AnimBone(boneId, data.Read()); Array& keyFrames = animated[ba].GetKeyFrames(); for (UInt_64 kf = 0; kf < keyFrames.Size(); ++kf) { float num = data.Read(); float timeStamp = data.Read(); Vec3_f pos = data.ReadVec3(); Quat_f rot = data.ReadQuat(); Vec3_f scale = data.ReadVec3(); keyFrames[kf] = KeyFrame(num, timeStamp, pos, rot, scale); } } } } } }