//Reads the next four bytes as an integer, using little-endian form
int readInt(ifstream &input) {
char buffer[4];
input.read(buffer, 4);
return toInt(buffer);
}
//Reads the next two bytes as a short, using little-endian form
short readShort(ifstream &input) {
char buffer[2];
input.read(buffer, 2);
return toShort(buffer);
}
//Reads the next two bytes as an unsigned short, using little-endian form
unsigned short readUShort(ifstream &input) {
char buffer[2];
input.read(buffer, 2);
return toUShort(buffer);
}
//Reads the next four bytes as a float, using little-endian form
float readFloat(ifstream &input) {
char buffer[4];
input.read(buffer, 4);
return toFloat(buffer);
}
//Calls readFloat three times and returns the results as a Vec3f object
Vec3f readVec3f(ifstream &input) {
float x = readFloat(input);
float y = readFloat(input);
float z = readFloat(input);
return Vec3f(x, y, z);
}
这些函数使得从一个文件中读取int, short, unsigned short, float, Ver3f数据比较的方便。
//Makes the image into a texture, and returns the id of the texture
GLuint loadTexture(Image *image) {
//...
}
}
这是我们从纹理渲染那课学过的函数。
MD2Model::~MD2Model() {
if (frames != NULL) {
for(int i = 0; i < numFrames; i++) {
delete[] frames[i].vertices;
}
delete[] frames;
}
if (texCoords != NULL) {
delete[] texCoords;
}
if (triangles != NULL) {
delete[] triangles;
}
}
这是类的析构函数,它释放所有申请的内存,包括顶点,帧,纹理,三角形。
MD2Model::MD2Model() {
frames = NULL;
texCoords = NULL;
triangles = NULL;
time = 0;
}
构造函数初始化一些变量,但并没有做多少事情。初始化在load方法中。
//Loads the MD2 model
MD2Model* MD2Model::load(const char* filename) {
ifstream input;
input.open(filename, istream::binary);
char buffer[64];
input.read(buffer, 4); //Should be "IPD2", if this is an MD2 file
if (buffer[0] != 'I' || buffer[1] != 'D' ||
buffer[2] != 'P' || buffer[3] != '2') {
return NULL;
}
if (readInt(input) != 8) { //The version number
return NULL;
}
这是加载MD2文件的方法。首先,检验文件前四个字节是否是"IPD2",这是MD2文件标识。然后,检验接下来的4个字节,表示为整型,值为8,这是加载的MD2文件的对应版本数字。
int textureWidth = readInt(input); //The width of the textures
int textureHeight = readInt(input); //The height of the textures
readInt(input); //The number of bytes per frame
int numTextures = readInt(input); //The number of textures
if (numTextures != 1) {
return NULL;
}
int numVertices = readInt(input); //The number of vertices
int numTexCoords = readInt(input); //The number of texture coordinates
int numTriangles = readInt(input); //The number of triangles
readInt(input); //The number of OpenGL commands
int numFrames = readInt(input); //The number of frames
接下来MD2文件格式指明,必须要有包含了动画顺序的一些特定的信息。我们将这些信息保存在变量中。有一些信息我们用不到,就直接丢弃了。
//Offsets (number of bytes after the beginning of the file to the beginning
//of where certain data appear)
int textureOffset = readInt(input); //The offset to the textures
int texCoordOffset = readInt(input); //The offset to the texture coordinates
int triangleOffset = readInt(input); //The offset to the triangles
int frameOffset = readInt(input); //The offset to the frames
readInt(input); //The offset to the OpenGL commands
readInt(input); //The offset to the end of the file
接下来MD2文件需要包含一些指明数据出现的位置的偏移量。
//Load the texture
input.seekg(textureOffset, ios_base::beg);
input.read(buffer, 64);
if (strlen(buffer) < 5 ||
strcmp(buffer + strlen(buffer) - 4, ".bmp") != 0) {
return NULL;
}
Image* image = loadBMP(buffer);
GLuint textureId = loadTexture(image);
delete image;
MD2Model* model = new MD2Model();
model->textureId = textureId;
我们找到纹理存放的地方,并把接下来的64个字节作为字符串读入。这个字符串是用于模型的纹理的文件名。我们确保这个纹理是个bitmap,并载入。