MD2.H&&MD2.CPP

///////////////////////////////////////MD2.H//////////////////////////////////////////////////
#ifndef _MD2_H 
#define _MD2_H 
 
// These are the needed defines for the max values when loading .MD2 files 
#define MD2_MAX_TRIANGLES        4096 
#define MD2_MAX_VERTICES        2048 
#define MD2_MAX_TEXCOORDS        2048 
#define MD2_MAX_FRAMES            512 
#define MD2_MAX_SKINS            32 
#define MD2_MAX_FRAMESIZE        (MD2_MAX_VERTICES * 4 + 128) 
 
// This holds the header information that is read in at the beginning of the file 
struct tMd2Header 
{  
   int magic;                    // This is used to identify the file 
   int version;                    // The version number of the file (Must be 8) 
   int skinWidth;                // The skin width in pixels 
   int skinHeight;                // The skin height in pixels 
   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 (constant for each frame) 
   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 animation 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 
}; 
 
 
//用来存储当前帧所读进来的顶点
struct tMd2AliasTriangle 
{ 
   byte vertex[3]; 
   byte lightNormalIndex; 
}; 
 
//这个存储帧的法线和顶点
struct tMd2Triangle 
{ 
   float vertex[3]; 
   float normal[3]; 
}; 
 
// 这个存储索引到顶点和纹理坐标数组
struct tMd2Face 
{ 
   short vertexIndices[3]; 
   short textureIndices[3]; 
}; 
 
// 此存储UV坐标
struct tMd2TexCoord 
{ 
   short u, v; 
}; 
 
// This stores the animation scale, translation and name information for a frame, plus verts 
struct tMd2AliasFrame 
{ 
   float scale[3]; 
   float translate[3]; 
   char name[16]; 
   tMd2AliasTriangle aliasVertices[1]; 
}; 
 
// This stores the frames vertices after they have been transformed 
struct tMd2Frame 
{ 
   char strName[16]; 
   tMd2Triangle *pVertices; 
}; 
 
// This stores a skin name 
typedef char tMd2Skin[64]; 
 
 
// This class handles all of the loading code 
class CLoadMD2 
{ 
 
public: 
    CLoadMD2();                                // This inits the data members 
 
    // This is the function that you call to load the MD2 
    bool ImportMD2(t3DModel *pModel, char *strFileName, char *strTexture); 
 
private: 
     
    // This reads in the data from the MD2 file and stores it in the member variables 
    void ReadMD2Data(); 
 
    // This converts the member variables to our pModel structure 
    void ConvertDataStructures(t3DModel *pModel); 
 
    // This computes the vertex normals for the object (used for lighting) 
    void ComputeNormals(t3DModel *pModel); 
 
    // This frees memory and closes the file 
    void CleanUp(); 
     
    // The file pointer 
    FILE *m_FilePointer; 
 
    // Member variables         
 
    tMd2Header                m_Header;            // The header data 
    tMd2Skin                *m_pSkins;            // The skin data 
    tMd2TexCoord            *m_pTexCoords;        // The texture coordinates 
    tMd2Face                *m_pTriangles;        // Face index information 
    tMd2Frame                *m_pFrames;            // The frames of animation (vertices) 
}; 
 
 
#endif 
 
 
///////////////////////////////////////////////////////////////////////////////// 
// 
// * QUICK NOTES *  
//  
// This file holds all of the structure and class definitions needed to load 
// a MD2 Quake2 file. 
// 
//  
// Ben Humphrey (DigiBen) 
// Game Programmer 
// DigiBen@GameTutorials.com 
// Co-Web Host of www.GameTutorials.com 
// 
// The Quake2 .Md2 file format is owned by ID Software.  This tutorial is being used  
// as a teaching tool to help understand model loading and animation.  This should 
// not be sold or used under any way for commercial use with out written conset 
// from ID Software. 
// 
// Quake and Quake2 are trademarks of id Software. 
// All trademarks used are properties of their respective owners.  
// 
//  
 
 
 
 ///////////////////////////////////////MD2.CPP//////////////////////////////////////////////////
 //***********************************************************************//   
