zoukankan      html  css  js  c++  java
  • 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.    
    //   
    //
  • 相关阅读:
    MySQL大表优化方案
    写一个简单脚本检测mysql主从是否正常
    Nginx配置基于ip的虚拟主机
    推荐一些好的linux学习网站
    shell基础入门(一)
    centos7和linux防火墙配置入门
    centos7.0之vsftpd随笔
    获取系统相关属性
    linux 文件管理操作入门
    ANSI文件操作
  • 原文地址:https://www.cnblogs.com/duanqiao/p/3518482.html
Copyright © 2011-2022 走看看