3
\$\begingroup\$

I'm trying to load MD2 models (stolen from Cube) and my loader seems to be loading the models fine, but I can't say the same for the drawing of the model. Here's my code:

typedef float vec3_t[3];

struct md2_t
{
    int ident;
    int version;

    int skinwidth;
    int skinheigh;
    int framesize;

    int num_skins;
    int num_xyz;
    int num_st;
    int num_tris;
    int num_glcommands;
    int num_frames;

    int ofs_skins;
    int ofs_st;
    int ofs_tris;
    int ofs_frames;
    int ofs_glcommands;
    int ofs_end;
};

struct md2_vertex_t
{
    unsigned char v[3];
    unsigned char index_normal;
};

typedef short md2_textcoord_t[2];

struct md2_frame_t
{
    float scale[3];
    vec3_t translate;
    char name[16];
    md2_vertex_t vertices[1]; // First vertex of this frame.
};


struct md2_triangle_t
{
    short index_xyz[3];
    short index_st[3];
};

struct md2_anim_t
{
    int first_frame, last_frame, fps;
};

struct md2_animstate_t
{
    md2_anim_t* animation;
    float current_time, old_time, interpol;
    int type, current_frame, next_frame;
};

struct md2_glcmd_t
{
    float s;
    float t;
    int index;
};

#define MD2_IDENT (('2'<<24) + ('P'<<16) + ('D'<<8) + 'I')
#define MD2_VERSION 8

class MD2 : public VertexModel
{
    public:
        MD2(const std::string& Path);
        ~MD2();

        void Draw(timestep_t Time);

    private:
        md2_t m_MD2Header;
        md2_animstate_t m_MD2AnimState;
        md2_anim_t* m_MD2Animations;
        vec3_t* m_Vertices;
        vec3_t* m_InterpolatedVertices;
        int* m_Commands;
        int* m_Normals;

        unsigned int m_TextureID;
        float m_Scale;

        void Interpolate(vec3_t* Vertices);
};


#include <helpers/md2.h>
#include <iostream>
#include <fstream>
#include <exception>

MD2::MD2(const std::string& Path) : m_TextureID(0), m_Scale(1.0f)
{
    std::ifstream File(Path.c_str(), std::iostream::in | std::ifstream::binary);
    if(!File.is_open())
    {
        Debugging::Debugf("Unable to open the file: %s", Path.c_str());
        exit(0);
    }

    // Get the filesize.
    File.seekg (0, std::ios::end);
    int Size = File.tellg();
    File.seekg (0, std::ios::beg);

    if(Size < sizeof(md2_t))
    {
        Debugging::Debugf("Incorrect header for the file: %s", Path.c_str());
        exit(0);
    }

    // Get the header.
    memset((void*)&m_MD2Header, 0, sizeof(md2_t));
    File.read((char*)&m_MD2Header, sizeof(md2_t));

    // Check if the file is actually a MD2 model.
    if(m_MD2Header.ident != MD2_IDENT || m_MD2Header.version != MD2_VERSION)
    {
        Debugging::Debugf("The file %s is not a MD2 model.", Path.c_str());
        exit(0);
    }

    // Allocate memory for the data.
    m_Vertices = new vec3_t[m_MD2Header.num_xyz * m_MD2Header.num_frames];
    m_InterpolatedVertices = new vec3_t[m_MD2Header.num_xyz];
    m_Normals = new int[m_MD2Header.num_xyz * m_MD2Header.num_frames];
    m_Commands = new int[m_MD2Header.num_glcommands];
    char* Buffer = new char[m_MD2Header.framesize * m_MD2Header.num_frames];

    // Read the frame data.
    File.seekg(m_MD2Header.ofs_frames, std::ios::beg);
    File.read(Buffer, m_MD2Header.framesize * m_MD2Header.num_frames);

    // Read the command data.
    File.seekg(m_MD2Header.ofs_glcommands, std::ios::beg);
    File.read((char*)m_Commands, m_MD2Header.num_glcommands * sizeof(int));

    // Read all the data.
    for(int i = 0; i < m_MD2Header.num_frames; ++i)
    {
        md2_frame_t* Frame = (md2_frame_t*)&Buffer[m_MD2Header.framesize * i];
        vec3_t* Vertices = &m_Vertices[m_MD2Header.num_xyz * i];
        int* Normals = &m_Normals[m_MD2Header.num_xyz * i];

        for(int vertex = 0; vertex < m_MD2Header.num_xyz; ++vertex)
        {
            Vertices[i][0] = (Frame->vertices[i].v[0] * Frame->scale[0]) + Frame->translate[0];
            Vertices[i][1] = (Frame->vertices[i].v[1] * Frame->scale[1]) + Frame->translate[1];
            Vertices[i][2] = (Frame->vertices[i].v[2] * Frame->scale[2]) + Frame->translate[2];
            Normals[i] = Frame->vertices[i].index_normal;
        }
    }

    // Free unused memory and close the file.
    delete[] Buffer;
    File.close();

    memset((void*)&m_MD2AnimState, 0, sizeof(m_MD2AnimState));
}

