Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 5 of 5

Thread: Trouble loading .md2 files

  1. #1
    Junior Member Newbie
    Join Date
    Aug 2013
    Posts
    12

    Trouble loading .md2 files

    I have a class I created for loading .md2 files which works almost perfectly. The one problem that I can't seem to fix is that the displayed model has its texture messed up. It's as if I'm using the wrong texture indices or just plain storing the wrong texture coordinates. Any help with this problem would be appreciated.

    My Structs:
    Code :
    struct MD2_Header
    {
        char ident[4];    ///identifer - IDP2
        int version;      ///version number - 8
        int skinwidth;    ///width of texture
        int skinheight;   ///height of texture
        int framesize;    ///size of a frame in bytes
        int num_skins;    ///number of textures
        int num_xyz;      ///number of vertices
        int num_st;       ///number of texture coordinates
        int num_tris;     ///number of triangles
        int num_glcmds;   ///number of opengl commands
        int num_frames;   ///number of frames
        int ofs_skins;    ///offset to texture names
        int ofs_st;       ///offset to texture coordinates
        int ofs_tris;     ///offset to triangles
        int ofs_frames;   ///offset to frame data
        int ofs_glcmds;   ///offset to gl commands
        int ofs_end;      ///offset to end of file
    };
     
    struct MD2_TextureCoord
    {
        short s;
        short t;
        float gl_X;
        float gl_Y;
    };
     
    struct MD2_Triangle
    {
        short VertexIndex[3];
        short TextureIndex[3];
    };
     
    struct MD2_Vertex
    {
        vec3 Pos;
        vec3 Norm;
    };
     
    struct MD2_Frame
    {
        char Name[16];
        vector<MD2_Vertex> Vertices;
    };
     
    struct MD2_glCommand
    {
        float s, t;
        int VertexIndex;
    };
     
    struct MD2_CommandGroup
    {
        int Size; /// positive - triangle strip/negative - triangle fan
        vector<MD2_glCommand> Commands;
    };

    My loading and displaying functions:
    Code :
    void MD2_Model::Load(string File, int Which)
    {
        cout<<"Loading .md2 file..."<<endl;
        WritetoLog("Loading Model: ",false);
        WritetoLog(File, false);
        WritetoLog("...");
     
        ifstream Model(File.c_str(), istream::binary);
        char Buffer[64];
     
        ///Check to see if it's a valid MD2 file
        Model.read( Header.ident, 4 );
        if ( Header.ident[0] != 'I' || Header.ident[1] != 'D' || Header.ident[2] != 'P' || Header.ident[3] != '2' )
        {
            cout<<"Not a valid MD2 file";
            WritetoLog("Attempted to load an invalid MD2 file: ", false);
            WritetoLog(File, false);
            WritetoLog(" .Wrong Identifer.");
            exit(0xBAD);
        }
        Header.version = ReadInt(Model);
        if ( Header.version != 8 )
        {
            cout<<"Not a valid MD2 file";
            WritetoLog("Attempted to load an invalid MD2 file: ", false);
            WritetoLog(File, false);
            WritetoLog(" .Wrong Version Number.");
            exit(0xBAD);
        }
        ///Get the header information
        Header.skinwidth =    ReadInt(Model);
        Header.skinheight =   ReadInt(Model);
        Header.framesize =    ReadInt(Model);
        Header.num_skins =    ReadInt(Model);
        Header.num_xyz =      ReadInt(Model);
        Header.num_st =       ReadInt(Model);
        Header.num_tris =     ReadInt(Model);
        Header.num_glcmds =   ReadInt(Model);
        Header.num_frames =   ReadInt(Model);
        Header.ofs_skins =    ReadInt(Model);
        Header.ofs_st =       ReadInt(Model);
        Header.ofs_tris =     ReadInt(Model);
        Header.ofs_frames =   ReadInt(Model);
        Header.ofs_glcmds =   ReadInt(Model);
        Header.ofs_end =      ReadInt(Model);
     
        if ( Header.num_skins != 1 )
        {
            cout<<"Invalid MD2 file";
            WritetoLog("Attempted to load MD2 value with incorrect amount of textures: ", false);
            WritetoLog(File);
            exit(0xBAD);
        }
     
        ///Load Texture
        Model.seekg( Header.ofs_skins, ios_base::beg );
        Model.read( Buffer, 64 );
        int Length = strlen(Buffer);
        wchar_t tempBuffer[Length];
        for ( int k = 0; k < Length; k++ )
            tempBuffer[k] = (wchar_t)Buffer[k];
        /// I only want to load .png files as the texture
        tempBuffer[ Length - 3 ] = L'p';
        tempBuffer[ Length - 2 ] = L'n';
        tempBuffer[ Length - 1 ] = L'g';
        Skin.LoadTexture( tempBuffer, Which );
     
        ///Load Texture Coordinates
        Model.seekg( Header.ofs_st, ios_base::beg );
        for ( int i = 0; i < Header.num_st; i++ )
        {
            MD2_TextureCoord Temp;
            Temp.s = ReadShort(Model);
            Temp.t = ReadShort(Model);
            Temp.gl_X = (float)Temp.s/Header.skinwidth;
            Temp.gl_Y = (float)Temp.t/Header.skinheight;
     
            TexCoords.push_back( Temp );
        }
     
        ///Load Triangles
        Model.seekg( Header.ofs_tris, ios_base::beg );
        for ( int i = 0; i < Header.num_tris; i++ )
        {
            MD2_Triangle Temp;
            for ( int j = 0; j < 3; j++ )
                Temp.VertexIndex[j] = ReadShort(Model);
            for ( int j = 0; j < 3; j++ )
                Temp.TextureIndex[j] = ReadShort(Model);
     
            Triangles.push_back(Temp);
        }
     
        ///Load Frame Data
        Model.seekg( Header.ofs_frames, ios_base::beg );
        for ( int i = 0; i < Header.num_frames; i++ )
        {
            MD2_Frame Temp;
     
            vec3 Scale = ReadVec3(Model);
            vec3 Translate = ReadVec3(Model);
            Model.read( Temp.Name, 16 );
     
            for ( int j = 0; j < Header.num_xyz; j++ )
            {
                MD2_Vertex Temp2;
     
                Model.read( Buffer, 3 );
                Temp2.Pos = vec3( (unsigned char)Buffer[0], (unsigned char)Buffer[1], (unsigned char)Buffer[2] );
                Temp2.Pos = Scale*Temp2.Pos + Translate;
     
                Model.read( Buffer, 1 );
                int Index = (int)((unsigned char)Buffer[0]);
                Temp2.Norm = vec3( MD2_Normals[3*Index], MD2_Normals[3*Index+1], MD2_Normals[3*Index+2] );
     
                Temp.Vertices.push_back( Temp2 );
            }
     
            Frames.push_back(Temp);
        }
     
        ///Load OpenGL Commands
        Model.seekg( Header.ofs_glcmds, ios_base::beg );
        for ( int num = ReadInt(Model); num != 0; num = ReadInt(Model) )
        {
            MD2_CommandGroup Temp;
            Temp.Size = num;
            for ( int i = 0; i < fabs(Temp.Size); i++ )
            {
                MD2_glCommand Temp2;
     
                Temp2.s = ReadFloat(Model);
                Temp2.t = ReadFloat(Model);
                Temp2.VertexIndex = ReadInt(Model);
     
                Temp.Commands.push_back(Temp2);
            }
            Groups.push_back(Temp);
        }
     
        StartFrame = 0;
        EndFrame = Header.num_frames - 1;
    }
     
    void MD2_Model::Draw( int Attributes[], bool Which_Way )
    {
        ///Get Frame indicies
        int FrameIndex1 = StartFrame, FrameIndex2 = StartFrame;
        int AnimationLength = EndFrame - StartFrame + 1;
     
        vector<float> FramePos;
        for ( int i = 0; i < AnimationLength; i++ )
            FramePos.push_back( i * 1.f/AnimationLength );
     
        for ( int i = 1; i < FramePos.size(); i++ )
            if ( Time >= FramePos[i-1] and Time <= FramePos[i] )
            {
                FrameIndex1 = i - 1 + StartFrame;
                FrameIndex2 = i + StartFrame;
            }
        if ( FrameIndex1 == FrameIndex2 )
            FrameIndex1 = EndFrame;
     
        MD2_Frame Frame1 = Frames[FrameIndex1], Frame2 = Frames[FrameIndex2];
     
        ///Get Fraction between the two frames
        float Fraction = 0;
        if ( AnimationLength > 0 )
            Fraction = float(Time - FramePos[FrameIndex1 - StartFrame] )*AnimationLength;
     
        ///Draw
        Skin.Bind();
     
        /// Usual Way
        if ( Which_Way )
        {
            glBegin(GL_TRIANGLES);
            for ( int i = 0; i < Header.num_tris; i++ )
            {
                MD2_Triangle Triangle = Triangles[i];
                for ( int j = 0; j < 3; j++ )
                {
                    MD2_Vertex V1 = Frame1.Vertices[ Triangle.VertexIndex[j] ];
                    MD2_Vertex V2 = Frame2.Vertices[ Triangle.VertexIndex[j] ];
     
                    vec3 Pos = V1.Pos * (1.f-Fraction) + V2.Pos * Fraction;
                    vec3 Norm = V1.Norm * (1.f-Fraction) + V2.Norm * Fraction;
     
                    MD2_TextureCoord Coord = TexCoords[ Triangle.TextureIndex[j] ];
     
                    glVertexAttrib3f( Attributes[0], Pos[0], Pos[1], Pos[2] );  ///Position
                    glVertexAttrib4f( Attributes[1], 1, 1, 1, 1 );                 ///Color
                    glVertexAttrib2f( Attributes[2], Coord.gl_X, Coord.gl_Y );  ///TexCoord
                    glVertexAttrib3f( Attributes[3], Norm[0], Norm[1], Norm[2] ); ///Normal
                }
            }
            glEnd();
        }
        ///Using file's commands
        else
        {
            for ( int i = 0; i < Groups.size(); i++ )
            {
                MD2_CommandGroup Group = Groups[i];
                if ( Group.Size > 0 )
                    glBegin( GL_TRIANGLE_STRIP );
                else
                    glBegin( GL_TRIANGLE_FAN );
     
                for ( int j = 0; j < fabs(Group.Size); j++ )
                {
                    MD2_glCommand Command = Group.Commands[j];
     
                    MD2_Vertex V1 = Frame1.Vertices[ Command.VertexIndex ];
                    MD2_Vertex V2 = Frame2.Vertices[ Command.VertexIndex ];
     
                    vec3 Pos = V1.Pos * (1.f-Fraction) + V2.Pos * Fraction;
                    vec3 Norm = V1.Norm * (1.f-Fraction) + V2.Norm * Fraction;
     
                    glVertexAttrib3f( Attributes[0], Pos[0], Pos[1], Pos[2] );  ///Position
                    glVertexAttrib4f( Attributes[1], 1, 1, 1, 1 );                 ///Color
                    glVertexAttrib2f( Attributes[2], Command.s, Command.t );    ///TexCoord
                    glVertexAttrib3f( Attributes[3], Norm[0], Norm[1], Norm[2] ); ///Normal
                }
                glEnd();
            }
        }
     
        Skin.UnBind();
    }

    Any help is appreciated. If there are any functions that I need to post to help you see what's going on in the program, just say so

    *the readshort/readint/whatever functions have obvious purposes and I'm certain the problem is not with them which is why I didn't post them
    **I've tested to make sure the problem is not with the file I'm loading

  2. #2
    Junior Member Regular Contributor
    Join Date
    Mar 2012
    Posts
    129
    Some image loaders load images upside-down. Try flipping the source image.

  3. #3
    Junior Member Newbie
    Join Date
    Aug 2013
    Posts
    12
    I tried flipping it all possible ways but none of them worked correctly.

  4. #4
    Member Regular Contributor
    Join Date
    Aug 2008
    Posts
    433
    You're using glBegin/glEnd + glVertexAttrib{2/3/4}f to issue vertices, this generally isn't the best way to use OpenGL and glBegin/glEnd aren't available in more recent OpenGL versions.

    When using glBegin/glEnd, the only calls that actually issue a new vertex are glVertex(...) and glVertexAttrib(0, ...). All the rest, such as glColor/glNormal/glVertexAttrib(N, ...){where N > 0}/etc. only set the current value for that attribute to be used when the vertex is issued.

    Depending on what OpenGL version you're using, you should read http://www.opengl.org/sdk/docs/man2/...rtexAttrib.xml or http://www.opengl.org/sdk/docs/man/x...rtexAttrib.xml

    For your code to work, the last attribute would have have to be Position (assuming Position location = 0), otherwise you will be issuing vertices with the current attribute values from the previous iteration of the loop.

  5. #5
    Junior Member Newbie
    Join Date
    Aug 2013
    Posts
    12
    I changed the ordering of the calls to glVertexAttrib so that the position one is called last and it worked perfectly. Thanks for the advice

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •