Dreikblack Posted 16 hours ago Posted 16 hours ago Source of Quake model loader: https://github.com/Leadwerks/PluginSDK/blob/master/Plugins/Quake Loader/Quake.h https://github.com/Leadwerks/PluginSDK/blob/9a7958b8fa821b0848ef611e66aca35c4d91e6c5/Plugins/Quake Loader/Loaders/MDL.cpp Plugin:Plugins.zip Example model (Quake 1 models can't be distributed, but this model should work too)human.zip I'm trying to set model to first animation frame, but it just breaks. I'm not sure, but probably initial mesh vertexes positions after model load should match 1st frame and it slightly off which could be related to an issue. Maybe someone can find what i'm missing. Without animations i can't finish my Slipgate Tactics project #include "Leadwerks.h" #include "ComponentSystem.h" #include <fstream> using namespace Leadwerks; const float modelScale = 4.68042326f; const WString modelPath = "human.mdl";//"player.mdl"; //scale and position void fixModel(shared_ptr<Model> model) { for (auto const& lod : model->lods) { for (auto& mesh : lod->meshes) { mesh->Translate(-mesh->bounds.center.x, -mesh->bounds.center.y, -mesh->bounds.center.z); mesh->Scale(modelScale, modelScale, modelScale); mesh->UpdateBounds(); model->UpdateBounds(); } } } struct vec3_t { float x, y, z; }; struct trivertx_t { uint8_t v[3]; // Compressed vertex coords uint8_t normalIndex; }; struct mdl_header_t { int32_t ident; int32_t version; vec3_t scale;/* scale factor */ vec3_t translate; /* translation vector */ float boundingradius; vec3_t eyeposition;/* eyes' position */ int32_t numskins; /* number of textures */ int32_t skinwidth;/* texture width */ int32_t skinheight; /* texture height */ int32_t numverts;/* number of vertices */ int32_t numtris;/* number of triangles */ int32_t numframes;/* number of frames */ int32_t synctype;/* 0 = synchron, 1 = random */ int32_t flags;/* state flag */ float size; }; struct mdl_simpleframe_t { char name[16]; std::vector<trivertx_t> vertices; }; struct AnimFrame { std::vector<Vec3> vertices; }; std::vector<AnimFrame> animationsFrames; bool AreSame(Vec3 a, Vec3 b) { return fabs(a.x - b.x) < b3d::EPSILON && fabs(a.y - b.y) < b3d::EPSILON && fabs(a.z - b.z) < b3d::EPSILON; } void setFrame(shared_ptr<Model> model, int frameId) { for (auto const& lod : model->lods) { for (auto& mesh : lod->meshes) { Print("1st mesh vertex coords: " + String(mesh->vertices[0].position.x) + " " + String(mesh->vertices[0].position.y) + " " + String(mesh->vertices[0].position.z)); vector<std::pair<int, int>> vertexPairs; for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { //Print("Vertex coords: " + String(mesh->vertices[i].position.x) + " " + String(mesh->vertices[i].position.y) + " " + String(mesh->vertices[i].position.z)); for (int j = animationsFrames[frameId].vertices.size(); j < mesh->vertices.size(); j++) { //if (AreSame(mesh->GetVertexPosition(i), mesh->GetVertexPosition(j))) { if (mesh->GetVertexPosition(i) == mesh->GetVertexPosition(j)) { vertexPairs.push_back(std::make_pair(i, j)); break; } } } for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { mesh->SetVertexPosition(i, animationsFrames[frameId].vertices[i]); } for (auto const& [original, dublicated] : vertexPairs) { mesh->SetVertexPosition(dublicated, mesh->GetVertexPosition(original)); } mesh->UpdateBounds(); model->UpdateBounds(); } } } void animations() { std::ifstream file(modelPath, std::ios::binary); if (!file) { std::cerr << "Failed to open mdl file.\n"; return; } mdl_header_t header; file.read(reinterpret_cast<char*>(&header), sizeof(mdl_header_t)); if (header.ident != 0x4F504449) { std::cerr << "Invalid MDL ident.\n"; return; } std::cout << "MDL Loaded: " << header.numframes << " frames, " << header.numverts << " verts per frame\n"; // Skip skins, tex coords, tris... int skinSize = header.numskins * header.skinwidth * header.skinheight; file.seekg(skinSize, std::ios::cur); std::vector<mdl_simpleframe_t> frames; for (int i = 0; i < header.numframes; ++i) { char name[16]; file.read(name, 16); mdl_simpleframe_t frame; std::memcpy(frame.name, name, 16); for (int j = 0; j < header.numverts; ++j) { trivertx_t v; file.read(reinterpret_cast<char*>(&v), sizeof(trivertx_t)); frame.vertices.push_back(v); } frames.push_back(frame); } for (int i = 0; i < frames.size(); i++) { AnimFrame newFrame; for (int v = 0; v < frames[i].vertices.size(); ++v) { float x = float(frames[i].vertices[v].v[1]) / 127.0f * header.scale.y + header.translate.y; float y = float(frames[i].vertices[v].v[2]) / 127.0f * header.scale.z + header.translate.z; float z = float(frames[i].vertices[v].v[0]) / 127.0f * header.scale.x + header.translate.x; newFrame.vertices.push_back(Vec3(x, y, z)); } animationsFrames.push_back(newFrame); } std::cout << "1st frame vertex coords: " << animationsFrames[0].vertices[0].x << " " << animationsFrames[0].vertices[0].y << " " << animationsFrames[0].vertices[0].z << "\n"; } int main(int argc, const char* argv[]) { RegisterComponents(); auto displays = GetDisplays(); auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); auto framebuffer = CreateFramebuffer(window); auto quakeLoaderPlugin = Core::LoadPlugin("Plugins/QuakeLoader"); //Create a world auto world = CreateWorld(); world->SetAmbientLight(Vec3(3)); //auto pak = LoadPackage(path + "/PAK0.PAK"); auto model = LoadModel(world, modelPath); //fixModel(model); model->Turn(0, 180, 0, true); //fill frame vector animations(); //Create a camera auto camera = CreateCamera(world); camera->SetPosition(model->GetBounds().center); camera->Move(0, 0, -1.5); camera->SetRotation(0, 0, 0); camera->SetRange(0.01, 100); camera->SetFov(70); camera->AddComponent<CameraControls>(); setFrame(model, 0); //Main loop while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { world->Update(); world->Render(framebuffer); } return 0; } Quote
Josh Posted 16 hours ago Posted 16 hours ago If you visualize the vertices somehow, like create a small box for each vertex in the animation data, you can probably get an idea of how the animations are oriented, and the solution will become more clear. It's very hard when you are basically double-blind. Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Dreikblack Posted 16 hours ago Author Posted 16 hours ago I don't know how to get world coordinates of vertices since local coords looks like that: -53.2006 -24.818 -25.2477 Quote
Josh Posted 16 hours ago Posted 16 hours ago I mean the animation data vertex positions. You can see the math Quake uses to store vertex positions here: https://github.com/Leadwerks/PluginSDK/blob/9a7958b8fa821b0848ef611e66aca35c4d91e6c5/Plugins/Quake Loader/Loaders/MDL.cpp#L326 Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Dreikblack Posted 16 hours ago Author Posted 16 hours ago Did that without touching model vertex positions. Frame coords are off for sure. And i don't know why is that because i did same as in plugin code #include "Leadwerks.h" #include "ComponentSystem.h" #include <fstream> using namespace Leadwerks; const float modelScale = 4.68042326f; const WString modelPath = "human.mdl";//"player.mdl"; //scale and position void fixModel(shared_ptr<Model> model) { for (auto const& lod : model->lods) { for (auto& mesh : lod->meshes) { mesh->Translate(-mesh->bounds.center.x, -mesh->bounds.center.y, -mesh->bounds.center.z); mesh->Scale(modelScale, modelScale, modelScale); mesh->UpdateBounds(); model->UpdateBounds(); } } } struct vec3_t { float x, y, z; }; struct trivertx_t { uint8_t v[3]; // Compressed vertex coords uint8_t normalIndex; }; struct mdl_header_t { int32_t ident; int32_t version; vec3_t scale;/* scale factor */ vec3_t translate; /* translation vector */ float boundingradius; vec3_t eyeposition;/* eyes' position */ int32_t numskins; /* number of textures */ int32_t skinwidth;/* texture width */ int32_t skinheight; /* texture height */ int32_t numverts;/* number of vertices */ int32_t numtris;/* number of triangles */ int32_t numframes;/* number of frames */ int32_t synctype;/* 0 = synchron, 1 = random */ int32_t flags;/* state flag */ float size; }; struct mdl_simpleframe_t { char name[16]; std::vector<trivertx_t> vertices; }; struct AnimFrame { std::vector<Vec3> vertices; }; std::vector<AnimFrame> animationsFrames; bool AreSame(Vec3 a, Vec3 b) { return fabs(a.x - b.x) < b3d::EPSILON && fabs(a.y - b.y) < b3d::EPSILON && fabs(a.z - b.z) < b3d::EPSILON; } shared_ptr<World> world; std::vector<shared_ptr<Entity>> points; void setFrame(shared_ptr<Model> model, int frameId) { for (auto const& lod : model->lods) { for (auto& mesh : lod->meshes) { Print("1st mesh vertex coords: " + String(mesh->vertices[0].position.x) + " " + String(mesh->vertices[0].position.y) + " " + String(mesh->vertices[0].position.z)); vector<std::pair<int, int>> vertexPairs; for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { //Print("Vertex coords: " + String(mesh->vertices[i].position.x) + " " + String(mesh->vertices[i].position.y) + " " + String(mesh->vertices[i].position.z)); for (int j = animationsFrames[frameId].vertices.size(); j < mesh->vertices.size(); j++) { //if (AreSame(mesh->GetVertexPosition(i), mesh->GetVertexPosition(j))) { if (mesh->GetVertexPosition(i) == mesh->GetVertexPosition(j)) { vertexPairs.push_back(std::make_pair(i, j)); break; } } } //for (auto v : mesh->vertices) { // auto point = CreateSphere(world, 0.01f, 8); // point->SetPosition(v.position); // point->SetColor(0,1,1); // points.push_back(point); //} //for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { // mesh->SetVertexPosition(i, animationsFrames[frameId].vertices[i]); // auto point = CreateSphere(world, 0.01f, 8); // point->SetColor(0, 1, 1); // point->SetPosition(animationsFrames[frameId].vertices[i]); // points.push_back(point); //} //for (auto const& [original, dublicated] : vertexPairs) { // mesh->SetVertexPosition(dublicated, mesh->GetVertexPosition(original)); // auto point = CreateSphere(world, 0.01f, 8); // point->SetColor(0, 1, 1); // point->SetPosition(mesh->GetVertexPosition(original)); // points.push_back(point); //} for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { auto point = CreateSphere(world, 0.01f, 8); point->SetColor(0, 1, 1); point->SetPosition(animationsFrames[frameId].vertices[i]); points.push_back(point); } mesh->UpdateBounds(); mesh->UpdateTangents(); mesh->UpdateNormals(); model->UpdateBounds(); } } } void animations() { std::ifstream file(modelPath, std::ios::binary); if (!file) { std::cerr << "Failed to open mdl file.\n"; return; } mdl_header_t header; file.read(reinterpret_cast<char*>(&header), sizeof(mdl_header_t)); if (header.ident != 0x4F504449) { std::cerr << "Invalid MDL ident.\n"; return; } std::cout << "MDL Loaded: " << header.numframes << " frames, " << header.numverts << " verts per frame\n"; // Skip skins, tex coords, tris... int skinSize = header.numskins * header.skinwidth * header.skinheight; file.seekg(skinSize, std::ios::cur); std::vector<mdl_simpleframe_t> frames; for (int i = 0; i < header.numframes; ++i) { char name[16]; file.read(name, 16); mdl_simpleframe_t frame; std::memcpy(frame.name, name, 16); for (int j = 0; j < header.numverts; ++j) { trivertx_t v; file.read(reinterpret_cast<char*>(&v), sizeof(trivertx_t)); frame.vertices.push_back(v); } frames.push_back(frame); } for (int i = 0; i < frames.size(); i++) { AnimFrame newFrame; for (int v = 0; v < frames[i].vertices.size(); ++v) { float x = float(frames[i].vertices[v].v[1]) / 127.0f * header.scale.y + header.translate.y; float y = float(frames[i].vertices[v].v[2]) / 127.0f * header.scale.z + header.translate.z; float z = float(frames[i].vertices[v].v[0]) / 127.0f * header.scale.x + header.translate.x; newFrame.vertices.push_back(Vec3(x, y, z)); } animationsFrames.push_back(newFrame); } std::cout << "1st frame vertex coords: " << animationsFrames[0].vertices[0].x << " " << animationsFrames[0].vertices[0].y << " " << animationsFrames[0].vertices[0].z << "\n"; } int main(int argc, const char* argv[]) { RegisterComponents(); auto displays = GetDisplays(); auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); auto framebuffer = CreateFramebuffer(window); auto quakeLoaderPlugin = Core::LoadPlugin("Plugins/QuakeLoader"); //Create a world world = CreateWorld(); world->SetAmbientLight(Vec3(3)); //auto pak = LoadPackage(path + "/PAK0.PAK"); auto model = LoadModel(world, modelPath); //fixModel(model); //model->Turn(0, 180, 0, true); //fill frame vector animations(); //Create a camera auto camera = CreateCamera(world); camera->SetPosition(model->GetBounds().center); camera->Move(0, 0, -1.5); camera->SetRotation(0, 0, 0); camera->SetRange(0.01, 100); camera->SetFov(70); camera->AddComponent<CameraControls>(); setFrame(model, 0); //Main loop while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { world->Update(); world->Render(framebuffer); } return 0; } Quote
Dreikblack Posted 14 hours ago Author Posted 14 hours ago Ah, i messed up with skipping some of data i so was not reading right coords in first play. But frame names still not correct and some vertexes are still off #include "Leadwerks.h" #include "ComponentSystem.h" #include <fstream> using namespace Leadwerks; const float modelScale = 4.68042326f; const WString modelPath = "human.mdl";//"player.mdl"; //scale and position void fixModel(shared_ptr<Model> model) { for (auto const& lod : model->lods) { for (auto& mesh : lod->meshes) { mesh->Translate(-mesh->bounds.center.x, -mesh->bounds.center.y, -mesh->bounds.center.z); mesh->Scale(modelScale, modelScale, modelScale); mesh->UpdateBounds(); model->UpdateBounds(); } } } struct vec3_t { float x, y, z; }; struct trivertx_t { unsigned char v[3]; // Compressed vertex coords unsigned char normalIndex; }; struct mdl_header_t { int ident; int version; vec3_t scale;/* scale factor */ vec3_t translate; /* translation vector */ float boundingradius; vec3_t eyeposition;/* eyes' position */ int numskins; /* number of textures */ int skinwidth;/* texture width */ int skinheight; /* texture height */ int numverts;/* number of vertices */ int numtris;/* number of triangles */ int numframes;/* number of frames */ int synctype;/* 0 = synchron, 1 = random */ int flags;/* state flag */ float size; }; struct mdl_simpleframe_t { struct trivertx_t bboxmin; /* bouding box min */ struct trivertx_t bboxmax; /* bouding box max */ char name[16]; std::vector<trivertx_t> vertices; }; /* Texture coords */ struct mdl_texcoord_t { int onseam; int s, t; }; /* Triangle info */ struct mdl_triangle_t { int facesfront; /* 0 = backface, 1 = frontface */ int vertex[3]; /* vertex indices */ }; struct AnimFrame { std::vector<Vec3> vertices; }; std::vector<AnimFrame> animationsFrames; bool AreSame(Vec3 a, Vec3 b) { return fabs(a.x - b.x) < b3d::EPSILON && fabs(a.y - b.y) < b3d::EPSILON && fabs(a.z - b.z) < b3d::EPSILON; } shared_ptr<World> world; std::vector<shared_ptr<Entity>> points; void setFrame(shared_ptr<Model> model, int frameId) { for (auto const& lod : model->lods) { for (auto& mesh : lod->meshes) { Print("1st mesh vertex coords: " + String(mesh->vertices[0].position.x) + " " + String(mesh->vertices[0].position.y) + " " + String(mesh->vertices[0].position.z)); vector<std::pair<int, int>> vertexPairs; for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { //Print("Vertex coords: " + String(mesh->vertices[i].position.x) + " " + String(mesh->vertices[i].position.y) + " " + String(mesh->vertices[i].position.z)); for (int j = animationsFrames[frameId].vertices.size(); j < mesh->vertices.size(); j++) { //if (AreSame(mesh->GetVertexPosition(i), mesh->GetVertexPosition(j))) { if (mesh->GetVertexPosition(i) == mesh->GetVertexPosition(j)) { vertexPairs.push_back(std::make_pair(i, j)); break; } } } //for (auto v : mesh->vertices) { // auto point = CreateSphere(world, 0.01f, 8); // point->SetPosition(v.position); // point->SetColor(0,1,1); // points.push_back(point); //} for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { mesh->SetVertexPosition(i, animationsFrames[frameId].vertices[i]); /* auto point = CreateSphere(world, 0.01f, 8); point->SetColor(0, 1, 1); point->SetPosition(animationsFrames[frameId].vertices[i]); points.push_back(point);*/ } for (auto const& [original, dublicated] : vertexPairs) { mesh->SetVertexPosition(dublicated, mesh->GetVertexPosition(original)); auto point = CreateSphere(world, 0.01f, 8); point->SetColor(0, 1, 1); point->SetPosition(mesh->GetVertexPosition(original)); points.push_back(point); } for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { auto point = CreateSphere(world, 0.01f, 8); point->SetColor(0, 1, 1); point->SetPosition(animationsFrames[frameId].vertices[i]); points.push_back(point); } mesh->UpdateBounds(); mesh->UpdateTangents(); mesh->UpdateNormals(); model->UpdateBounds(); } } } void animations() { std::ifstream file(modelPath, std::ios::binary); if (!file) { std::cerr << "Failed to open mdl file.\n"; return; } mdl_header_t header; file.read(reinterpret_cast<char*>(&header), sizeof(mdl_header_t)); if (header.ident != 0x4F504449) { std::cerr << "Invalid MDL ident.\n"; return; } std::cout << "MDL Loaded: " << header.numframes << " frames, " << header.numverts << " verts per frame\n"; // Skip skins, tex coords, tris... int skinSize = header.numskins * header.skinwidth * header.skinheight; file.seekg(skinSize, std::ios::cur); file.seekg(sizeof(mdl_texcoord_t) * header.numverts, std::ios::cur); file.seekg(sizeof(mdl_triangle_t) * header.numtris, std::ios::cur); std::vector<mdl_simpleframe_t> frames; for (int i = 0; i < header.numframes; ++i) { char name[16]; file.read(name, 16); mdl_simpleframe_t frame; std::memcpy(frame.name, name, 16); for (int j = 0; j < header.numverts; ++j) { trivertx_t v; file.read(reinterpret_cast<char*>(&v), sizeof(trivertx_t)); frame.vertices.push_back(v); } frames.push_back(frame); } for (int i = 0; i < frames.size(); i++) { AnimFrame newFrame; for (int v = 0; v < frames[i].vertices.size(); ++v) { float x = float(frames[i].vertices[v].v[1]) / 127.0f * header.scale.y + header.translate.y; float y = float(frames[i].vertices[v].v[2]) / 127.0f * header.scale.z + header.translate.z; float z = float(frames[i].vertices[v].v[0]) / 127.0f * header.scale.x + header.translate.x; newFrame.vertices.push_back(Vec3(x, y, z)); } animationsFrames.push_back(newFrame); } std::cout << "1st frame vertex coords: " << animationsFrames[0].vertices[0].x << " " << animationsFrames[0].vertices[0].y << " " << animationsFrames[0].vertices[0].z << "\n"; } int main(int argc, const char* argv[]) { RegisterComponents(); auto displays = GetDisplays(); auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); auto framebuffer = CreateFramebuffer(window); auto quakeLoaderPlugin = Core::LoadPlugin("Plugins/QuakeLoader"); //Create a world world = CreateWorld(); world->SetAmbientLight(Vec3(3)); //auto pak = LoadPackage(path + "/PAK0.PAK"); auto model = LoadModel(world, modelPath); //fixModel(model); //model->Turn(0, 180, 0, true); //fill frame vector animations(); //Create a camera auto camera = CreateCamera(world); camera->SetPosition(model->GetBounds().center); camera->Move(0, 0, -1.5); camera->SetRotation(0, 0, 0); camera->SetRange(0.01, 100); camera->SetFov(70); camera->AddComponent<CameraControls>(); setFrame(model, 0); //Main loop while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { world->Update(); world->Render(framebuffer); } return 0; } Quote
Solution Dreikblack Posted 3 hours ago Author Solution Posted 3 hours ago omg, i did it. I still have no damn idea what was wrong exactly, but for some reason in every frame there were 3 extra char between bounds and name. I was doing everything same as in code examples with same structs, but found an issue only by debugging everything and noticing that name was 3 characters later. Still a lot of work to do, but at least i have finally a start. I hope i will make it work with fixed scale and mesh position. Current code: #include "Leadwerks.h" #include "ComponentSystem.h" #include <fstream> using namespace Leadwerks; const float modelScale = 4.68042326f; const WString modelPath = "human.mdl";//"player.mdl"; //scale and position void fixModel(shared_ptr<Model> model) { for (auto const& lod : model->lods) { for (auto& mesh : lod->meshes) { mesh->Translate(-mesh->bounds.center.x, -mesh->bounds.center.y, -mesh->bounds.center.z); mesh->Scale(modelScale, modelScale, modelScale); mesh->UpdateBounds(); model->UpdateBounds(); } } } struct vec3_t { float x, y, z; }; struct trivertx_t { unsigned char v[3]; // Compressed vertex coords unsigned char normalIndex; }; struct mdl_header_t { int ident;//"IDPO" (0x4F504449) int version;// 6 vec3_t scale;/* scale factor */ vec3_t translate; /* translation vector */ float boundingradius; vec3_t eyeposition;/* eyes' position */ int numskins; /* number of textures */ int skinwidth;/* texture width */ int skinheight; /* texture height */ int numverts;/* number of vertices */ int numtris;/* number of triangles */ int numframes;/* number of frames */ int synctype;/* 0 = synchron, 1 = random */ int flags;/* state flag */ float size; }; struct mdl_simpleframe_t { struct trivertx_t bboxmin; /* bouding box min */ struct trivertx_t bboxmax; /* bouding box max */ char name[16]; std::vector<trivertx_t> vertices; }; /* Group of simple frames */ struct mdl_groupframe_t { struct trivertx_t min; /* min pos in all simple frames */ struct trivertx_t max; /* max pos in all simple frames */ float* time; /* time duration for each frame */ struct mdl_simpleframe_t* frames; /* simple frame list */ }; /* Texture coords */ struct mdl_texcoord_t { int onseam; int s, t; }; /* Triangle info */ struct mdl_triangle_t { int facesfront; /* 0 = backface, 1 = frontface */ int vertex[3]; /* vertex indices */ }; struct AnimFrame { std::vector<Vec3> vertices; }; std::vector<AnimFrame> animationsFrames; bool AreSame(Vec3 a, Vec3 b) { return fabs(a.x - b.x) < b3d::EPSILON && fabs(a.y - b.y) < b3d::EPSILON && fabs(a.z - b.z) < b3d::EPSILON; } shared_ptr<World> world; std::vector<shared_ptr<Entity>> points; void setFrame(shared_ptr<Model> model, int frameId) { for (auto const& lod : model->lods) { for (auto& mesh : lod->meshes) { Print("1st mesh vertex coords: " + String(mesh->vertices[0].position.x) + " " + String(mesh->vertices[0].position.y) + " " + String(mesh->vertices[0].position.z)); vector<std::pair<int, int>> vertexPairs; for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { //Print("Vertex coords: " + String(mesh->vertices[i].position.x) + " " + String(mesh->vertices[i].position.y) + " " + String(mesh->vertices[i].position.z)); for (int j = animationsFrames[frameId].vertices.size(); j < mesh->vertices.size(); j++) { //if (AreSame(mesh->GetVertexPosition(i), mesh->GetVertexPosition(j))) { if (mesh->GetVertexPosition(i) == mesh->GetVertexPosition(j)) { vertexPairs.push_back(std::make_pair(i, j)); break; } } } for (int i = 0; i < animationsFrames[frameId].vertices.size(); i++) { mesh->SetVertexPosition(i, animationsFrames[frameId].vertices[i]); } for (auto const& [original, dublicated] : vertexPairs) { mesh->SetVertexPosition(dublicated, mesh->GetVertexPosition(original)); } mesh->UpdateBounds(); mesh->UpdateTangents(); mesh->UpdateNormals(); model->UpdateBounds(); } } } struct mdl_frame_t { std::string name; std::vector<vec3_t> vertices; }; std::vector<mdl_frame_t> all_frames; void animations() { std::ifstream file(modelPath, std::ios::binary); if (!file) { std::cerr << "Failed to open mdl file.\n"; return; } mdl_header_t header; file.read(reinterpret_cast<char*>(&header), sizeof(header)); if (header.ident != 0x4F504449) { std::cerr << "Invalid MDL ident.\n"; return; } std::cout << "MDL Loaded: " << header.numframes << " frames, " << header.numverts << " verts per frame\n"; // Skip skins, tex coords, tris... for (int i = 0; i < header.numskins; ++i) { int group; file.read(reinterpret_cast<char*>(&group), sizeof(int)); if (group == 0) { std::vector<uint8_t> skin_data(header.skinwidth * header.skinheight); file.read(reinterpret_cast<char*>(skin_data.data()), skin_data.size()); } else { int nb; float time; file.read(reinterpret_cast<char*>(&nb), sizeof(int)); for (int n = 0; n < nb; ++n) { file.read(reinterpret_cast<char*>(&time), sizeof(float)); } for (int n = 0; n < nb; ++n) { std::vector<uint8_t> skin_data(header.skinwidth * header.skinheight); file.read(reinterpret_cast<char*>(skin_data.data()), skin_data.size()); } } } file.seekg(sizeof(mdl_texcoord_t) * header.numverts, std::ios::cur); file.seekg(sizeof(mdl_triangle_t) * header.numtris, std::ios::cur); std::vector<mdl_simpleframe_t> frames; for (int i = 0; i < header.numframes; ++i) { uint8_t type; file.read(reinterpret_cast<char*>(&type), sizeof(uint8_t)); if (type == 0) { // --- Single frame --- char name[16]; std::vector<trivertx_t> verts(header.numverts); file.seekg(sizeof(char) * (4 * 2 + 3), std::ios::cur); // file.seekg(sizeof(char) * 3, std::ios::cur); file.read(name, 16); mdl_simpleframe_t frame; std::memcpy(frame.name, name, 16); for (int j = 0; j < header.numverts; ++j) { trivertx_t v; file.read(reinterpret_cast<char*>(&v), sizeof(trivertx_t)); frame.vertices.push_back(v); } Print(name); frames.push_back(frame); } else if (type == 1) { // --- Group frame (animation group) --- int num_group_frames; file.read(reinterpret_cast<char*>(&num_group_frames), sizeof(int)); std::vector<float> intervals(num_group_frames); file.read(reinterpret_cast<char*>(intervals.data()), sizeof(float) * num_group_frames); for (int g = 0; g < num_group_frames; ++g) { vec3_t bboxmin, bboxmax; char name[16]; std::vector<trivertx_t> verts(header.numverts); file.read(reinterpret_cast<char*>(&bboxmin), sizeof(vec3_t)); file.read(reinterpret_cast<char*>(&bboxmax), sizeof(vec3_t)); file.read(name, 16); file.read(reinterpret_cast<char*>(verts.data()), sizeof(trivertx_t) * header.numverts); mdl_frame_t frame; frame.name = name; frame.vertices.resize(header.numverts); for (int i = 0; i < header.numverts; ++i) { frame.vertices[i].x = verts[i].v[0] * header.scale.x + header.translate.x; frame.vertices[i].y = verts[i].v[1] * header.scale.y + header.translate.y; frame.vertices[i].z = verts[i].v[2] * header.scale.z + header.translate.z; } all_frames.push_back(std::move(frame)); Print(name); } } else { std::cerr << "Unknown frame type: " << int(type) << "\n"; break; } } for (int i = 0; i < frames.size(); i++) { AnimFrame newFrame; for (int v = 0; v < frames[i].vertices.size(); ++v) { float x = float(frames[i].vertices[v].v[1]) / 127.0f * header.scale.y + header.translate.y; float y = float(frames[i].vertices[v].v[2]) / 127.0f * header.scale.z + header.translate.z; float z = float(frames[i].vertices[v].v[0]) / 127.0f * header.scale.x + header.translate.x; newFrame.vertices.push_back(Vec3(x, y, z)); } animationsFrames.push_back(newFrame); } std::cout << "1st frame vertex coords: " << animationsFrames[0].vertices[0].x << " " << animationsFrames[0].vertices[0].y << " " << animationsFrames[0].vertices[0].z << "\n"; } int main(int argc, const char* argv[]) { RegisterComponents(); auto displays = GetDisplays(); auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); auto framebuffer = CreateFramebuffer(window); auto quakeLoaderPlugin = Core::LoadPlugin("Plugins/QuakeLoader"); //Create a world world = CreateWorld(); world->SetAmbientLight(Vec3(3)); //auto pak = LoadPackage(path + "/PAK0.PAK"); auto model = LoadModel(world, modelPath); //fixModel(model); //model->Turn(0, 180, 0, true); //fill frame vector animations(); //Create a camera auto camera = CreateCamera(world); camera->SetPosition(model->GetBounds().center); camera->Move(0, 0, -1.5); camera->SetRotation(0, 0, 0); camera->SetRange(0.01, 100); camera->SetFov(70); camera->AddComponent<CameraControls>(); setFrame(model, 3); //Main loop while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { world->Update(); world->Render(framebuffer); } return 0; } Quote
Dreikblack Posted 2 hours ago Author Posted 2 hours ago Still some frames are partly broken because of extra vertexes i suppose Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.