//                                                                       //   
//      - "Talk to me like I'm a 3 year old!" Programming Lessons -      //   
//                                                                       //   
//      $Author:        DigiBen     digiben@gametutorials.com            //   
//                                                                       //   
//      $Program:       MD2 Loader                                       //   
//                                                                       //   
//      $Description:   Demonstrates how to load a Quake2 MD2 Model      //   
//                                                                       //   
//      $Date:          2/6/02                                           //   
//                                                                       //   
//***********************************************************************//   
   
   
#include "main.h"   
#include "Md2.h"   
   
   
/////////////////////////////////////////////////////////////////////////   
//   
// This file holds the code to load the Quake2 models from a .Md2 format.   
// The .Md2 file is usually stored in a .zip file (don't let the extension   
// fool you, just rename it to .zip), depending on where you get the models   
// from.  The CLoadMD2 class handles the loading, but we draw the model   
// externally on our own in main.cpp.  I created a converter function   
// to convert to our already used model and object structures.  This way   
// eventually we can create a model library that can load any type of   
// model that we support, as well as use inheritance to create a new class   
// for each file format for the small things that each model format needs differently.   
// Like the other loading tutorials, we calculate our own vertex normals.   
// The .Md2 format is REALLY simple to load.  That is why I chose it.  The   
// next tutorial will show how to load and animate Md2 files.  Next, we   
// will move from key frame animation to skeletal animation with the Quake3   
// .Md3 files.  This is also a wonderfuly easy format to load and use.   
//   
//   
   
   
///////////////////////////////// CLOAD MD2 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
/////   
/////   This constructor initializes the md2 structures   
/////   
///////////////////////////////// CLOAD MD2 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
   
CLoadMD2::CLoadMD2()   
{   
    // Here we initialize our structures to 0   
    memset(&m_Header, 0, sizeof(tMd2Header));   
   
    // Set the pointers to null   
    m_pSkins=NULL;   
    m_pTexCoords=NULL;   
    m_pTriangles=NULL;   
    m_pFrames=NULL;   
}   
   
   
///////////////////////////////// IMPORT MD2 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
/////   
/////   This is called by the client to open the .Md2 file, read it, then clean up   
/////   
///////////////////////////////// IMPORT MD2 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
   
bool CLoadMD2::ImportMD2(t3DModel *pModel, char *strFileName, char *strTexture)   
{   
    char strMessage[255] = {0};   
   
    // Open the MD2 file in binary   
    m_FilePointer = fopen(strFileName, "rb");   
   
    // Make sure we have a valid file pointer (we found the file)   
    if(!m_FilePointer)    
    {   
        // Display an error message and don't load anything if no file was found   
        sprintf(strMessage, "Unable to find the file: %s!", strFileName);   
        MessageBox(NULL, strMessage, "Error", MB_OK);   
        return false;   
    }   
       
    // Just like most file formats, there is a header that needs to be read   
    // from the .Md2 format.  If you look at the tMd2Header structure you will   
    // find all the data that will be read in.  It's nice to know up front about   
    // the data that we will be reading.  This makes it easy to just to large   
    // binary reads using fread, instead of counting and reading chunks.   
   
    // Read the header data and store it in our m_Header member variable   
    fread(&m_Header, 1, sizeof(tMd2Header), m_FilePointer);   
   
    // For some reason, .Md2 files MUST have a version of 8.  I am not sure why,   
    // but if it doesn't there is something wrong and the header was read in   
    // incorrectly, or perhaps the file format is bad.   
    if(m_Header.version != 8)   
    {   
        // Display an error message for bad file format, then stop loading   
        sprintf(strMessage, "Invalid file format (Version not 8): %s!", strFileName);   
        MessageBox(NULL, strMessage, "Error", MB_OK);   
        return false;   
    }   
   
    // Now that we made sure the header had correct data, we want to read in the   
    // rest of the data.  Once the data is read in, we need to convert it to our structures.   
    // Since we are only reading in the first frame of animation, there will only   
    // be ONE object in our t3DObject structure, held within our pModel variable.   
    ReadMD2Data();   
       
    // Here we pass in our model structure to it can store the read Quake data   
    // in our own model and object structure data   
    ConvertDataStructures(pModel);   
   
    // After we have read the whole MD2 file, we want to calculate our own vertex normals.   
    ComputeNormals(pModel);   
   
    // If there is a valid texture name passed in, we want to set the texture data   
    if(strTexture)   
    {   
        // Create a local material info structure   
        tMaterialInfo texture;   
   
        // Copy the name of the file into our texture file name variable   
        strcpy(texture.strFile, strTexture);   
   
        // Since there is only one texture for a .Md2 file, the ID is always 0   
        texture.texureId = 0;   
   
        // The tile or scale for the UV's is 1 to 1 (but Quake saves off a 0-256 ratio)   
        texture.uTile = texture.uTile = 1;   
   
        // We only have 1 material for a model   
        pModel->numOfMaterials = 1;   
   
        // Add the local material info to our model's material list   
        pModel->pMaterials.push_back(texture);   
    }   
   
    // Clean up after everything   
    CleanUp();   
   
    // Return a success   
    return true;   
}   
   
   
///////////////////////////////// READ MD2 DATA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
/////   
/////   This function reads in all of the model's data, except the animation frames   
/////   
///////////////////////////////// READ MD2 DATA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
   
