Jump to content

Need help with Quake model animations


Go to solution Solved by Dreikblack,

Recommended Posts

Posted

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;
}

 

Posted

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.

My job is to make tools you love, with the features you want, and performance you can't live without.

Posted

image.png.1642a2d59e98a7d315125edaf174857a.png

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;
}

 

Posted

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

image.thumb.png.9391d3113f1ce7adddecb78dc8f1bca4.png

#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;
}

 

  • Solution
Posted

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.

image.thumb.png.d028828a42203029e832e9c1c8c7e471.png

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;
}

 

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...