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