void CLoadMD2::ReadMD2Data()   
{   
    // Create a larger buffer for the frames of animation (not fully used yet)   
    unsigned char buffer[MD2_MAX_FRAMESIZE];   
    int j = 0;   
   
    // Here we allocate all of our memory from the header's information   
    m_pSkins     = new tMd2Skin [m_Header.numSkins];   
    m_pTexCoords = new tMd2TexCoord [m_Header.numTexCoords];   
    m_pTriangles = new tMd2Face [m_Header.numTriangles];   
    m_pFrames    = new tMd2Frame [m_Header.numFrames];   
   
    // Next, we start reading in the data by seeking to our skin names offset   
    fseek(m_FilePointer, m_Header.offsetSkins, SEEK_SET);   
       
    // Depending on the skin count, we read in each skin for this model   
    fread(m_pSkins, sizeof(tMd2Skin), m_Header.numSkins, m_FilePointer);   
       
    // Move the file pointer to the position in the file for texture coordinates   
    fseek(m_FilePointer, m_Header.offsetTexCoords, SEEK_SET);   
       
    // Read in all the texture coordinates in one fell swoop   
    fread(m_pTexCoords, sizeof(tMd2TexCoord), m_Header.numTexCoords, m_FilePointer);   
   
    // Move the file pointer to the triangles/face data offset   
    fseek(m_FilePointer, m_Header.offsetTriangles, SEEK_SET);   
       
    // Read in the face data for each triangle (vertex and texCoord indices)   
    fread(m_pTriangles, sizeof(tMd2Face), m_Header.numTriangles, m_FilePointer);   
               
    // Move the file pointer to the vertices (frames)   
    fseek(m_FilePointer, m_Header.offsetFrames, SEEK_SET);   
   
    // Assign our alias frame to our buffer memory   
    tMd2AliasFrame *pFrame = (tMd2AliasFrame *) buffer;   
   
    // Allocate the memory for the first frame of animation's vertices   
    m_pFrames[0].pVertices = new tMd2Triangle [m_Header.numVertices];   
   
    // Read in the first frame of animation   
    fread(pFrame, 1, m_Header.frameSize, m_FilePointer);   
   
    // Copy the name of the animation to our frames array   
    strcpy(m_pFrames[0].strName, pFrame->name);   
               
    // After we have read in the data for the model, since there is animation,   
    // This means that there are scale and translation values to be dealt with.   
    // To apply the scale and translation values, we simply multiply the scale (x, y, z)   
    // by the current vertex (x, y, z).  Also notice that we switch the Y and Z values   
    // so that Y is faces up, NOT Z.   
       
    // Store off a vertex array pointer to cut down large lines of code   
    tMd2Triangle *pVertices = m_pFrames[0].pVertices;   
   
    // Go through all of the number of vertices and assign the scale and translations.   
    // Store the vertices in our current frame's vertex list array, while swapping Y and Z.   
    // Notice we also negate the Z axis as well to make the swap correctly.   
    for (j=0; j < m_Header.numVertices; j++)   
    {   
        pVertices[j].vertex[0] = pFrame->aliasVertices[j].vertex[0] * pFrame->scale[0] + pFrame->translate[0];   
        pVertices[j].vertex[2] = -1 * (pFrame->aliasVertices[j].vertex[1] * pFrame->scale[1] + pFrame->translate[1]);   
        pVertices[j].vertex[1] = pFrame->aliasVertices[j].vertex[2] * pFrame->scale[2] + pFrame->translate[2];   
    }   
}   
   
   
///////////////////////////////// CONVERT DATA STRUCTURES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
/////   
/////   This function converts the .md2 structures to our own model and object structures   
/////   
///////////////////////////////// CONVERT DATA STRUCTURES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
   
