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.
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
|