我试图找出颜色问题。我创建了一个从高度图加载的景观和一个从 MD2 模型加载的动画。MD2 模型将从位图纹理中获取颜色。景观的颜色必须由 glColor3f 设置。
现在问题出在我的 Draw 方法中:
void drawScene() {
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(cameraPositionX, cameraPositionY, cameraPositionZ, cameraAimX, cameraAimY, cameraAimZ, 0, 1, 0);
GLfloat ambientColor[] = {0.4f, 0.4f, 0.4f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);
GLfloat lightColor0[] = {0.6f, 0.6f, 0.6f, 1.0f};
GLfloat lightPos0[] = {-0.5f, 0.8f, 0.1f, 0.0f};
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
if (_model != NULL) {
glPushMatrix();
glTranslatef(modelPositionX, modelPositionY, modelPositionZ);
glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
glRotatef(110.0f, 1.0f, 0.0f, 0.0f);
glScalef(0.2f, 0.2f, 0.2f);
_model->draw();
glPopMatrix();
}
glTranslatef(-(float)(_terrain->width() - 1) / 2,
0.0f,
-(float)(_terrain->length() - 1) / 2);
glColor3f(0.0f, 1.0f, 0.0f);
for(int z = 0; z < _terrain->length() - 1; z++) {
glBegin(GL_TRIANGLE_STRIP);
for(int x = 0; x < _terrain->width(); x++) {
Vec3f normal = _terrain->getNormal(x, z);
glNormal3f(normal[0], normal[1], normal[2]);
glVertex3f(x, _terrain->getHeight(x, z), z);
normal = _terrain->getNormal(x, z + 1);
glNormal3f(normal[0], normal[1], normal[2]);
glVertex3f(x, _terrain->getHeight(x, z + 1), z + 1);
}
glEnd();
}
glutSwapBuffers();
}
当我注释掉 glColor3f(0.0f, 1.0f, 0.0f); 声明,景观将获得与动画从位图纹理获得的颜色相同的颜色。但是当我包含 glColor3f(0.0f, 1.0f, 0.0f); 声明,动画将获得与风景相同的颜色。我想让动画和风景有不同的颜色。
这是完整的 main.cpp 类和 md2model.cpp 类。
主文件
#include <iostream>
#include <stdlib.h>
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include "imageloader.h"
#include "imageloader.cpp"
#include "vec3f.h"
#include "vec3f.cpp"
#include "md2model.h"
#include "md2model.cpp"
using namespace std;
class Terrain {
private:
int w;
int l;
float** hs;
Vec3f** normals;
bool computedNormals;
public:
Terrain(int w2, int l2) {
w = w2;
l = l2;
hs = new float*[l];
for(int i = 0; i < l; i++) {
hs[i] = new float[w];
}
normals = new Vec3f*[l];
for(int i = 0; i < l; i++) {
normals[i] = new Vec3f[w];
}
computedNormals = false;
}
~Terrain() {
for(int i = 0; i < l; i++) {
delete[] hs[i];
}
delete[] hs;
for(int i = 0; i < l; i++) {
delete[] normals[i];
}
delete[] normals;
}
int width() {
return w;
}
int length() {
return l;
}
void setHeight(int x, int z, float y) {
hs[z][x] = y;
computedNormals = false;
}
float getHeight(int x, int z) {
return hs[z][x];
}
void computeNormals() {
if (computedNormals) {
return;
}
Vec3f** normals2 = new Vec3f*[l];
for(int i = 0; i < l; i++) {
normals2[i] = new Vec3f[w];
}
for(int z = 0; z < l; z++) {
for(int x = 0; x < w; x++) {
Vec3f sum(0.0f, 0.0f, 0.0f);
Vec3f out;
if (z > 0) {
out = Vec3f(0.0f, hs[z - 1][x] - hs[z][x], -1.0f);
}
Vec3f in;
if (z < l - 1) {
in = Vec3f(0.0f, hs[z + 1][x] - hs[z][x], 1.0f);
}
Vec3f left;
if (x > 0) {
left = Vec3f(-1.0f, hs[z][x - 1] - hs[z][x], 0.0f);
}
Vec3f right;
if (x < w - 1) {
right = Vec3f(1.0f, hs[z][x + 1] - hs[z][x], 0.0f);
}
if (x > 0 && z > 0) {
sum += out.cross(left).normalize();
}
if (x > 0 && z < l - 1) {
sum += left.cross(in).normalize();
}
if (x < w - 1 && z < l - 1) {
sum += in.cross(right).normalize();
}
if (x < w - 1 && z > 0) {
sum += right.cross(out).normalize();
}
normals2[z][x] = sum;
}
}
const float FALLOUT_RATIO = 0.5f;
for(int z = 0; z < l; z++) {
for(int x = 0; x < w; x++) {
Vec3f sum = normals2[z][x];
if (x > 0) {
sum += normals2[z][x - 1] * FALLOUT_RATIO;
}
if (x < w - 1) {
sum += normals2[z][x + 1] * FALLOUT_RATIO;
}
if (z > 0) {
sum += normals2[z - 1][x] * FALLOUT_RATIO;
}
if (z < l - 1) {
sum += normals2[z + 1][x] * FALLOUT_RATIO;
}
if (sum.magnitude() == 0) {
sum = Vec3f(0.0f, 1.0f, 0.0f);
}
normals[z][x] = sum;
}
}
for(int i = 0; i < l; i++) {
delete[] normals2[i];
}
delete[] normals2;
computedNormals = true;
}
Vec3f getNormal(int x, int z) {
if (!computedNormals) {
computeNormals();
}
return normals[z][x];
}
};
Terrain* loadTerrain(const char* filename, float height) {
Image* image = loadBMP(filename);
Terrain* t = new Terrain(image->width, image->height);
for(int y = 0; y < image->height; y++) {
for(int x = 0; x < image->width; x++) {
unsigned char color =
(unsigned char)image->pixels[3 * (y * image->width + x)];
float h = height * ((color / 255.0f) - 0.5f);
t->setHeight(x, y, h);
}
}
delete image;
t->computeNormals();
return t;
}
float cameraPositionX = 2;
float cameraPositionY = 2;
float cameraPositionZ = 1;
float cameraAimX = 0;
float cameraAimY = 0;
float cameraAimZ = 0;
float modelPositionX = 0;
float modelPositionY = 1;
float modelPositionZ = 0;
Terrain* _terrain;
MD2Model* _model;
void cleanup() {
delete _terrain;
delete _model;
}
void handleKeypress(unsigned char key, int x, int y) {
switch (key) {
case 27:
cleanup();
exit(0);
}
}
void handleSpecialKeypress(int key, int x, int y) {
switch (key) {
case GLUT_KEY_UP:
cameraPositionX -= 0.5;
cameraAimX -= 0.5;
modelPositionX -= 0.5;
if (_model != NULL) {
_model->advance(0.025f);
}
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
cameraPositionX += 0.5;
cameraAimX += 0.5;
modelPositionX += 0.5;
if (_model != NULL) {
_model->advance(0.025f);
}
glutPostRedisplay();
break;
case GLUT_KEY_LEFT:
//Do something
break;
case GLUT_KEY_RIGHT:
//Do something
break;
}
}
void initRendering() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glShadeModel(GL_SMOOTH);
_model = MD2Model::load("tallguy.md2");
if (_model != NULL) {
_model->setAnimation("run");
}
}
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(105.0, (double)w / (double)h, 1.0, 500.0);
}
void drawScene() {
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(cameraPositionX, cameraPositionY, cameraPositionZ, cameraAimX, cameraAimY, cameraAimZ, 0, 1, 0);
GLfloat ambientColor[] = {0.4f, 0.4f, 0.4f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);
GLfloat lightColor0[] = {0.6f, 0.6f, 0.6f, 1.0f};
GLfloat lightPos0[] = {-0.5f, 0.8f, 0.1f, 0.0f};
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
if (_model != NULL) {
glPushMatrix();
glTranslatef(modelPositionX, modelPositionY, modelPositionZ);
glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
glRotatef(110.0f, 1.0f, 0.0f, 0.0f);
glScalef(0.2f, 0.2f, 0.2f);
_model->draw();
glPopMatrix();
}
glTranslatef(-(float)(_terrain->width() - 1) / 2,
0.0f,
-(float)(_terrain->length() - 1) / 2);
//glColor3f(0.0f, 1.0f, 0.0f);
for(int z = 0; z < _terrain->length() - 1; z++) {
glBegin(GL_TRIANGLE_STRIP);
for(int x = 0; x < _terrain->width(); x++) {
Vec3f normal = _terrain->getNormal(x, z);
glNormal3f(normal[0], normal[1], normal[2]);
glVertex3f(x, _terrain->getHeight(x, z), z);
normal = _terrain->getNormal(x, z + 1);
glNormal3f(normal[0], normal[1], normal[2]);
glVertex3f(x, _terrain->getHeight(x, z + 1), z + 1);
}
glEnd();
}
glutSwapBuffers();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(400, 400);
glutCreateWindow("Terrain");
initRendering();
_terrain = loadTerrain("heightmap.bmp", 50);
glutDisplayFunc(drawScene);
glutKeyboardFunc(handleKeypress);
glutSpecialFunc(handleSpecialKeypress);
glutReshapeFunc(handleResize);
glutMainLoop();
return 0;
}
M2DModel.cpp
#include <fstream>
#include "imageloader.h"
#include "md2model.h"
#include "string.h"
using namespace std;
namespace {
//Normals used in the MD2 file format
float NORMALS[486] =
{-0.525731f, 0.000000f, 0.850651f,
-0.442863f, 0.238856f, 0.864188f,
-0.295242f, 0.000000f, 0.955423f,
-0.309017f, 0.500000f, 0.809017f,
-0.162460f, 0.262866f, 0.951056f,
0.000000f, 0.000000f, 1.000000f,
0.000000f, 0.850651f, 0.525731f,
-0.147621f, 0.716567f, 0.681718f,
0.147621f, 0.716567f, 0.681718f,
0.000000f, 0.525731f, 0.850651f,
0.309017f, 0.500000f, 0.809017f,
0.525731f, 0.000000f, 0.850651f,
0.295242f, 0.000000f, 0.955423f,
0.442863f, 0.238856f, 0.864188f,
0.162460f, 0.262866f, 0.951056f,
-0.681718f, 0.147621f, 0.716567f,
-0.809017f, 0.309017f, 0.500000f,
-0.587785f, 0.425325f, 0.688191f,
-0.850651f, 0.525731f, 0.000000f,
-0.864188f, 0.442863f, 0.238856f,
-0.716567f, 0.681718f, 0.147621f,
-0.688191f, 0.587785f, 0.425325f,
-0.500000f, 0.809017f, 0.309017f,
-0.238856f, 0.864188f, 0.442863f,
-0.425325f, 0.688191f, 0.587785f,
-0.716567f, 0.681718f, -0.147621f,
-0.500000f, 0.809017f, -0.309017f,
-0.525731f, 0.850651f, 0.000000f,
0.000000f, 0.850651f, -0.525731f,
-0.238856f, 0.864188f, -0.442863f,
0.000000f, 0.955423f, -0.295242f,
-0.262866f, 0.951056f, -0.162460f,
0.000000f, 1.000000f, 0.000000f,
0.000000f, 0.955423f, 0.295242f,
-0.262866f, 0.951056f, 0.162460f,
0.238856f, 0.864188f, 0.442863f,
0.262866f, 0.951056f, 0.162460f,
0.500000f, 0.809017f, 0.309017f,
0.238856f, 0.864188f, -0.442863f,
0.262866f, 0.951056f, -0.162460f,
0.500000f, 0.809017f, -0.309017f,
0.850651f, 0.525731f, 0.000000f,
0.716567f, 0.681718f, 0.147621f,
0.716567f, 0.681718f, -0.147621f,
0.525731f, 0.850651f, 0.000000f,
0.425325f, 0.688191f, 0.587785f,
0.864188f, 0.442863f, 0.238856f,
0.688191f, 0.587785f, 0.425325f,
0.809017f, 0.309017f, 0.500000f,
0.681718f, 0.147621f, 0.716567f,
0.587785f, 0.425325f, 0.688191f,
0.955423f, 0.295242f, 0.000000f,
1.000000f, 0.000000f, 0.000000f,
0.951056f, 0.162460f, 0.262866f,
0.850651f, -0.525731f, 0.000000f,
0.955423f, -0.295242f, 0.000000f,
0.864188f, -0.442863f, 0.238856f,
0.951056f, -0.162460f, 0.262866f,
0.809017f, -0.309017f, 0.500000f,
0.681718f, -0.147621f, 0.716567f,
0.850651f, 0.000000f, 0.525731f,
0.864188f, 0.442863f, -0.238856f,
0.809017f, 0.309017f, -0.500000f,
0.951056f, 0.162460f, -0.262866f,
0.525731f, 0.000000f, -0.850651f,
0.681718f, 0.147621f, -0.716567f,
0.681718f, -0.147621f, -0.716567f,
0.850651f, 0.000000f, -0.525731f,
0.809017f, -0.309017f, -0.500000f,
0.864188f, -0.442863f, -0.238856f,
0.951056f, -0.162460f, -0.262866f,
0.147621f, 0.716567f, -0.681718f,
0.309017f, 0.500000f, -0.809017f,
0.425325f, 0.688191f, -0.587785f,
0.442863f, 0.238856f, -0.864188f,
0.587785f, 0.425325f, -0.688191f,
0.688191f, 0.587785f, -0.425325f,
-0.147621f, 0.716567f, -0.681718f,
-0.309017f, 0.500000f, -0.809017f,
0.000000f, 0.525731f, -0.850651f,
-0.525731f, 0.000000f, -0.850651f,
-0.442863f, 0.238856f, -0.864188f,
-0.295242f, 0.000000f, -0.955423f,
-0.162460f, 0.262866f, -0.951056f,
0.000000f, 0.000000f, -1.000000f,
0.295242f, 0.000000f, -0.955423f,
0.162460f, 0.262866f, -0.951056f,
-0.442863f, -0.238856f, -0.864188f,
-0.309017f, -0.500000f, -0.809017f,
-0.162460f, -0.262866f, -0.951056f,
0.000000f, -0.850651f, -0.525731f,
-0.147621f, -0.716567f, -0.681718f,
0.147621f, -0.716567f, -0.681718f,
0.000000f, -0.525731f, -0.850651f,
0.309017f, -0.500000f, -0.809017f,
0.442863f, -0.238856f, -0.864188f,
0.162460f, -0.262866f, -0.951056f,
0.238856f, -0.864188f, -0.442863f,
0.500000f, -0.809017f, -0.309017f,
0.425325f, -0.688191f, -0.587785f,
0.716567f, -0.681718f, -0.147621f,
0.688191f, -0.587785f, -0.425325f,
0.587785f, -0.425325f, -0.688191f,
0.000000f, -0.955423f, -0.295242f,
0.000000f, -1.000000f, 0.000000f,
0.262866f, -0.951056f, -0.162460f,
0.000000f, -0.850651f, 0.525731f,
0.000000f, -0.955423f, 0.295242f,
0.238856f, -0.864188f, 0.442863f,
0.262866f, -0.951056f, 0.162460f,
0.500000f, -0.809017f, 0.309017f,
0.716567f, -0.681718f, 0.147621f,
0.525731f, -0.850651f, 0.000000f,
-0.238856f, -0.864188f, -0.442863f,
-0.500000f, -0.809017f, -0.309017f,
-0.262866f, -0.951056f, -0.162460f,
-0.850651f, -0.525731f, 0.000000f,
-0.716567f, -0.681718f, -0.147621f,
-0.716567f, -0.681718f, 0.147621f,
-0.525731f, -0.850651f, 0.000000f,
-0.500000f, -0.809017f, 0.309017f,
-0.238856f, -0.864188f, 0.442863f,
-0.262866f, -0.951056f, 0.162460f,
-0.864188f, -0.442863f, 0.238856f,
-0.809017f, -0.309017f, 0.500000f,
-0.688191f, -0.587785f, 0.425325f,
-0.681718f, -0.147621f, 0.716567f,
-0.442863f, -0.238856f, 0.864188f,
-0.587785f, -0.425325f, 0.688191f,
-0.309017f, -0.500000f, 0.809017f,
-0.147621f, -0.716567f, 0.681718f,
-0.425325f, -0.688191f, 0.587785f,
-0.162460f, -0.262866f, 0.951056f,
0.442863f, -0.238856f, 0.864188f,
0.162460f, -0.262866f, 0.951056f,
0.309017f, -0.500000f, 0.809017f,
0.147621f, -0.716567f, 0.681718f,
0.000000f, -0.525731f, 0.850651f,
0.425325f, -0.688191f, 0.587785f,
0.587785f, -0.425325f, 0.688191f,
0.688191f, -0.587785f, 0.425325f,
-0.955423f, 0.295242f, 0.000000f,
-0.951056f, 0.162460f, 0.262866f,
-1.000000f, 0.000000f, 0.000000f,
-0.850651f, 0.000000f, 0.525731f,
-0.955423f, -0.295242f, 0.000000f,
-0.951056f, -0.162460f, 0.262866f,
-0.864188f, 0.442863f, -0.238856f,
-0.951056f, 0.162460f, -0.262866f,
-0.809017f, 0.309017f, -0.500000f,
-0.864188f, -0.442863f, -0.238856f,
-0.951056f, -0.162460f, -0.262866f,
-0.809017f, -0.309017f, -0.500000f,
-0.681718f, 0.147621f, -0.716567f,
-0.681718f, -0.147621f, -0.716567f,
-0.850651f, 0.000000f, -0.525731f,
-0.688191f, 0.587785f, -0.425325f,
-0.587785f, 0.425325f, -0.688191f,
-0.425325f, 0.688191f, -0.587785f,
-0.425325f, -0.688191f, -0.587785f,
-0.587785f, -0.425325f, -0.688191f,
-0.688191f, -0.587785f, -0.425325f};
//Returns whether the system is little-endian
bool littleEndian() {
//The short value 1 has bytes (1, 0) in little-endian and (0, 1) in
//big-endian
short s = 1;
return (((char*)&s)[0]) == 1;
}
//Converts a two-character array to an unsigned short, using little-endian
//form
unsigned short toUShort(const char* bytes) {
return (unsigned short)(((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Converts a four-character array to a float, using little-endian form
float toFloat(const char* bytes) {
float f;
if (littleEndian()) {
((char*)&f)[0] = bytes[0];
((char*)&f)[1] = bytes[1];
((char*)&f)[2] = bytes[2];
((char*)&f)[3] = bytes[3];
}
else {
((char*)&f)[0] = bytes[3];
((char*)&f)[1] = bytes[2];
((char*)&f)[2] = bytes[1];
((char*)&f)[3] = bytes[0];
}
return f;
}
//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);
}
//Makes the image into a texture, and returns the id of the texture
GLuint loadTexture(Image *image) {
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
image->width, image->height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
image->pixels);
return textureId;
}
}
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;
}
//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;
}
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
//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
//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;
//Load the texture coordinates
input.seekg(texCoordOffset, ios_base::beg);
model->texCoords = new MD2TexCoord[numTexCoords];
for(int i = 0; i < numTexCoords; i++) {
MD2TexCoord* texCoord = model->texCoords + i;
texCoord->texCoordX = (float)readShort(input) / textureWidth;
texCoord->texCoordY = 1 - (float)readShort(input) / textureHeight;
}
//Load the triangles
input.seekg(triangleOffset, ios_base::beg);
model->triangles = new MD2Triangle[numTriangles];
model->numTriangles = numTriangles;
for(int i = 0; i < numTriangles; i++) {
MD2Triangle* triangle = model->triangles + i;
for(int j = 0; j < 3; j++) {
triangle->vertices[j] = readUShort(input);
}
for(int j = 0; j < 3; j++) {
triangle->texCoords[j] = readUShort(input);
}
}
//Load the frames
input.seekg(frameOffset, ios_base::beg);
model->frames = new MD2Frame[numFrames];
model->numFrames = numFrames;
for(int i = 0; i < numFrames; i++) {
MD2Frame* frame = model->frames + i;
frame->vertices = new MD2Vertex[numVertices];
Vec3f scale = readVec3f(input);
Vec3f translation = readVec3f(input);
input.read(frame->name, 16);
for(int j = 0; j < numVertices; j++) {
MD2Vertex* vertex = frame->vertices + j;
input.read(buffer, 3);
Vec3f v((unsigned char)buffer[0],
(unsigned char)buffer[1],
(unsigned char)buffer[2]);
vertex->pos = translation + Vec3f(scale[0] * v[0],
scale[1] * v[1],
scale[2] * v[2]);
input.read(buffer, 1);
int normalIndex = (int)((unsigned char)buffer[0]);
vertex->normal = Vec3f(NORMALS[3 * normalIndex],
NORMALS[3 * normalIndex + 1],
NORMALS[3 * normalIndex + 2]);
}
}
model->startFrame = 0;
model->endFrame = numFrames - 1;
return model;
}
void MD2Model::setAnimation(const char* name) {
/* The names of frames normally begin with the name of the animation in
* which they are, e.g. "run", and are followed by a non-alphabetical
* character. Normally, they indicate their frame number in the animation,
* e.g. "run_1", "run_2", etc.
*/
bool found = false;
for(int i = 0; i < numFrames; i++) {
MD2Frame* frame = frames + i;
if (strlen(frame->name) > strlen(name) &&
strncmp(frame->name, name, strlen(name)) == 0 &&
!isalpha(frame->name[strlen(name)])) {
if (!found) {
found = true;
startFrame = i;
}
else {
endFrame = i;
}
}
else if (found) {
break;
}
}
}
void MD2Model::advance(float dt) {
if (dt < 0) {
return;
}
time += dt;
if (time < 1000000000) {
time -= (int)time;
}
else {
time = 0;
}
}
void MD2Model::draw() {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//Figure out the two frames between which we are interpolating
int frameIndex1 = (int)(time * (endFrame - startFrame + 1)) + startFrame;
if (frameIndex1 > endFrame) {
frameIndex1 = startFrame;
}
int frameIndex2;
if (frameIndex1 < endFrame) {
frameIndex2 = frameIndex1 + 1;
}
else {
frameIndex2 = startFrame;
}
MD2Frame* frame1 = frames + frameIndex1;
MD2Frame* frame2 = frames + frameIndex2;
//Figure out the fraction that we are between the two frames
float frac =
(time - (float)(frameIndex1 - startFrame) /
(float)(endFrame - startFrame + 1)) * (endFrame - startFrame + 1);
//Draw the model as an interpolation between the two frames
glBegin(GL_TRIANGLES);
for(int i = 0; i < numTriangles; i++) {
MD2Triangle* triangle = triangles + i;
for(int j = 0; j < 3; j++) {
MD2Vertex* v1 = frame1->vertices + triangle->vertices[j];
MD2Vertex* v2 = frame2->vertices + triangle->vertices[j];
Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;
Vec3f normal = v1->normal * (1 - frac) + v2->normal * frac;
if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) {
normal = Vec3f(0, 0, 1);
}
glNormal3f(normal[0], normal[1], normal[2]);
MD2TexCoord* texCoord = texCoords + triangle->texCoords[j];
glTexCoord2f(texCoord->texCoordX, texCoord->texCoordY);
glVertex3f(pos[0], pos[1], pos[2]);
}
}
glEnd();
}