void CLoadMD2::ConvertDataStructures(t3DModel *pModel)   
{   
    int j = 0, i = 0;   
       
    // Assign the number of objects, which is 1 since we only want 1 frame   
    // of animation.  In the next tutorial each object will be a key frame   
    // to interpolate between.   
    pModel->numOfObjects = 1;   
   
    // Create a local object to store the first frame of animation's data   
    t3DObject currentFrame = {0};   
   
    // Assign the vertex, texture coord and face count to our new structure   
    currentFrame.numOfVerts   = m_Header.numVertices;   
    currentFrame.numTexVertex = m_Header.numTexCoords;   
    currentFrame.numOfFaces   = m_Header.numTriangles;   
   
    // Allocate memory for the vertices, texture coordinates and face data.   
    currentFrame.pVerts    = new CVector3 [currentFrame.numOfVerts];   
    currentFrame.pTexVerts = new CVector2 [currentFrame.numTexVertex];   
    currentFrame.pFaces    = new tFace [currentFrame.numOfFaces];   
   
    // Go through all of the vertices and assign them over to our structure   
    for (j=0; j < currentFrame.numOfVerts; j++)   
    {   
        currentFrame.pVerts[j].x = m_pFrames[0].pVertices[j].vertex[0];   
        currentFrame.pVerts[j].y = m_pFrames[0].pVertices[j].vertex[1];   
        currentFrame.pVerts[j].z = m_pFrames[0].pVertices[j].vertex[2];   
    }   
   
    // We can now free the old vertices stored in this frame of animation   
    delete m_pFrames[0].pVertices;   
   
    // Go through all of the uv coordinates and assign them over to our structure.   
    // The UV coordinates are not normal uv coordinates, they have a pixel ratio of   
    // 0 to 256.  We want it to be a 0 to 1 ratio, so we divide the u value by the   
    // skin width and the v value by the skin height.  This gives us our 0 to 1 ratio.   
    // For some reason also, the v coodinate is flipped upside down.  We just subtract   
    // the v coordinate from 1 to remedy this problem.   
    for (j=0; j < currentFrame.numTexVertex; j++)   
    {   
        currentFrame.pTexVerts[j].x = m_pTexCoords[j].u / float(m_Header.skinWidth);   
        currentFrame.pTexVerts[j].y = 1 - m_pTexCoords[j].v / float(m_Header.skinHeight);   
    }   
   
    // Go through all of the face data and assign it over to OUR structure   
    for(j=0; j < currentFrame.numOfFaces; j++)   
    {   
        // Assign the vertex indices to our face data   
        currentFrame.pFaces[j].vertIndex[0] = m_pTriangles[j].vertexIndices[0];   
        currentFrame.pFaces[j].vertIndex[1] = m_pTriangles[j].vertexIndices[1];   
        currentFrame.pFaces[j].vertIndex[2] = m_pTriangles[j].vertexIndices[2];   
   
        // Assign the texture coord indices to our face data   
        currentFrame.pFaces[j].coordIndex[0] = m_pTriangles[j].textureIndices[0];   
        currentFrame.pFaces[j].coordIndex[1] = m_pTriangles[j].textureIndices[1];   
        currentFrame.pFaces[j].coordIndex[2] = m_pTriangles[j].textureIndices[2];   
    }   
   
    // Here we add the current object (or frame) to our list object list   
    pModel->pObject.push_back(currentFrame);   
}   
   
   
///////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
/////   
/////   This function cleans up our allocated memory and closes the file   
/////   
///////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
   
void CLoadMD2::CleanUp()   
{   
    // This just just the regular cleanup or our md2 model class.  We can free   
    // all of this data because we already have it stored in our own structures.   
   
    fclose(m_FilePointer);                      // Close the current file pointer   
   
    if(m_pSkins)     delete [] m_pSkins;        // Free the skins data   
    if(m_pTexCoords) delete m_pTexCoords;       // Free the texture coord data   
    if(m_pTriangles) delete m_pTriangles;       // Free the triangle face data   
    if(m_pFrames)    delete m_pFrames;          // Free the frames of animation   
}   
   
   
   
// *Note*    
//   
// Below are some math functions for calculating vertex normals.  We want vertex normals   
// because it makes the lighting look really smooth and life like.  You probably already   
// have these functions in the rest of your engine, so you can delete these and call   
// your own.  I wanted to add them so I could show how to calculate vertex normals.   
   
//////////////////////////////  Math Functions  ////////////////////////////////*   
   
// This computes the magnitude of a normal.   (magnitude = sqrt(x^2 + y^2 + z^2)   
#define Mag(Normal) (sqrt(Normal.x*Normal.x + Normal.y*Normal.y + Normal.z*Normal.z))   
   
