Created
February 28, 2014 17:42
-
-
Save gszauer/9275752 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* md3-vbo.c -- md3 model loader | |
* last modification: mar. 22, 2009 | |
* | |
* Copyright (c) 2009 David HENRY | |
* | |
* Permission is hereby granted, free of charge, to any person | |
* obtaining a copy of this software and associated documentation | |
* files (the "Software"), to deal in the Software without | |
* restriction, including without limitation the rights to use, | |
* copy, modify, merge, publish, distribute, sublicense, and/or | |
* sell copies of the Software, and to permit persons to whom the | |
* Software is furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be | |
* included in all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
* NONINFRINGEMENT. | |
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | |
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
* | |
* gcc -Wall -ansi -lGL -lGLU -lglew -lglut md3-vbo.c -o md3-vbo | |
*/ | |
#include <GL/glew.h> | |
#include <GL/glut.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <math.h> | |
#define BUFFER_OFFSET(x) ((char *)NULL + x) | |
/* Vectors */ | |
typedef float vec2_t[2]; | |
typedef float vec3_t[3]; | |
/* MD3 header */ | |
struct md3_header_t | |
{ | |
int ident; | |
int version; | |
char name[64]; | |
int flags; | |
int num_frames; | |
int num_tags; | |
int num_meshes; | |
int num_skins; | |
int offset_frames; | |
int offset_tag; | |
int offset_meshes; | |
int offset_eof; | |
}; | |
/* Frame data */ | |
struct md3_frame_t | |
{ | |
vec3_t min_bounds; | |
vec3_t max_bounds; | |
vec3_t local_origin; | |
float radius; | |
char creator[16]; | |
}; | |
/* Tag information */ | |
struct md3_tag_t | |
{ | |
char name[64]; | |
vec3_t origin; | |
float axis[3][3]; | |
}; | |
/* Mesh header */ | |
struct md3_mesh_header_t | |
{ | |
int ident; | |
char name[64]; | |
int flags; | |
int num_frames; | |
int num_shaders; | |
int num_verts; | |
int num_triangles; | |
int offset_triangles; | |
int offset_shaders; | |
int offset_st; | |
int offset_xyznormal; | |
int offset_end; | |
}; | |
/* Mesh shader */ | |
struct md3_shader_t | |
{ | |
char name[64]; | |
int shader_index; | |
}; | |
/* Triangle info */ | |
struct md3_triangle_t | |
{ | |
int index[3]; | |
}; | |
/* Texture coordinates */ | |
struct md3_texCoord_t | |
{ | |
float s; | |
float t; | |
}; | |
/* Compressed vertex data */ | |
struct md3_vertex_t | |
{ | |
short v[3]; | |
unsigned char normal[2]; | |
}; | |
/* MD3 mesh structure */ | |
struct md3_mesh_t | |
{ | |
struct md3_mesh_header_t header; | |
struct md3_shader_t *shaders; | |
struct md3_triangle_t *triangles; | |
struct md3_texCoord_t *texcoords; | |
struct md3_vertex_t *vertices; | |
/* Index buffer range */ | |
GLuint start, end; | |
GLuint count, offset; | |
}; | |
/* MD3 model structure */ | |
struct md3_model_t | |
{ | |
struct md3_header_t header; | |
struct md3_frame_t *frames; | |
struct md3_mesh_t *meshes; | |
struct md3_tag_t *tags; | |
/* Vertex and Index buffer objects */ | |
GLuint vbo; | |
GLuint ibo; | |
}; | |
/* Vertex Data for VBOs */ | |
struct Vertex_VNT | |
{ | |
GLfloat xyz[3]; | |
GLfloat norm[3]; | |
GLfloat st[2]; | |
}; | |
/* Table of precalculated normals */ | |
vec3_t anorms_table[256][256]; | |
/*** An MD3 model ***/ | |
struct md3_model_t md3file; | |
/** | |
* Generate the pre-computed normals used by MD3 models. | |
*/ | |
void | |
BuildNormalLookupTable () | |
{ | |
const float pi = 3.14159265358979323846; | |
float lat, lon; | |
int i, j; | |
for (i = 0; i < 256; i++) | |
{ | |
for (j = 0; j < 256; j++) | |
{ | |
lat = j * 2.0f * pi / 255.0f; | |
lon = i * 2.0f * pi / 255.0f; | |
anorms_table[i][j][0] = cos (lat) * sin (lon); | |
anorms_table[i][j][1] = sin (lat) * sin (lon); | |
anorms_table[i][j][2] = cos (lon); | |
} | |
} | |
} | |
/** | |
* Load an MD3 mesh from MD3 file. | |
* | |
* Note: MD3 format stores model's data in little-endian ordering. On | |
* big-endian machines, you'll have to perform proper conversions. | |
*/ | |
int | |
ReadMd3Mesh (FILE *fp, struct md3_mesh_t *mesh) | |
{ | |
long pos; | |
pos = ftell (fp); | |
/* Read header */ | |
fread (&mesh->header, 1, sizeof (struct md3_mesh_header_t), fp); | |
if (mesh->header.ident != 860898377) | |
{ | |
/* Error! */ | |
fprintf (stderr, "Error: bad mesh identifier\n"); | |
return 0; | |
} | |
/* Memory allocations */ | |
mesh->shaders = (struct md3_shader_t *) | |
malloc (sizeof (struct md3_shader_t) * mesh->header.num_shaders); | |
mesh->triangles = (struct md3_triangle_t *) | |
malloc (sizeof (struct md3_triangle_t) * mesh->header.num_triangles); | |
mesh->texcoords = (struct md3_texCoord_t *) | |
malloc (sizeof (struct md3_texCoord_t) * mesh->header.num_verts); | |
mesh->vertices = (struct md3_vertex_t *) | |
malloc (sizeof (struct md3_vertex_t) * mesh->header.num_verts * mesh->header.num_frames); | |
/* Read mesh data */ | |
fseek (fp, pos + mesh->header.offset_shaders, SEEK_SET); | |
fread (mesh->shaders, sizeof (struct md3_shader_t), | |
mesh->header.num_shaders, fp); | |
fseek (fp, pos + mesh->header.offset_triangles, SEEK_SET); | |
fread (mesh->triangles, sizeof (struct md3_triangle_t), | |
mesh->header.num_triangles, fp); | |
fseek (fp, pos + mesh->header.offset_st, SEEK_SET); | |
fread (mesh->texcoords, sizeof (struct md3_texCoord_t), | |
mesh->header.num_verts, fp); | |
fseek (fp, pos + mesh->header.offset_xyznormal, SEEK_SET); | |
fread (mesh->vertices, sizeof (struct md3_vertex_t), | |
mesh->header.num_verts * mesh->header.num_frames, fp); | |
fseek (fp, pos + mesh->header.offset_end, SEEK_SET); | |
return 1; | |
} | |
/** | |
* Load an MD3 model from file. | |
* | |
* Note: MD3 format stores model's data in little-endian ordering. On | |
* big-endian machines, you'll have to perform proper conversions. | |
*/ | |
int | |
ReadMD3Model (const char *filename, struct md3_model_t *mdl) | |
{ | |
FILE *fp; | |
int i; | |
fp = fopen (filename, "rb"); | |
if (!fp) | |
{ | |
fprintf (stderr, "Error: couldn't open \"%s\"!\n", filename); | |
return 0; | |
} | |
/* Read header */ | |
fread (&mdl->header, 1, sizeof (struct md3_header_t), fp); | |
if ((mdl->header.ident != 860898377) || | |
(mdl->header.version != 15)) | |
{ | |
/* Error! */ | |
fprintf (stderr, "Error: bad version or identifier\n"); | |
fclose (fp); | |
return 0; | |
} | |
/* Memory allocations */ | |
mdl->frames = (struct md3_frame_t *) | |
malloc (sizeof (struct md3_frame_t) * mdl->header.num_frames); | |
mdl->tags = (struct md3_tag_t *) | |
malloc (sizeof (struct md3_tag_t) * mdl->header.num_tags * mdl->header.num_frames); | |
mdl->meshes = (struct md3_mesh_t *) | |
malloc (sizeof (struct md3_mesh_t) * mdl->header.num_meshes); | |
/* Read model data */ | |
fseek (fp, mdl->header.offset_frames, SEEK_SET); | |
fread (mdl->frames, sizeof (struct md3_frame_t), | |
mdl->header.num_frames, fp); | |
fseek (fp, mdl->header.offset_tag, SEEK_SET); | |
fread (mdl->tags, sizeof (struct md3_tag_t), | |
mdl->header.num_tags * mdl->header.num_frames, fp); | |
fseek (fp, mdl->header.offset_meshes, SEEK_SET); | |
for (i = 0; i < mdl->header.num_meshes; i++) | |
if (!ReadMd3Mesh (fp, &mdl->meshes[i])) | |
{ | |
/* Error when reading mesh! */ | |
fclose (fp); | |
return 0; | |
} | |
fclose (fp); | |
return 1; | |
} | |
/** | |
* Free resources allocated for the mesh. | |
*/ | |
void | |
FreeMesh (struct md3_mesh_t *mesh) | |
{ | |
if (mesh) | |
{ | |
if (mesh->shaders) | |
free (mesh->shaders); | |
if (mesh->triangles) | |
free (mesh->triangles); | |
if (mesh->texcoords) | |
free (mesh->texcoords); | |
if (mesh->vertices) | |
free (mesh->vertices); | |
} | |
} | |
/** | |
* Free resources allocated for the model. | |
*/ | |
void | |
FreeModel (struct md3_model_t *mdl) | |
{ | |
int i; | |
if (mdl->frames) | |
{ | |
free (mdl->frames); | |
mdl->frames = NULL; | |
} | |
if (mdl->tags) | |
{ | |
free (mdl->tags); | |
mdl->tags = NULL; | |
} | |
if (mdl->meshes) | |
{ | |
for (i = 0; i < mdl->header.num_meshes; i++) | |
FreeMesh (&mdl->meshes[i]); | |
free (mdl->meshes); | |
mdl->meshes = NULL; | |
} | |
if (glIsBufferARB (mdl->vbo)) | |
glDeleteBuffersARB (1, &mdl->vbo); | |
if (glIsBufferARB (mdl->ibo)) | |
glDeleteBuffersARB (1, &mdl->ibo); | |
} | |
/** | |
* Initialize Vertex and Index Buffer Objects for the model. | |
*/ | |
void | |
InitModel (struct md3_model_t *mdl) | |
{ | |
int i, j, k; | |
int num_verts = 0; | |
int num_indices = 0; | |
int ibo_start = 0; | |
int vbo_start = 0; | |
int num_mesh_indices; | |
int num_mesh_vertices; | |
GLuint *indexBuffer, *indices; | |
for (i = 0; i < mdl->header.num_meshes; i++) | |
{ | |
num_verts += mdl->meshes[i].header.num_verts; | |
num_indices += mdl->meshes[i].header.num_triangles * 3; | |
} | |
/* Index buffer for indices of all model's meshes */ | |
indexBuffer = (GLuint *)malloc (sizeof (GLuint) * num_indices); | |
indices = indexBuffer; | |
/* Prepare indices for each mesh, and setup VBO related stuff */ | |
for (i = 0; i < mdl->header.num_meshes; i++) | |
{ | |
num_mesh_indices = mdl->meshes[i].header.num_triangles * 3; | |
num_mesh_vertices = mdl->meshes[i].header.num_verts; | |
mdl->meshes[i].start = vbo_start; | |
mdl->meshes[i].end = vbo_start + num_mesh_vertices - 1; | |
mdl->meshes[i].count = num_mesh_indices; | |
mdl->meshes[i].offset = ibo_start * sizeof (GLuint); | |
for (j = 0; j < mdl->meshes[i].header.num_triangles; j++) | |
for (k = 2; k >= 0; k--) | |
*indices++ = vbo_start + mdl->meshes[i].triangles[j].index[k]; | |
ibo_start += num_mesh_indices; | |
vbo_start += num_mesh_vertices; | |
} | |
glGenBuffersARB (1, &mdl->ibo); | |
glGenBuffersARB (1, &mdl->vbo); | |
/* Alloc the index buffer and fill it with data */ | |
glBindBufferARB (GL_ELEMENT_ARRAY_BUFFER_ARB, mdl->ibo); | |
glBufferDataARB (GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof (GLuint) * num_indices, | |
indexBuffer, GL_STATIC_DRAW_ARB); | |
glBindBufferARB (GL_ELEMENT_ARRAY_BUFFER_ARB, 0); | |
/* Just allocate memory for vertices */ | |
glBindBufferARB (GL_ARRAY_BUFFER_ARB, mdl->vbo); | |
glBufferDataARB (GL_ARRAY_BUFFER_ARB, sizeof (struct Vertex_VNT) * num_verts, | |
NULL, GL_STREAM_DRAW_ARB); | |
glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); | |
free (indexBuffer); | |
} | |
/** | |
* Prepare model's VBO with mesh's vertices for a given frame. | |
*/ | |
int | |
PrepareMeshFrame (int n, struct Vertex_VNT *verts, | |
const struct md3_mesh_t * const mesh) | |
{ | |
const struct md3_vertex_t *vert; | |
const struct md3_texCoord_t *texcoords; | |
float scale_and_uncompress; | |
unsigned char un, vn; | |
int frameOffset; | |
int i; | |
scale_and_uncompress = 1.0f / 64.0f; | |
frameOffset = n * mesh->header.num_verts; | |
for (i = 0; i < mesh->header.num_verts; i++) | |
{ | |
vert = &mesh->vertices[frameOffset + i]; | |
texcoords = &mesh->texcoords[i]; | |
verts[i].xyz[0] = vert->v[0] * scale_and_uncompress; | |
verts[i].xyz[1] = vert->v[1] * scale_and_uncompress; | |
verts[i].xyz[2] = vert->v[2] * scale_and_uncompress; | |
un = vert->normal[0]; | |
vn = vert->normal[1]; | |
verts[i].norm[0] = anorms_table[un][vn][0]; | |
verts[i].norm[1] = anorms_table[un][vn][1]; | |
verts[i].norm[2] = anorms_table[un][vn][2]; | |
verts[i].st[0] = texcoords->s; | |
verts[i].st[1] = texcoords->t; | |
} | |
return i; | |
} | |
/** | |
* Prepare model's VBO for a given frame. | |
*/ | |
void | |
PrepareModelFrame (int n, const struct md3_model_t * const mdl) | |
{ | |
struct Vertex_VNT *verts; | |
int offset, i; | |
/* Check if n is in a valid range */ | |
if ((n < 0) || (n >= mdl->header.num_frames)) | |
return; | |
glBindBufferARB (GL_ARRAY_BUFFER_ARB, mdl->vbo); | |
verts = (struct Vertex_VNT *) | |
glMapBufferARB (GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); | |
for (i = 0, offset = 0; i < mdl->header.num_meshes; i++) | |
offset += PrepareMeshFrame (n, &verts[offset], &mdl->meshes[i]); | |
glUnmapBufferARB (GL_ARRAY_BUFFER_ARB); | |
glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); | |
} | |
/** | |
* Prepare VBO for this mesh with interpolated frames. | |
* 'verts' is a pointer to the VBO data. | |
*/ | |
int | |
PrepareMeshFrameItp (int curr, int next, float interp, | |
struct Vertex_VNT *verts, | |
const struct md3_mesh_t * const mesh) | |
{ | |
const struct md3_vertex_t *v_curr, *v_next; | |
const struct md3_texCoord_t *texcoords; | |
int currFrameOffset, nextFrameOffset; | |
float scale_and_uncompress; | |
unsigned char uA, vA, uB, vB; | |
float *normA, *normB; | |
int i; | |
scale_and_uncompress = 1.0f / 64.0f; | |
currFrameOffset = curr * mesh->header.num_verts; | |
nextFrameOffset = next * mesh->header.num_verts; | |
for (i = 0; i < mesh->header.num_verts; i++) | |
{ | |
v_curr = &mesh->vertices[currFrameOffset + i]; | |
v_next = &mesh->vertices[nextFrameOffset + i]; | |
texcoords = &mesh->texcoords[i]; | |
/* Interpolate vertices */ | |
verts[i].xyz[0] = (v_curr->v[0] + interp * (v_next->v[0] - v_curr->v[0])) * scale_and_uncompress; | |
verts[i].xyz[1] = (v_curr->v[1] + interp * (v_next->v[1] - v_curr->v[1])) * scale_and_uncompress; | |
verts[i].xyz[2] = (v_curr->v[2] + interp * (v_next->v[2] - v_curr->v[2])) * scale_and_uncompress; | |
/* Interpolate normals */ | |
uA = v_curr->normal[0]; | |
vA = v_curr->normal[1]; | |
uB = v_next->normal[0]; | |
vB = v_next->normal[1]; | |
normA = (float *)&anorms_table[uA][vA]; | |
normB = (float *)&anorms_table[uB][vB]; | |
verts[i].norm[0] = normA[0] + interp * (normB[0] - normA[0]); | |
verts[i].norm[1] = normA[1] + interp * (normB[1] - normA[1]); | |
verts[i].norm[2] = normA[2] + interp * (normB[2] - normA[2]); | |
/* Copy texture coordinates */ | |
verts[i].st[0] = texcoords->s; | |
verts[i].st[1] = texcoords->t; | |
} | |
return i; | |
} | |
/** | |
* Prepare VBO for this model with interpolated frames. | |
*/ | |
void | |
PrepareModelFrameItp (int curr, int next, float interp, | |
const struct md3_model_t * const mdl) | |
{ | |
struct Vertex_VNT *verts; | |
int offset, i; | |
/* Check if frames are in a valid range */ | |
if ((curr < 0) || (curr >= mdl->header.num_frames)) | |
return; | |
if ((next < 0) || (next >= mdl->header.num_frames)) | |
return; | |
glBindBufferARB (GL_ARRAY_BUFFER_ARB, mdl->vbo); | |
verts = (struct Vertex_VNT *) | |
glMapBufferARB (GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); | |
for (i = 0, offset = 0; i < mdl->header.num_meshes; i++) | |
offset += PrepareMeshFrameItp (curr, next, interp, | |
&verts[offset], &mdl->meshes[i]); | |
glUnmapBufferARB (GL_ARRAY_BUFFER_ARB); | |
glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); | |
} | |
/** | |
* Render the mesh using VBO. The mesh data is a portion of model's VBO. | |
*/ | |
void | |
RenderMesh (const struct md3_mesh_t * const mesh) | |
{ | |
glDrawRangeElements (GL_TRIANGLES, mesh->start, mesh->end, | |
mesh->count, GL_UNSIGNED_INT, | |
BUFFER_OFFSET(mesh->offset)); | |
} | |
/** | |
* Render the model using VBO. | |
*/ | |
void | |
RenderModel (const struct md3_model_t * const mdl) | |
{ | |
int i; | |
glEnableClientState (GL_VERTEX_ARRAY); | |
glEnableClientState (GL_NORMAL_ARRAY); | |
glEnableClientState (GL_TEXTURE_COORD_ARRAY); | |
glBindBufferARB (GL_ELEMENT_ARRAY_BUFFER_ARB, mdl->ibo); | |
glBindBufferARB (GL_ARRAY_BUFFER, mdl->vbo); | |
glNormalPointer (GL_FLOAT, sizeof (struct Vertex_VNT), BUFFER_OFFSET(sizeof (GLfloat) * 3)); | |
glTexCoordPointer (2, GL_FLOAT, sizeof (struct Vertex_VNT), BUFFER_OFFSET(sizeof (GLfloat) * 6)); | |
glVertexPointer (3, GL_FLOAT, sizeof (struct Vertex_VNT), BUFFER_OFFSET(0)); | |
for (i = 0; i < mdl->header.num_meshes; i++) | |
RenderMesh (&mdl->meshes[i]); | |
glBindBufferARB (GL_ELEMENT_ARRAY_BUFFER_ARB, 0); | |
glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); | |
glDisableClientState (GL_VERTEX_ARRAY); | |
glDisableClientState (GL_NORMAL_ARRAY); | |
glDisableClientState (GL_TEXTURE_COORD_ARRAY); | |
} | |
/** | |
* Calculate the current frame in animation beginning at frame | |
* 'start' and ending at frame 'end', given interpolation percent. | |
* interp will be reseted to 0.0 if the next frame is reached. | |
*/ | |
void | |
Animate (int start, int end, int *frame, float *interp) | |
{ | |
if ((*frame < start) || (*frame > end)) | |
*frame = start; | |
if (*interp >= 1.0f) | |
{ | |
/* Move to next frame */ | |
*interp = 0.0f; | |
(*frame)++; | |
if (*frame >= end) | |
*frame = start; | |
} | |
} | |
void | |
init (const char *filename) | |
{ | |
GLfloat lightpos[] = { 5.0f, 10.0f, 0.0f, 1.0f }; | |
GLenum err = glewInit (); | |
if (GLEW_OK != err) | |
{ | |
/* Problem: glewInit failed, something is seriously wrong. */ | |
fprintf (stderr, "Error: %s\n", glewGetErrorString (err)); | |
exit (EXIT_FAILURE); | |
} | |
if (!GLEW_ARB_vertex_buffer_object) | |
{ | |
fprintf (stderr, "Error: missing ARB_vertex_buffer_object extension\n"); | |
exit (EXIT_FAILURE); | |
} | |
/* Initialize OpenGL context */ | |
glClearColor (0.5f, 0.5f, 0.5f, 1.0f); | |
glShadeModel (GL_SMOOTH); | |
glEnable (GL_CULL_FACE); | |
glEnable (GL_DEPTH_TEST); | |
glEnable (GL_LIGHTING); | |
glEnable (GL_LIGHT0); | |
glLightfv (GL_LIGHT0, GL_POSITION, lightpos); | |
BuildNormalLookupTable (); | |
/* Load MD3 model file */ | |
if (!ReadMD3Model (filename, &md3file)) | |
exit (EXIT_FAILURE); | |
InitModel (&md3file); | |
err = glGetError (); | |
if (err != GL_NO_ERROR) | |
fprintf (stderr, "OpenGL Error: %s\n", gluErrorString (err)); | |
} | |
void | |
cleanup () | |
{ | |
FreeModel (&md3file); | |
} | |
void | |
reshape (int w, int h) | |
{ | |
if (h == 0) | |
h = 1; | |
glViewport (0, 0, (GLsizei)w, (GLsizei)h); | |
glMatrixMode (GL_PROJECTION); | |
glLoadIdentity (); | |
gluPerspective (45.0, w/(GLdouble)h, 0.1, 1000.0); | |
glMatrixMode (GL_MODELVIEW); | |
glLoadIdentity (); | |
} | |
void | |
display () | |
{ | |
static int n = 0; /* The current frame */ | |
static float interp = 0.0; | |
static double curent_time = 0; | |
static double last_time = 0; | |
int curr, next; | |
GLenum err; | |
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
glLoadIdentity (); | |
last_time = curent_time; | |
curent_time = (double)glutGet (GLUT_ELAPSED_TIME) / 1000.0; | |
/* Animate model from frames 0 to num_frames-1 */ | |
interp += 15 * (curent_time - last_time); | |
Animate (0, md3file.header.num_frames - 1, &n, &interp); | |
curr = n; | |
next = (n + 1) % md3file.header.num_frames; | |
glTranslatef (0.0f, 0.0f, -75.0f); | |
glRotatef (-90.0f, 1.0, 0.0, 0.0); | |
glRotatef (-90.0f, 0.0, 0.0, 1.0); | |
/* Prepare model's vertices */ | |
if (md3file.header.num_frames > 1) | |
PrepareModelFrameItp (curr, next, interp, &md3file); | |
else | |
PrepareModelFrame (n, &md3file); | |
/* Draw the model */ | |
RenderModel (&md3file); | |
err = glGetError (); | |
if (err != GL_NO_ERROR) | |
fprintf (stderr, "OpenGL Error: %s\n", gluErrorString (err)); | |
glutSwapBuffers (); | |
glutPostRedisplay (); | |
} | |
void | |
keyboard (unsigned char key, int x, int y) | |
{ | |
/* Escape */ | |
if (key == 27) | |
exit (0); | |
} | |
int | |
main (int argc, char *argv[]) | |
{ | |
if (argc < 2) | |
{ | |
fprintf (stderr, "usage: %s <filename.md3>\n", argv[0]); | |
return -1; | |
} | |
glutInit (&argc, argv); | |
glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); | |
glutInitWindowSize (640, 480); | |
glutCreateWindow ("MD3 Model (with VBO)"); | |
atexit (cleanup); | |
init (argv[1]); | |
glutReshapeFunc (reshape); | |
glutDisplayFunc (display); | |
glutKeyboardFunc (keyboard); | |
glutMainLoop (); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment