   MD2 Loader Problem  - Please Help
  Hi AllI've been working on an MD2 Mesh loader as part of an OpenGL app.  I've tried two different ways of reading it in etc. now and it just doesn't work.  I would be HUUUUUGELY grateful if someone could take a look at my code and figure out what's gone wrong.  Thanks!- AndycAnimModel.h#ifndef _CANIMMODEL_H_#define _CANIMMODEL_H_enum eModelState{IDLE,CROUCH,RUN,JUMP};// Vertextypedef struct{float v[3];} sVertex;// Texture Coordinatetypedef struct{float s;float t;} sTexCoord;// Texture Coordinate Indextypedef struct{short s;short t;} sTexIndex;// Single Frame Point Infotypedef struct{unsigned char v[3];unsigned char normalIndex;} sFramePoint;// Frame Informationtypedef struct{float scale[3];float translate[3];char name[16];sFramePoint fp[1];} sFrame;// Triangle Datatypedef struct{unsigned short meshIndex[3];unsigned short texIndex[3];} sMesh;// Model Headertypedef struct{int ID;int Version;int SkinWidth;int SkinHeight;int FrameSize;int NumSkins;int NumXYZ;int NumST;int NumTris;int NumGLCmds;int NumFrames;int OffsetSkins;int OffsetST;int OffsetTris;int OffsetFrames;int OffsetGLCmds;int OffsetEnd;} sModelHeader;class cAnimModel{private:int NumFrames;int NumVertices;int NumTriangles;int NumST;int FrameSize;int CurrentFrame;int NextFrame;int TexID;float Interpol;sMesh *TriIndex;sTexCoord *ST;sVertex *VertexList;eModelState ModelState;public:cAnimModel();~cAnimModel();bool Load(char *MeshFile, char *SkinFile);int Animate(int StartFrame, int EndFrame, float Percent);int RenderFrame(int KeyFrame);int Unload();int SetState(eModelState State) { ModelState = State; }eModelState GetState() { return ModelState; }};#endifcAnimModel.cpp#include <Windows.h>#include <gl\GL.h>#include "cTexture.h"#include "cAnimModel.h"#define TextureManager cTexture::Instance()cAnimModel::cAnimModel(){NumFrames= 0;NumVertices= 0;NumTriangles= 0;NumST= 0;FrameSize= 0;CurrentFrame= 0;NextFrame= 1;Interpol= 0.0f;TriIndex= NULL;VertexList= NULL;ST= NULL;ModelState= IDLE;}bool cAnimModel::Load(char *MeshFile, char *SkinFile){FILE *pFile;// File Pointerint iFileLength;// Length of the Model Filechar *pBuffer;// File BuffersModelHeader *ModelHeader;// Model HeadersTexIndex *pTexIndex;// Texture Index DatasFrame *pFrame;// Frame DatasVertex *pVertexList;// Vertex DatasMesh *pIndexList;// Index Dataint i, j;// For ^2 Loops// Open the FilepFile = fopen(MeshFile, "rb");// Check that it Openedif (pFile == NULL)return false;// Find the Length of the Filefseek(pFile, 0, SEEK_END);iFileLength = ftell(pFile);fseek(pFile, 0, SEEK_SET);// Read the Entire File into the BufferpBuffer = new char[iFileLength + 1];fread(pBuffer, sizeof(char), iFileLength, pFile);// Extract the Header Information from the BufferModelHeader = (sModelHeader *)pBuffer;// Declare and Size-up the Vertex ListVertexList = new sVertex[ModelHeader->NumXYZ * ModelHeader->NumFrames];// Set some VariablesNumVertices= ModelHeader->NumXYZ;NumFrames= ModelHeader->NumFrames;FrameSize= ModelHeader->FrameSize;// Read in the Vertices, Frame-by-Framefor (j = 0; j < NumFrames; j++){// Frame BufferpFrame = (sFrame *)&pBuffer[ModelHeader->OffsetFrames + FrameSize * j];// Point the Vertex List Pointer to the Vertex ListpVertexList = (sVertex *)&VertexList[NumVertices * j];// Read in Each Vertex in the Framefor (i = 0; i < NumVertices; i++){pVertexList.v[0] = pFrame->scale[0] * pFrame->fp.v[0] + pFrame->translate[0];pVertexList.v[1] = pFrame->scale[1] * pFrame->fp.v[1] + pFrame->translate[1];pVertexList.v[2] = pFrame->scale[2] * pFrame->fp.v[2] + pFrame->translate[2];}}// Load the Skin FileTexID = TextureManager->LoadFile(SkinFile);// Get the Number of Texture CoordinatesNumST= ModelHeader->NumST;ST= new sTexCoord[NumST];// Get the Texture Coordinate Indices from the BufferpTexIndex = (sTexIndex *)&pBuffer[ModelHeader->OffsetST];// Loop through and Set the Texture Coordinatesfor (i = 0; i < NumST; i++){ST.s = (float)pTexIndex.s / (float)ModelHeader->SkinWidth;ST.t = (float)pTexIndex.t / (float)ModelHeader->SkinHeight;}// Get the Number of TrianglesNumTriangles= ModelHeader->NumTris;TriIndex= new sMesh[NumTriangles];// Get the Triangle Indices from the BufferpIndexList = (sMesh *)&pBuffer[ModelHeader->OffsetTris];// Create a Triangle List for Each Framefor (j = 0; j < NumTriangles; j++){for (i = 0; i < NumFrames; i++){TriIndex.meshIndex[0] = pIndexList.meshIndex[0];TriIndex.meshIndex[1] = pIndexList.meshIndex[1];TriIndex.meshIndex[2] = pIndexList.meshIndex[2];TriIndex.texIndex[0] = pIndexList.texIndex[0];TriIndex.texIndex[1] = pIndexList.texIndex[1];TriIndex.texIndex[2] = pIndexList.texIndex[2];}}// Close the Filefclose(pFile);// Remove the Buffer from Memoryfree(pBuffer);// Set some Animation VariablesCurrentFrame= 0;NextFrame= 1;Interpol= 0.0f;// We did it?!return true;}int cAnimModel::Animate(int StartFrame, int EndFrame, float Percent){// Vertices for the Current FramesVertex *cVertexList;// Vertices for the Next FramesVertex *nVertexList;// For ^2 Loopsint i;// Current FramePoint Valuesfloat x1, y1, z1;// Next FramePoint Valuesfloat x2, y2, z2;// Buffer Vertices (for a Triangle)sVertex Vertex[3];// Bounds Checkingif (StartFrame > CurrentFrame)CurrentFrame = StartFrame;if ((StartFrame < 0) || (EndFrame < 0))return false;if ((StartFrame >= NumFrames) || (EndFrame >= NumFrames))return false;// Move to the Next Frameif (Interpol >= 1.0){// Reset the Interpolation ValueInterpol = 0.0f;// Increase the Frame CounterCurrentFrame++;// Bounds Checkingif (CurrentFrame >= EndFrame)CurrentFrame = StartFrame;// Set the Next FrameNextFrame = CurrentFrame + 1;// Bounds Checkingif (NextFrame >= EndFrame)NextFrame = StartFrame;}// Set the Vertex ListscVertexList = &VertexList[NumVertices * CurrentFrame];nVertexList = &VertexList[NumVertices * NextFrame];// Bind the TextureglBindTexture(GL_TEXTURE_2D, TexID);// Begin Triangle Drawing ModeglBegin(GL_TRIANGLES);// Loop through and Interpolate the Trianglesfor (i = 0; i < NumTriangles; i++){// Get the First Point of Each Framex1 = cVertexList[TriIndex.meshIndex[0]].v[0];y1 = cVertexList[TriIndex.meshIndex[0]].v[1];z1 = cVertexList[TriIndex.meshIndex[0]].v[2];x2 = nVertexList[TriIndex.meshIndex[0]].v[0];y2 = nVertexList[TriIndex.meshIndex[0]].v[1];z2 = nVertexList[TriIndex.meshIndex[0]].v[2];// Store the Interpolated VertexVertex[0].v[0] = x1 + Interpol * (x2 - x1);Vertex[0].v[1] = y1 + Interpol * (y2 - y1);Vertex[0].v[2] = z1 + Interpol * (z2 - z1);// Get the Second Point of Each Framex1 = cVertexList[TriIndex.meshIndex[2]].v[0];y1 = cVertexList[TriIndex.meshIndex[2]].v[1];z1 = cVertexList[TriIndex.meshIndex[2]].v[2];x2 = nVertexList[TriIndex.meshIndex[2]].v[0];y2 = nVertexList[TriIndex.meshIndex[2]].v[1];z2 = nVertexList[TriIndex.meshIndex[2]].v[2];// Store the Interpolated VertexVertex[2].v[0] = x1 + Interpol * (x2 - x1);Vertex[2].v[1] = y1 + Interpol * (y2 - y1);Vertex[2].v[2] = z1 + Interpol * (z2 - z1);// Get the Third Point of Each Framex1 = cVertexList[TriIndex.meshIndex[1]].v[0];y1 = cVertexList[TriIndex.meshIndex[1]].v[1];z1 = cVertexList[TriIndex.meshIndex[1]].v[2];x2 = nVertexList[TriIndex.meshIndex[1]].v[0];y2 = nVertexList[TriIndex.meshIndex[1]].v[1];z2 = nVertexList[TriIndex.meshIndex[1]].v[2];// Store the Interpolated VertexVertex[1].v[0] = x1 + Interpol * (x2 - x1);Vertex[1].v[1] = y1 + Interpol * (y2 - y1);Vertex[1].v[2] = z1 + Interpol * (z2 - z1);// Draw the Textured TriangleglTexCoord2f(ST[TriIndex.texIndex[0]].s, ST[TriIndex.texIndex[0]].t);glVertex3fv(Vertex[0].v);glTexCoord2f(ST[TriIndex.texIndex[2]].s, ST[TriIndex.texIndex[2]].t);glVertex3fv(Vertex[2].v);glTexCoord2f(ST[TriIndex.texIndex[1]].s, ST[TriIndex.texIndex[1]].t);glVertex3fv(Vertex[1].v);}// End Drawing ModeglEnd();// Increase the InterpolationInterpol += Percent;return 1;}WinMain.cpp// Windows Headers#include <windows.h>#include <windowsx.h>#include <MMSystem.h>// OpenGL Headers#include <GL/gl.h>#include <GL/glu.h>// Define the Window Size#define WINWIDTH  1024#define WINHEIGHT 768// Standard IO Header#include <stdio.h>// Local Includes#include "cAnimModel.h"#include "cCamera.h"cAnimModel *test;#define Camera cCamera::Instance()// Initialisation Codevoid Initialise(){Camera->SetPosition(0, 0, 0);test = new cAnimModel();test->Load("centaur\\Tris.md2", "centaur\\Centaur.bmp");// Class InitialisorsglShadeModel(GL_SMOOTH);glViewport(0, 0, WINWIDTH, WINHEIGHT);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(90.0f,(GLfloat)WINWIDTH/(GLfloat)WINHEIGHT,0.1f,5000.0f);}// OpenGL Rendering Codevoid Render(){glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glMatrixMode(GL_MODELVIEW);glLoadIdentity();// OpenGL Render AttributesglEnable(GL_DEPTH_TEST);glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);glEnable(GL_TEXTURE_2D);// Class Render Functionstest->Animate(0, 39, 0.0016);glFlush();}// Message HandlerLRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){PAINTSTRUCT PaintStruct;HDC hdc;switch (message){case WM_PAINT:BeginPaint(hWnd, &PaintStruct);EndPaint(hWnd, &PaintStruct);break;case WM_SIZE:glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));PostMessage(hWnd, WM_PAINT, 0, 0);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;}HWND CreateOpenGLWindow(LPCWSTR Title,int X, int Y,int Width, int Height,BYTE Type, DWORD Flags){intPaintFormat;HDChDC;HWNDhWnd;WNDCLASSWinClass;PIXELFORMATDESCRIPTORPixFormat;HINSTANCE hInstance= 0;if (!hInstance){// Setup the Window Class PropertieshInstance= GetModuleHandle(NULL);WinClass.style= CS_OWNDC;WinClass.lpfnWndProc= (WNDPROC)WndProc;WinClass.cbClsExtra= 0;WinClass.cbWndExtra= 0;WinClass.hInstance= hInstance;WinClass.hIcon= LoadIcon(NULL, IDI_WINLOGO);WinClass.hCursor= LoadCursor(NULL, IDC_ARROW);WinClass.hbrBackground= NULL;WinClass.lpszMenuName= NULL;WinClass.lpszClassName= L"WindowClass";if (!RegisterClass(&WinClass))return NULL;}hWnd = CreateWindow(L"WindowClass", Title,WS_OVERLAPPEDWINDOW,X, Y, Width, Height,NULL, NULL, hInstance, NULL);if (hWnd == NULL)return NULL;// Get the Window Device ContexthDC = GetDC(hWnd);// Set the Pixel Format Properties for Drawingmemset(&PixFormat, 0, sizeof(PixFormat));PixFormat.nSize= sizeof(PixFormat);PixFormat.nVersion= 1;PixFormat.dwFlags= PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | Flags;PixFormat.iPixelType= Type;PixFormat.cColorBits= 32;PaintFormat = ChoosePixelFormat(hDC, &PixFormat);if (PaintFormat == 0)return NULL;if (SetPixelFormat(hDC, PaintFormat, &PixFormat) == FALSE)return NULL;DescribePixelFormat(hDC, PaintFormat, sizeof(PIXELFORMATDESCRIPTOR), &PixFormat);// Release Device Context from MemoryReleaseDC(hWnd, hDC);// Return the Window Instancereturn hWnd;}// Win32 Application Entry Pointint WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR lpCmdLine,int nCmdShow){HDChDC;// Device ContextHGLRChRC;// OpenGL ContextHWNDhWnd;// WindowhWnd = CreateOpenGLWindow(L"Andy Mills | Realtime Rendering & Animation", 0, 0, WINWIDTH, WINHEIGHT, PFD_TYPE_RGBA, 0);// Exit if Window not Createdif (hWnd == NULL)exit(1);hDC = GetDC(hWnd);hRC = wglCreateContext(hDC);wglMakeCurrent(hDC, hRC);Initialise();// Show the OpenGL WindowShowWindow(hWnd, nCmdShow);// Main Message LoopMSG Message = {0};while (WM_QUIT != Message.message){DWORD StartPoint = GetTickCount();if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)){TranslateMessage(&Message);DispatchMessage(&Message);}Render();while (GetTickCount() - StartPoint < 16);}wglMakeCurrent(NULL, NULL);ReleaseDC(hWnd, hDC);wglDeleteContext(hRC);DestroyWindow(hWnd);return Message.wParam;}