// This calculates a vector between 2 points and returns the result   
CVector3 Vector(CVector3 vPoint1, CVector3 vPoint2)   
{   
    CVector3 vVector;                           // The variable to hold the resultant vector   
   
    vVector.x = vPoint1.x - vPoint2.x;          // Subtract point1 and point2 x's   
    vVector.y = vPoint1.y - vPoint2.y;          // Subtract point1 and point2 y's   
    vVector.z = vPoint1.z - vPoint2.z;          // Subtract point1 and point2 z's   
   
    return vVector;                             // Return the resultant vector   
}   
   
// This adds 2 vectors together and returns the result   
CVector3 AddVector(CVector3 vVector1, CVector3 vVector2)   
{   
    CVector3 vResult;                           // The variable to hold the resultant vector   
       
    vResult.x = vVector2.x + vVector1.x;        // Add Vector1 and Vector2 x's   
    vResult.y = vVector2.y + vVector1.y;        // Add Vector1 and Vector2 y's   
    vResult.z = vVector2.z + vVector1.z;        // Add Vector1 and Vector2 z's   
   
    return vResult;                             // Return the resultant vector   
}   
   
// This divides a vector by a single number (scalar) and returns the result   
CVector3 DivideVectorByScaler(CVector3 vVector1, float Scaler)   
{   
    CVector3 vResult;                           // The variable to hold the resultant vector   
       
    vResult.x = vVector1.x / Scaler;            // Divide Vector1's x value by the scaler   
    vResult.y = vVector1.y / Scaler;            // Divide Vector1's y value by the scaler   
    vResult.z = vVector1.z / Scaler;            // Divide Vector1's z value by the scaler   
   
    return vResult;                             // Return the resultant vector   
}   
   
// This returns the cross product between 2 vectors   
CVector3 Cross(CVector3 vVector1, CVector3 vVector2)   
{   
    CVector3 vCross;                                // The vector to hold the cross product   
                                                // Get the X value   
    vCross.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y));   
                                                // Get the Y value   
    vCross.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z));   
                                                // Get the Z value   
    vCross.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x));   
   
    return vCross;                              // Return the cross product   
}   
   
// This returns the normal of a vector   
CVector3 Normalize(CVector3 vNormal)   
{   
    double Magnitude;                           // This holds the magitude             
   
    Magnitude = Mag(vNormal);                   // Get the magnitude   
   
    vNormal.x /= (float)Magnitude;              // Divide the vector's X by the magnitude   
    vNormal.y /= (float)Magnitude;              // Divide the vector's Y by the magnitude   
    vNormal.z /= (float)Magnitude;              // Divide the vector's Z by the magnitude   
   
    return vNormal;                             // Return the normal   
}   
   
///////////////////////////////// COMPUTER NORMALS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
/////   
/////   This function computes the normals and vertex normals of the objects   
/////   
///////////////////////////////// COMPUTER NORMALS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
   
