Animating MD2 - Quake 2 File Format
Author bkenwright@xbdev.net
For some people who are new to the principle of animation and key frames I'll have to just outline the very basics of how it all works, then you can expand on this and learn more.
The animations (frames) can be interpolated using the standard linear interpolation equation: p(t) = p(0) + t( p1 - p0 ).
• t - The current time with 0 being the start and 1 being the end.
• p(t) - The result of the equation with time t.
• p0 - The starting position.
• p1 - The ending position.
Now I want you to write this out on a piece of paper a 100 times... until you know it like the back on your hand, as this is how nearly all animating is done in games... there are a couple of fancier methods but they are very similar in principle to the above one.
/***************************************************************************/
/* */
/* File: md2_v1.cpp */
/* Author: bkenwright@xbdev.net */
/* Date: 10-11-2002 */
/* */
/***************************************************************************/
#include <windows.h>
#include <stdio.h>
void abc(char *str)
{
FILE *fp = fopen("output.txt", "a+");
fprintf(fp, "%s\n", str);
fclose(fp);
}
char buff[500];
struct stMd2Header
{
int magic; // The magic number used to identify the file.
int version; // The file version number (must be 8).
int skinWidth; // The width in pixels of our image.
int skinHeight; // The height in pixels of our image.
int frameSize; // The size in bytes the frames are.
int numSkins; // The number of skins associated with the model.
int numVertices; // The number of vertices.
int numTexCoords; // The number of texture coordinates.
int numTriangles; // The number of faces (polygons).
int numGlCommands; // The number of gl commands.
int numFrames; // The number of animated frames.
int offsetSkins; // The offset in the file for the skin data.
int offsetTexCoords;// The offset in the file for the texture data.
int offsetTriangles;// The offset in the file for the face data.
int offsetFrames; // The offset in the file for the frames data.
int offsetGlCommands;// The offset in the file for the gl commands data.
int offsetEnd; // The end of the file offset.
};
stMd2Header Md2Header;
// Some structures to hold or read in data in.
struct stSkins
{
char skinName[64];
};
struct stTexCoords
{
short u, v;
};
struct stTriangles
{
float vertex[3];
float normal[3];
};
struct stVerts
{
byte vertex[3]; // an index reference into the location of our vertexs
byte lightNormalIndex; // in index into which tex coords to use.
};
struct stFrames
{
float scale[3];
float translate[3];
char strFrameName[16];
stVerts *pVerts;
};
int _stdcall WinMain(HINSTANCE hinstance, HINSTANCE n, char *k, int l)
{
FILE *f = fopen("pac3D.md2", "rb");
fread(&Md2Header, 1, sizeof(Md2Header), f);
// Allocate memory for our data so we can read it in.
stSkins* pSkins = new stSkins[ Md2Header.numSkins ];
stTexCoords* pTexCoords = new stTexCoords[ Md2Header.numTexCoords ];
stTriangles* pTriangles = new stTriangles[ Md2Header.numTriangles ];
stFrames* pFrames = new stFrames[ Md2Header.numFrames ];
// -1- Seek to the start of our skins name data and read it in.
fseek(f, Md2Header.offsetSkins, SEEK_SET);
fread(pSkins, sizeof(stSkins), Md2Header.numSkins, f);
// -2- Seek to the start of our Texture Coord data and read it in.
fseek(f, Md2Header.offsetTexCoords, SEEK_SET);
fread(pTexCoords, sizeof(stTexCoords), Md2Header.numTexCoords, f);
// -3- Seek to the start of the Triangle(e.g. Faces) data and read that in.
fseek(f, Md2Header.offsetTriangles, SEEK_SET);
fread(pTriangles, sizeof(stTriangles), Md2Header.numTriangles, f);
// -4- Finally lets read in "one" of the frames, the first one.!
fseek(f, Md2Header.offsetFrames, SEEK_SET);
pFrames[0].pVerts = new stVerts[ Md2Header.numVertices ];
fread(pFrames, 1, Md2Header.frameSize, f);
// CONVERSION! A few things before we can use our read in values,
// for some reason the Z and Y need to be swapped, as Z is facing up
// and Y is facing into the screen.
// Also our texture coordinates values are between 0 and 256, we just
// divide them all by 256 which makes them between 0 and 1.
// Swap Z<->Y
for(int i=0; i< Md2Header.numVertices; i++)
{
stVerts tempVert;
tempVert.vertex[1] = pFrames[0].pVerts[i].vertex[1]; // y
tempVert.vertex[2] = pFrames[0].pVerts[i].vertex[2]; // z
pFrames[0].pVerts[i].vertex[1] = tempVert.vertex[2]; // z->y
pFrames[0].pVerts[i].vertex[2] = tempVert.vertex[1]; // y->z
}
// Scale Textures.
for (int j=0; j< Md2Header.numTexCoords; j++)
{
pTexCoords[j].u = pTexCoords[j].u / float(Md2Header.skinWidth);
pTexCoords[j].v = pTexCoords[j].v / float(Md2Header.skinHeight);
}
// Now --Here-- is where we have all our data...if we wanted to could
// convert of draw it here or something... but since we only wanted
// to see how its extracted, we just clean up after ourselfs and exit.
// Tidy up before exiting.
delete[] pFrames[0].pVerts;
delete[] pSkins;
delete[] pTexCoords;
delete[] pTriangles;
delete[] pFrames;
fclose(f);
return 1;
}
/***************************************************************************/
/* */
/* Well at first it may look like a lot of code above, but in fact its */
/* really simple once yo7u've gone over it once or twice, all it has done */
/* is read in the main parts of the file... so that you have in essence, */
/* extracted the 3D data which you can use to render you 3D model... */
/* Only a single frame has been extracted, but we'll get to animation later*/
/* */
/***************************************************************************/
The following shows the output dump for the key information from the MD2 file.
<?php
num keys: 16
start:0 end:39 name:stand
start:40 end:45 name:run
start:46 end:53 name:attack
start:54 end:65 name:pain
start:66 end:71 name:jump
start:72 end:83 name:flip
start:84 end:94 name:salute
start:95 end:111 name:taunt
start:112 end:122 name:wave
start:123 end:134 name:point
start:135 end:153 name:crstnd
start:154 end:159 name:crwalk
start:160 end:168 name:crattack
start:169 end:172 name:crpain
start:173 end:177 name:crdeath
start:178 end:197 name:death</p>
stand01
stand02
stand03
stand04
stand05
stand06
stand07
stand08
stand09
stand10
stand11
stand12
stand13
stand14
stand15
stand16
stand17
stand18
stand19
stand20
stand21
stand22
stand23
stand24
stand25
stand26
stand27
stand28
stand29
stand30
stand31
stand32
stand33
stand34
stand35
stand36
stand37
stand38
stand39
stand40
run1
run2
run3
run4
run5
run6
attack1
attack2
attack3
attack4
attack5
attack6
attack7
attack8
pain101
pain102
pain103
pain104
pain204
pain203
pain202
pain201
pain301
pain302
pain303
pain304
jump1
jump2
jump3
jump4
jump5
jump6
flip01
flip02
flip03
flip04
flip05
flip06
flip07
flip08
flip09
flip10
flip11
flip12
salute01
salute02
salute03
salute04
salute05
salute06
salute07
salute08
salute09
salute10
salute11
taunt01
taunt02
taunt03
taunt04
taunt05
taunt06
taunt07
taunt08
taunt09
taunt10
taunt11
taunt12
taunt13
taunt14
taunt15
taunt16
taunt17
wave01
wave03
wave04
wave05
wave06
wave07
wave08
wave09
wave10
wave11
wave12
point01
point02
point03
point04
point05
point06
point07
point08
point09
point10
point11
point12
crstnd01
crstnd02
crstnd03
crstnd04
crstnd05
crstnd06
crstnd07
crstnd08
crstnd09
crstnd10
crstnd11
crstnd12
crstnd13
crstnd14
crstnd15
crstnd16
crstnd17
crstnd18
crstnd19
crwalk1
crwalk2
crwalk3
crwalk4
crwalk5
crwalk6
crattack1
crattack2
crattack3
crattack4
crattack5
crattack6
crattack7
crattack8
crattack9
crpain1
crpain2
crpain3
crpain4
crdeath2
crdeath2
crdeath3
crdeath4
crdeath5
death11
death12
death13
death14
death15
death16
death21
death22
death23
death24
death25
death26
death31
death32
death33
death34
death35
death36
death37
death38
|