MD2::~MD2()
{
    delete[] m_MD2Animations;
    delete[] m_Vertices;
    delete[] m_InterpolatedVertices;
    delete[] m_Commands;
    delete[] m_Normals;
}

void MD2::Draw(timestep_t Time)
{
    glPushMatrix();
        // Transform the model coordinates into OpenGL coordinates.
        glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
        glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);

        // Reverse the orientation of front-facing polygons.
        glPushAttrib(GL_POLYGON_BIT);
        glFrontFace(GL_CW);
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);

        // Bind the texture.
        //glEnable(GL_TEXTURE_2D);
        //glBindTexture(GL_TEXTURE_2D, m_TextureID);

        // Interpolate between frames.
        Interpolate(m_InterpolatedVertices);

        // Draw the model.
        int* Commands = m_Commands;
        while(int i = *(Commands++))
        {
            if(i < 0)
            {
                glBegin(GL_TRIANGLE_FAN);
                i = -i;
            }
            else
            {
                glBegin(GL_TRIANGLE_STRIP);
            }

            for(; i > 0; --i, Commands += 3)
            {
                md2_glcmd_t* Command = (md2_glcmd_t*)Commands;

                glColor3f(1.0f, 1.0f, 1.0f);
                glTexCoord2f(Command->s, Command->t);
                glVertex3fv(m_InterpolatedVertices[Command->index]);
            }

            glEnd();
        }

        // Use the original orientation.
        glDisable(GL_CULL_FACE);
        glPopAttrib();

    glPopMatrix();
}

void MD2::Interpolate(vec3_t* Vertices)
{
    for(int i = 0; i < m_MD2Header.num_xyz; ++i)
    {
        Vertices[i][0] = m_Vertices[i + (m_MD2Header.num_xyz * m_MD2AnimState.current_frame)][0] * m_Scale;
        Vertices[i][1] = m_Vertices[i + (m_MD2Header.num_xyz * m_MD2AnimState.current_frame)][1] * m_Scale;
        Vertices[i][2] = m_Vertices[i + (m_MD2Header.num_xyz * m_MD2AnimState.current_frame)][2] * m_Scale;
    }
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The drawing code looks fine - are you sure the loading is?

// Read all the data.
for(int i = 0; i < m_MD2Header.num_frames; ++i)
{
    md2_frame_t* Frame = (md2_frame_t*)&Buffer[m_MD2Header.framesize * i];
    vec3_t* Vertices = &m_Vertices[m_MD2Header.num_xyz * i];
    int* Normals = &m_Normals[m_MD2Header.num_xyz * i];

    for(int vertex = 0; vertex < m_MD2Header.num_xyz; ++vertex)
    {
        Vertices[i][0] = (Frame->vertices[i].v[0] * Frame->scale[0]) + Frame->translate[0];
        Vertices[i][1] = (Frame->vertices[i].v[1] * Frame->scale[1]) + Frame->translate[1];
        Vertices[i][2] = (Frame->vertices[i].v[2] * Frame->scale[2]) + Frame->translate[2];
        Normals[i] = Frame->vertices[i].index_normal;
    }
}

To me it looks as if the indexing is wrong - shouldn't you index Vertices[vertex][0] rather than Vertices[i][0]?

Besides: you don't need to take the OpenGL command list from the MD2 file - MD2 files also contain a regular list of triangles with indexes into the texture coordinate and vertex arrays.

I mention it because I took this path when I wrote a MD2 loader. I found this data much more convinient than a pre-optimized OpenGL stream, but it surely depends on the application.

\$\endgroup\$
1
  • \$\begingroup\$ I can't believe I missed that. \$\endgroup\$ Commented Mar 30, 2011 at 0:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .