   Textures and MD2s
  Hey all,I'm writing a simple game using opengl and md2 models. I'm having problems applying a texture to the md2 model though, i'll post my code below and any help would be greatly appreciated.main.cpp#include <iostream>#include <GL/glu.h>#include <GL/gl.h>#include <GL/glut.h>#include "gameobject.h"#include "plane.h"using namespace std;float angle = 0.0f;plane ss = plane("data/fighter.md2");void initRendering() {glEnable(GL_DEPTH_TEST);glEnable(GL_COLOR_MATERIAL);}void handleResize(int w, int h) {glViewport(0, 0, w, h);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(45.0, (double)w/(double)h, 1.0, 500.0);}void display() {glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glTranslatef( 0.0f, 0.0f, -250.0f);glRotatef( angle, 1.0f, 1.0f, 1.0f);ss.draw();glutSwapBuffers();}void refresh(int value) {angle += 1.5f;if(angle > 360) {angle -= 360;}glutPostRedisplay();glutTimerFunc(25, refresh, 0);}int main(int argc, char** argv) {glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);glutInitWindowSize(500, 500);glutCreateWindow("Welcome to AirDrop.");initRendering();glutDisplayFunc(display);glutReshapeFunc(handleResize);glutTimerFunc(25, refresh, 0);glutMainLoop();}plane.cpp#include "plane.h"#include "imageloader.h"#include <GL/glu.h>#include <GL/gl.h>#include <GL/glut.h>#include <iostream>#include <stdlib.h>#include <SDL/sdl.h>plane::plane() {this->num_vertices = 0;this->vertices = NULL;}plane::plane(const char * filename) {ifstream md2file;md2file.open(filename, ios::in|ios::binary);// C stuffmd2_header_t * md2header = (struct md2_header_t *)malloc(sizeof(struct md2_header_t));// it involves evil casting.  Would be much happier if this was byte *.md2file.read((char *) md2header, sizeof (struct md2_header_t));if ((md2header->ident != 844121161) ||(md2header->version != 8)) {/* Error! */cerr << "Error: bad version or identifier" << endl;}// Get the triangle data.this->triangles = (md2_triangle_t *)calloc(md2header->num_tris, sizeof (struct md2_triangle_t));this->num_triangles = md2header->num_tris;md2file.seekg(md2header->offset_tris, ios::beg);md2file.read((char *) triangles, sizeof (struct md2_triangle_t) * md2header->num_tris);// Get the vertices of the first frame only.// Note: this is dangerous, we _really_// should populate the whole structure as documented in// http://tfc.duke.free.fr/coding/md2-specs-en.htmlthis->vertices = (vec3_t *)calloc (md2header->num_vertices, sizeof (vec3_t));md2file.seekg(md2header->offset_frames, ios::beg);/* Read first frame data */vec3_t * scale = (vec3_t *) malloc(sizeof(vec3_t));md2file.read((char *) scale, sizeof (vec3_t));cout << (*scale)[0] << " " << (*scale)[1] << " " << (*scale)[2] << endl;vec3_t * translate = (vec3_t *) malloc(sizeof(vec3_t));md2file.read((char *) translate, sizeof (vec3_t));cout << (*translate)[0] << " " << (*translate)[1] << " " << (*translate)[2] << endl;// beware the magic numberchar * name = (char *) calloc(16, sizeof(char));md2file.read((char *) name, 16);cout << name << endl;md2_vertex_t * c_vertices = (md2_vertex_t *) calloc(md2header->num_vertices, sizeof (struct md2_vertex_t));md2file.read((char *) c_vertices, (sizeof (struct md2_vertex_t)) *md2header->num_vertices);this->num_vertices = md2header->num_vertices;// Unpack verticesthis->vertices = (vec3_t *) calloc(this->num_vertices, sizeof(vec3_t));for(int i=0; i<this->num_vertices;i++) {this->vertices[0] = (c_vertices.v[0] * (*scale)[0]) + (*translate)[0];this->vertices[1] = (c_vertices.v[1] * (*scale)[1]) + (*translate)[1];this->vertices[2] = (c_vertices.v[2] * (*scale)[2]) + (*translate)[2];}// Hopefully we now have vertices.  Note: No error checking.// cleanupmd2file.close();free(c_vertices);free(scale);free(translate);free(name);free(md2header);}plane::~plane() {// TODO Auto-generated destructor stub}GLuint loadTexture(Image *image) {GLuint textureId;glGenTextures(1, &textureId);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image->width, image->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->pixels);return textureId;}void plane::loadSkin() {textureId = loadTexture("data/fighter.bmp");}void plane::draw() {glBegin(GL_TRIANGLES);for(int i=0; i<this->num_triangles;i++) {for(int j=0; j<3; j++) {glVertex3fv(this->vertices[this->triangles.vertex[j]]);}}glEnd();}plane.h#include <GL/gl.h>#include <stdlib.h>#include <string>#include <iostream>#include <fstream>#include "gameobject.h"using namespace std;#ifndef PLANE_H_#define PLANE_H_class plane {public:plane();plane(const char * filename);virtual ~plane();virtual void loadSkin();virtual void loadTexture();virtual void draw();private:/* MD2 header from http://tfc.duke.free.fr/coding/md2-specs-en.html */struct md2_header_t{  int ident;   /* magic number: "IDP2" */int version; /* version: must be 8 */int skinwidth;    /* texture width */int skinheight;   /* texture height */int framesize;    /* size in bytes of a frame */int num_skins;    /* number of skins */int num_vertices; /* number of vertices per frame */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 offset_skins; /* offset skin data */int offset_st;    /* offset texture coordinate data */int offset_tris;  /* offset triangle data */int offset_frames;/* offset frame data */int offset_glcmds;/* offset OpenGL command data */int offset_end;   /* offset end of file */};/* Compressed vertex */struct md2_vertex_t{  unsigned char v[3];    /* position */unsigned char normalIndex;  /* normal vector index */};/* Triangle info */struct md2_triangle_t{  unsigned short vertex[3];   /* vertex indices of the triangle */unsigned short st[3];  /* tex. coord. indices */};/* Vector */typedef float vec3_t[3];vec3_t * vertices;int num_vertices;md2_triangle_t * triangles;int num_triangles;};#endif /* PLANE_H_ */imageloader.cpp#include <assert.h>#include <fstream>#include "imageloader.h"using namespace std;Image::Image(char* ps, int w, int h) : pixels(ps), width(w), height(h) {}Image::~Image() {delete[] pixels;}namespace {int toInt(const char* bytes) {return (int)(((unsigned char)bytes[3] << 24) | ((unsigned char)bytes[2] << 16) | ((unsigned char)bytes[1] << 8) | (unsigned char)bytes[0]);}short toShort(const char* bytes) {return (short)(((unsigned char)bytes[1] << 8) |   (unsigned char)bytes[0]);}int readInt(ifstream &input) {char buffer[4];input.read(buffer, 4);return toInt(buffer);}short readShort(ifstream &input) {char buffer[2];input.read(buffer, 2);return toShort(buffer);}template<class T>class auto_array {private:T* array;mutable bool isReleased;public:explicit auto_array(T* array_ = NULL) :array(array_), isReleased(false) {}auto_array(const auto_array<T> &aarray) {array = aarray.array;isReleased = aarray.isReleased;aarray.isReleased = true;}~auto_array() {if (!isReleased && array != NULL) {delete[] array;}}T* get() const {return array;}T &operator*() const {return *array;}void operator=(const auto_array<T> &aarray) {if (!isReleased && array != NULL) {delete[] array;}array = aarray.array;isReleased = aarray.isReleased;aarray.isReleased = true;}T* operator->() const {return array;}T* release() {isReleased = true;return array;}void reset(T* array_ = NULL) {if (!isReleased && array != NULL) {delete[] array;}array = array_;}T* operator+(int i) {return array + i;}T &operator[](int i) {return array;}};}Image* loadBMP(const char* filename) {ifstream input;input.open(filename, ifstream::binary);assert(!input.fail() || !"Could not find file");char buffer[2];input.read(buffer, 2);assert(buffer[0] == 'B' && buffer[1] == 'M' || !"Not a bitmap file");input.ignore(8);int dataOffset = readInt(input);int headerSize = readInt(input);int width;int height;switch(headerSize) {case 40://V3width = readInt(input);height = readInt(input);input.ignore(2);assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");assert(readShort(input) == 0 || !"Image is compressed");break;case 12://OS/2 V1width = readShort(input);height = readShort(input);input.ignore(2);assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");break;case 64://OS/2 V2assert(!"Can't load OS/2 V2 bitmaps");break;case 108://Windows V4assert(!"Can't load Windows V4 bitmaps");break;case 124://Windows V5assert(!"Can't load Windows V5 bitmaps");break;default:assert(!"Unknown Format");}int bytesPerRow = ((width * 3 + 3) / 4) * 4 - (width * 3 % 4);int size = bytesPerRow * height;auto_array<char> pixels(new char[size]);input.seekg(dataOffset, ios_base::beg);input.read(pixels.get(), size);auto_array<char> pixels2(new char[width * height * 3]);for(int y = 0; y < height; y++) {for(int x = 0; x < width; x++) {for(int c = 0; c < 3; c++) {pixels2[3 * (width * y + x) + c] =pixels[bytesPerRow * y + 3 * x + (2 - c)];}}}input.close();return new Image(pixels2.release(), width, height);}imageloader.h#ifndef IMAGELOADER_H_#define IMAGELOADER_H_class Image {public:Image(char* ps, int w, int h);~Image();char* pixels;int width;int height;};Image* loadBMP(const char* filename);#endif /* IMAGELOADER_H_ */gameobject.h#ifndef GAMEOBJECT_H_#define GAMEOBJECT_H_class GameObject {public:virtual void draw() = 0;};#endif
  When you draw, you're only specifying the vertices, you need to bind the texture and specify the texture coordinates as well.  It looks like you need to load the texture coordinate as well.   ;  Any ideas about how I would go about doing that?   