void CLoadMD2::ComputeNormals(t3DModel *pModel)   
{   
    CVector3 vVector1, vVector2, vNormal, vPoly[3];   
   
    // If there are no objects, we can skip this part   
    if(pModel->numOfObjects <= 0)   
        return;   
   
    // What are vertex normals?  And how are they different from other normals?   
    // Well, if you find the normal to a triangle, you are finding a "Face Normal".   
    // If you give OpenGL a face normal for lighting, it will make your object look   
    // really flat and not very round.  If we find the normal for each vertex, it makes   
    // the smooth lighting look.  This also covers up blocky looking objects and they appear   
    // to have more polygons than they do.    Basically, what you do is first   
    // calculate the face normals, then you take the average of all the normals around each   
    // vertex.  It's just averaging.  That way you get a better approximation for that vertex.   
   
    // Go through each of the objects to calculate their normals   
    for(int index = 0; index < pModel->numOfObjects; index++)   
    {   
        // Get the current object   
        t3DObject *pObject = &(pModel->pObject[index]);   
   
        // Here we allocate all the memory we need to calculate the normals   
        CVector3 *pNormals      = new CVector3 [pObject->numOfFaces];   
        CVector3 *pTempNormals  = new CVector3 [pObject->numOfFaces];   
        pObject->pNormals        = new CVector3 [pObject->numOfVerts];   
   
        // Go though all of the faces of this object   
        for(int i=0; i < pObject->numOfFaces; i++)   
        {                                                  
            // To cut down LARGE code, we extract the 3 points of this face   
            vPoly[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]];   
            vPoly[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]];   
            vPoly[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]];   
   
            // Now let's calculate the face normals (Get 2 vectors and find the cross product of those 2)   
   
            vVector1 = Vector(vPoly[0], vPoly[2]);      // Get the vector of the polygon (we just need 2 sides for the normal)   
            vVector2 = Vector(vPoly[2], vPoly[1]);      // Get a second vector of the polygon   
   
            vNormal  = Cross(vVector1, vVector2);       // Return the cross product of the 2 vectors (normalize vector, but not a unit vector)   
            pTempNormals[i] = vNormal;                  // Save the un-normalized normal for the vertex normals   
            vNormal  = Normalize(vNormal);              // Normalize the cross product to give us the polygons normal   
   
            pNormals[i] = vNormal;                      // Assign the normal to the list of normals   
        }   
   
        //////////////// Now Get The Vertex Normals /////////////////   
   
        CVector3 vSum = {0.0, 0.0, 0.0};   
        CVector3 vZero = vSum;   
        int shared=0;   
   
        for (i = 0; i < pObject->numOfVerts; i++)         // Go through all of the vertices   
        {   
            for (int j = 0; j < pObject->numOfFaces; j++) // Go through all of the triangles   
            {                                               // Check if the vertex is shared by another face   
                if (pObject->pFaces[j].vertIndex[0] == i ||    
                    pObject->pFaces[j].vertIndex[1] == i ||    
                    pObject->pFaces[j].vertIndex[2] == i)   
                {   
                    vSum = AddVector(vSum, pTempNormals[j]);// Add the un-normalized normal of the shared face   
                    shared++;                               // Increase the number of shared triangles   
                }   
            }         
               
            // Get the normal by dividing the sum by the shared.  We negate the shared so it has the normals pointing out.   
            pObject->pNormals[i] = DivideVectorByScaler(vSum, float(-shared));   
   
            // Normalize the normal for the final vertex normal   
            pObject->pNormals[i] = Normalize(pObject->pNormals[i]);      
   
            vSum = vZero;                                   // Reset the sum   
            shared = 0;                                     // Reset the shared   
        }   
       
        // Free our memory and start over on the next object   
        delete [] pTempNormals;   
        delete [] pNormals;   
    }   
}   
   
   
/////////////////////////////////////////////////////////////////////////////////   
//   
// * QUICK NOTES *    
//   
// Pretty simple huh?  This is probably the easiest 3D file format I have ever   
// worked with, so good job Carmack!  Once again, the next Md2 tutorial will cover   
// the key frame animation that is associated with these models.  Then you can    
// actually say you have worked with real quake characters and know how they did   
// their animation.  Let's go over a brief explanation of this loader:   
//   
// The structures MUST be the same size and data types in order to load the   
// Quake2 data.  First we load the Header information.  This tells us everything   
// about the file and it's contents.   
//    
// After the header is loaded, we need to check if the ID is 8.  This is a must.   
// Don't ask me why it's 8, ask John Carmack!  If the version ID checks out, then   
// we can start loading the data.   
//    
// For each set of data you want to load is, we use an fseek() to move the file   
// pointer to that location in the file that is given in the header.   
//   
// After you load the data, you can then convert the data structures to your own   
// format, that way you don't have ot be stuck with theirs.  I decided to make it   
// like the other loaders for future purposes.  We also compute our own normals.   
//   
// There is one thing I didn't mention that was NOT loaded in.  There is an array   
// of OpenGL commands that allow you to render the vertices in triangle strips and   
// a triangle fan.  This is the ugliest code I have ever seen to implement it, so   
// I left it out :)   
//   
// I would like to thank Daniel E. Schoenblum <dansch@hops.cs.jhu.edu> for help   
// with explaining the file format.   
//   
// Let me know if this helps you out!   
//    
//    
// Ben Humphrey (DigiBen)   
// Game Programmer   
// DigiBen@GameTutorials.com   
// Co-Web Host of www.GameTutorials.com   
//   
// The Quake2 .Md2 file format is owned by ID Software.  This tutorial is being used    
// as a teaching tool to help understand model loading and animation.  This should   
// not be sold or used under any way for commercial use with out written conset   
// from ID Software.   
//   
// Quake and Quake2 are trademarks of id Software.   
// All trademarks used are properties of their respective owners.    
//   
//

 

posted @ 2014-01-14 10:07  拾遗日志  阅读(373)  评论(0编辑  收藏  举报