Quote:// Create a Triangle List for Each Framefor (j = 0; j < NumTriangles; j++){for (i = 0; i < NumFrames; i++){TriIndex.meshIndex[0] = pIndexList.meshIndex[0];TriIndex.meshIndex[1] = pIndexList.meshIndex[1];TriIndex.meshIndex[2] = pIndexList.meshIndex[2];TriIndex.texIndex[0] = pIndexList.texIndex[0];TriIndex.texIndex[1] = pIndexList.texIndex[1];TriIndex.texIndex[2] = pIndexList.texIndex[2];}}The main thing I can notice is that the TriIndex array is being set incorrectly. Triangles indices in MD2 are only stored to the total amount of triangles in the mesh, multiple frames have no effect on the amount of triangles. Everything else looks fine.// Create a Triangle Index Listfor (i = 0; i < NumTriangles; i++){TriIndex.meshIndex[0] = pIndexList.meshIndex[0];TriIndex.meshIndex[1] = pIndexList.meshIndex[1];TriIndex.meshIndex[2] = pIndexList.meshIndex[2];TriIndex.texIndex[0] = pIndexList.texIndex[0];TriIndex.texIndex[1] = pIndexList.texIndex[1];TriIndex.texIndex[2] = pIndexList.texIndex[2];} ;  I changed the code as you suggested.  Unfortunately still the same problem.  A memory out of bounds exception when setting the Texture Coordinates.   ;  Try stepping through the code and seeing what the values of the texture coordinates are. When you are testing an MD2 file also make sure it is valid and loads by testing it in other programs, it could be a corrupt MD2.   