• 49. obj文件读数据并渲染的演示程序


    token.h

    #ifndef _UGP_TOKEN_H_
    #define _UGP_TOKEN_H_


    class CToken
    {
    public:
    CToken() : m_length(0), m_startIndex(0), m_endIndex(0), m_data(0) {}
    ~CToken() { Shutdown(); }

    void Reset(){ m_startIndex = m_endIndex = 0; }

    void SetTokenStream(char *data);

    bool GetNextToken(char *buffer);
    bool GetNextToken(char *token, char *buffer);

    bool MoveToNextLine(char *buffer);

    void Shutdown();

    private:
    int m_length;
    int m_startIndex, m_endIndex;
    char *m_data;
    };

    #endif

    token.cpp

    #include<string.h>
    #include"Token.h"


    bool isValidIdentifier(char c)
    {
    // It is valid if it falls within one of these ranges.
    if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||

    (c >= 'A' && c <= 'Z') || c == '_' || c =='"' || c =='/' ||
    c =='(' || c ==')' || c =='-' || c=='.')
    return true;

    return false;
    }


    void CToken::SetTokenStream(char *data)
    {
    Shutdown();

    m_length = strlen(data);
    m_data = new char[(m_length + 1) * sizeof(char)];
    strcpy(m_data, data);
    m_data[m_length] = '\0';
    }


    bool CToken::GetNextToken(char *buffer)
    {
    bool inString = false;
    m_startIndex = m_endIndex;

    if(buffer) buffer[0] = '\0';

    while(m_startIndex < m_length && ((m_data[m_startIndex] == ' ' || m_data[m_startIndex] == '\t') ||
    inString))
    {
    if(m_data[m_startIndex] == '"') inString = !inString;
    m_startIndex++;
    }

    m_endIndex = m_startIndex + 1;

    if(m_startIndex < m_length)
    {
    bool valid = true;

    if(isValidIdentifier(m_data[m_startIndex]))
    while(isValidIdentifier(m_data[m_endIndex]) || m_data[m_endIndex] == '.') m_endIndex++;
    else valid = false;

    if(buffer != NULL)
    {
    if(valid)
    {
    strncpy(buffer, m_data + m_startIndex, m_endIndex - m_startIndex);
    buffer[m_endIndex - m_startIndex] = '\0';

    if(strcmp(buffer, "\n") == 0) buffer[0] = '\0';
    }
    else buffer[0] = '\0';
    }

    return true;
    }

    return false;
    }


    bool CToken::GetNextToken(char *token, char *buffer)
    {
    char tok[256];

    while(GetNextToken(tok))
    if(stricmp(tok, token) == 0) return GetNextToken(buffer);

    return false;
    }


    bool CToken::MoveToNextLine(char *buffer)
    {
    if(m_startIndex < m_length && m_endIndex < m_length)
    {
    m_startIndex = m_endIndex;

    while(m_endIndex < m_length && (m_data[m_endIndex] != '\n' &&
    m_data[m_endIndex] != '\r' && m_data[m_endIndex] != '\0')) m_endIndex++;

    if(m_endIndex - m_startIndex >= 511) return false;

    if(buffer != NULL)
    {
    strncpy(buffer, m_data + m_startIndex, m_endIndex - m_startIndex);
    buffer[m_endIndex - m_startIndex] = '\0';
    }
    }
    else
    return false;

    return true;
    }


    void CToken::Shutdown()
    {
    if(m_data) delete[] m_data;
    m_data = NULL;

    m_length = m_startIndex = m_endIndex = 0;
    }

    objLoader.h

    #ifndef _OBJ_LOADER_H_
    #define _OBJ_LOADER_H_

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include"Token.h"

    // Pretty straight forward don't you think?
    struct stObjModel

    {
    float *vertices;
    float *normals;
    float *texCoords;
    int numFaces;
    };

    stObjModel *LoadOBJModel(char *fileName);
    void FreeModel(stObjModel *model);

    ////////////////////////////////////////////////////////// hkx add//////////////////////////////////////
    #include <vector>

    #include <fstream>
    #include <iostream>

    // 顶点, 法线顶点
    struct vertex

    {
    vertex(float x = 0, float y = 0, float z = 0):m_x(x), m_y(y), m_z(z){}
    float m_x;
    float m_y;
    float m_z;
    };

    // 纹理坐标顶点
    struct texVertex

    {
    texVertex(float x = 0, float y = 0):m_u(x), m_v(y) {}
    float m_u;
    float m_v;
    };

    // 面;三角形,里面存的顶点的索引
    struct face

    {
    int m_vertexIndex1;
    int m_vertexIndex2;
    int m_vertexIndex3;

    int m_texVertexIndex1;
    int m_texVertexIndex2;
    int m_texVertexIndex3;

    int m_normalVertexIndex1;
    int m_normalVertexIndex2;
    int m_normalVertexIndex3;
    };

    // obj文件存的所有内容
    struct ObjModel

    {
    std::vector<vertex> m_vecVertex; // 顶点数组
    std::vector<vertex> m_vecNormalVertex; // 法线坐标顶点数组
    std::vector<texVertex> m_vecTexVertex; // 纹理坐标顶点数组
    int m_nFaces; // 三角形的个数
    };



    class CObjModelManager
    {
    public:

    static CObjModelManager& GetSingleton()
    {
    static CObjModelManager manager;
    return manager;
    }

    static void CloseSingleton()
    {
    }

    void LoadObjModel(char *fileName)
    {
    m_vecObjModel.clear();

    std::ifstream ifs;
    ifs.open(fileName);
    if (ifs.fail())
    return;

    int tmp = ifs.tellg();
    ifs.seekg(0, std::ios_base::end);
    int size = ifs.tellg();
    ifs.seekg(tmp);

    char* data = 0;
    data = new char[(size + 1) * sizeof(char)];
    if(!data)
    return;
    ifs.read(data, size);
    data[size] = '\0';
    ifs.close();

    CToken lexer, tempLex;
    char tempLine[512];
    char token[512];

    lexer.SetTokenStream(data);

    delete[] data; data = 0;

    bool validFile = false;
    while(lexer.GetNextToken(token))
    {
    if(strcmp(token, "Wavefront") == 0)
    {
    validFile = true;
    break;
    }
    }
    if(!validFile) return;

    lexer.Reset();

    ObjModel obj;

    std::vector<vertex> tempVecVertex;
    std::vector<vertex> tempNormalVertex;
    std::vector<texVertex> tempVectexVertex;
    std::vector<face> vecFaces;

    vertex vert;
    vertex normalvert;
    texVertex texvert;

    while(lexer.MoveToNextLine(tempLine))
    {
    tempLex.SetTokenStream(tempLine);
    lexer.GetNextToken(NULL);
    if(!tempLex.GetNextToken(token)) continue;

    if(strcmp(token, "v") == 0)
    {
    tempLex.GetNextToken(token);
    vert.m_x = (float)atof(token);

    tempLex.GetNextToken(token);
    vert.m_y = (float)atof(token);

    tempLex.GetNextToken(token);
    vert.m_z = (float)atof(token);

    tempVecVertex.push_back(vert);
    }
    else if(strcmp(token, "vn") == 0)
    {
    tempLex.GetNextToken(token);
    normalvert.m_x = (float)atof(token);

    tempLex.GetNextToken(token);
    normalvert.m_y = (float)atof(token);

    tempLex.GetNextToken(token);
    normalvert.m_z = (float)atof(token);

    tempNormalVertex.push_back(normalvert);
    }
    else if(strcmp(token, "vt") == 0)
    {
    tempLex.GetNextToken(token);
    texvert.m_u = (float)atof(token);

    tempLex.GetNextToken(token);
    texvert.m_v = (float)atof(token);

    tempVectexVertex.push_back(texvert);
    }
    else if(strcmp(token, "f") == 0)
    {
    face f;
    for(int i = 0; i < 3; i++)
    {
    tempLex.GetNextToken(token);
    if(i == 0)
    sscanf_s(token, "%d/%d/%d", &(f.m_vertexIndex1),
    &(f.m_texVertexIndex1), &(f.m_normalVertexIndex1));
    else if (i == 1)
    sscanf_s(token, "%d/%d/%d", &(f.m_vertexIndex2),
    &(f.m_texVertexIndex2), &(f.m_normalVertexIndex2));
    else
    sscanf_s(token, "%d/%d/%d", &(f.m_vertexIndex3),
    &(f.m_texVertexIndex3), &(f.m_normalVertexIndex3));

    }//for

    vecFaces.push_back(f);
    }

    token[0] = '\0';
    }

    // No longer need.
    lexer.Shutdown();


    obj.m_nFaces = vecFaces.size();

    for (int i=0; i<vecFaces.size(); ++i)
    {
    obj.m_vecVertex.push_back(tempVecVertex[vecFaces[i].m_vertexIndex1 - 1]);
    obj.m_vecVertex.push_back(tempVecVertex[vecFaces[i].m_vertexIndex2 - 1]);
    obj.m_vecVertex.push_back(tempVecVertex[vecFaces[i].m_vertexIndex3 - 1]);

    obj.m_vecTexVertex.push_back(tempVectexVertex[vecFaces[i].m_texVertexIndex1 - 1]);
    obj.m_vecTexVertex.push_back(tempVectexVertex[vecFaces[i].m_texVertexIndex2 - 1]);
    obj.m_vecTexVertex.push_back(tempVectexVertex[vecFaces[i].m_texVertexIndex3 - 1]);

    obj.m_vecNormalVertex.push_back(tempNormalVertex[vecFaces[i].m_normalVertexIndex1 - 1]);
    obj.m_vecNormalVertex.push_back(tempNormalVertex[vecFaces[i].m_normalVertexIndex2 - 1]);
    obj.m_vecNormalVertex.push_back(tempNormalVertex[vecFaces[i].m_normalVertexIndex3 - 1]);
    }

    m_vecObjModel.push_back(obj);
    }

    std::vector<ObjModel> m_vecObjModel;
    };
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    #endif

    objLoader.cpp

    #include"objLoader.h"


    stObjModel *LoadOBJModel(char *fileName)
    {
    FILE *file;
    char *data = NULL;
    CToken lexer, tempLex;
    char tempLine[512];
    char token[512];

    // Open file for input.
    file = fopen(fileName, "r");

    if(!file) return NULL;

    // Get the length of the file.
    fseek(file, 0, SEEK_END);

    int length = ftell(file);
    fseek(file, 0, SEEK_SET);

    // Read in all data from the file.
    data = new char[(length + 1) * sizeof(char)];

    if(!data) return NULL;
    fread(data, length, 1, file);
    data[length] = '\0';

    // Close the file when we are done.
    fclose(file);


    // Set our file to our lexer.
    lexer.SetTokenStream(data);


    // No longer need.
    delete[] data; data = NULL;


    bool validFile = false;

    // Look for the word Wavefront somewhere in the file to
    // determine if this .obj is compatiable since so modelers export
    // to slightly different formats.
    while(lexer.GetNextToken(token))

    {
    if(strcmp(token, "Wavefront") == 0)
    {
    validFile = true;
    break;
    }
    }

    if(!validFile) return NULL;

    // Reset for next pass.
    lexer.Reset();


    // Used to get the total number of each declared in a file.
    // Since faces uses indices these number could be different.
    int totalVertices = 0, totalNormals = 0,

    totalTexC = 0, totalFaces = 0;

    // Get the first (or next) line.
    while(lexer.MoveToNextLine(tempLine))

    {
    // Set line to the temp lexer.
    tempLex.SetTokenStream(tempLine);


    // Read the new line character.
    lexer.GetNextToken(NULL);


    // If something was set to the temp lex then we keep going.
    if(!tempLex.GetNextToken(token)) continue;


    // If the first token of the line is a v, vn, vt, or f
    // increment the respective counter.
    if(strcmp(token, "v") == 0) totalVertices++;

    else if(strcmp(token, "vn") == 0) totalNormals++;
    else if(strcmp(token, "vt") == 0) totalTexC++;
    else if(strcmp(token, "f") == 0) totalFaces++; // f开头的代表一个三角形,也就是一个面

    token[0] = '\0';
    }

    // Allocate temp space to hold the data. Face are by 9 since there are
    // 3 vertices each with 3 values (v index/vt index/vn index).
    float *verts = new float[totalVertices * 3];

    float *norms = new float[totalNormals * 3];
    float *texC = new float[totalTexC * 2];
    int *faces = new int[totalFaces * 9]; //一个三角形有三个顶点,每个顶点三个坐标
    int vIndex = 0, nIndex = 0, tIndex = 0, fIndex = 0, index = 0;


    // Move to the beginning of the file.
    lexer.Reset();


    // 记录faces数组中索引的总数
    int facesArraySize = 0;

    // Do it all again but this time we get the data.
    while(lexer.MoveToNextLine(tempLine))

    {
    // Set to temp lex, read past newline, get token.
    tempLex.SetTokenStream(tempLine);

    lexer.GetNextToken(NULL);
    if(!tempLex.GetNextToken(token)) continue;

    // If v then we get the vertex x, y, z.
    if(strcmp(token, "v") == 0)

    {
    // Get the x and save it.
    tempLex.GetNextToken(token);

    verts[vIndex] = (float)atof(token);
    vIndex++;

    // Get the y and save it.
    tempLex.GetNextToken(token);

    verts[vIndex] = (float)atof(token);
    vIndex++;

    // Get the z and save it.
    tempLex.GetNextToken(token);

    verts[vIndex] = (float)atof(token);
    vIndex++;
    }
    // Else If vn then we get the normal x, y, z.
    else if(strcmp(token, "vn") == 0)

    {
    // Get the x and save it.
    tempLex.GetNextToken(token);

    norms[nIndex] = (float)atof(token);
    nIndex++;

    // Get the y and save it.
    tempLex.GetNextToken(token);

    norms[nIndex] = (float)atof(token);
    nIndex++;

    // Get the z and save it.
    tempLex.GetNextToken(token);

    norms[nIndex] = (float)atof(token);
    nIndex++;
    }
    // Else If vt then we get the tex coord u, v.
    else if(strcmp(token, "vt") == 0)

    {
    // Get the u and save it.
    tempLex.GetNextToken(token);

    texC[tIndex] = (float)atof(token);
    tIndex++;

    // Get the v and save it.
    tempLex.GetNextToken(token);

    texC[tIndex] = (float)atof(token);
    tIndex++;
    }
    // Else If f then get each vertex 3 indices set.
    else if(strcmp(token, "f") == 0)

    {
    // Load for each vertex (3 in a triangle).
    for(int i = 0; i < 3; i++)

    {
    // Get first set. Get the length of it.
    tempLex.GetNextToken(token);

    int len = strlen(token);

    // Since there are no spaces between a set (1/1/1)
    // we can't simply read tokens so we must loop
    // through and take out each value before the / sign.
    for(int s = 0; s < len + 1; s++)

    {
    char buff[64];

    // If this is not a / or if not at the end.
    if(token[s] != '/' && s < len)

    {
    buff[index] = token[s];
    index++;
    }
    else
    {
    // Else end the string, convert it, save it.
    buff[index] = '\0';

    faces[fIndex] = (int)atoi(buff);
    fIndex++;
    index = 0;

    facesArraySize ++;
    }
    }
    }
    }

    token[0] = '\0';
    }

    // No longer need.
    lexer.Shutdown();


    // Create the model object by allocating.
    stObjModel *model = new stObjModel;

    if(!model) return NULL;
    memset(model, 0, sizeof(stObjModel));

    // Save face count.
    model->numFaces = totalFaces;


    // Reset temp counters.
    vIndex = 0, nIndex = 0, tIndex = 0, fIndex = 0, index = 0;


    // Allocate data for each part of the model.
    // 因为vertices是float数组,每个三角形三个顶点,每个顶点有3个坐标位置x,y,z
    model->vertices = new float[totalFaces * 3 * 3];

    // 因为normals是float数组,每个三角形三个顶点,每个顶点有3个法线坐标nx,ny,nz
    if(totalNormals) model->normals = new float[totalFaces * 3 * 3];

    // 因为texCoords是float数组,每个三角形三个顶点,每个顶点有2个纹理坐标点u,v
    if(totalTexC) model->texCoords = new float[totalFaces * 3 * 2];


    // Loop through and fill in our model.
    // 总顶点个数为totalFaces * 9
    for(int f = 0; f < totalFaces * 9; f += 3)

    {
    // Get vertex. We subtract by 1 since we need our indices to be
    // in the range of 0 to max - 1 not 1 to max. We multiply by 3
    // since there are 3 componets (x, y, z) in a vertex.
    //faces数组中存的是顶点的索引
    // 得到一个索引后还需从verts中取出对象顶点的三个坐标分量复制到model->vertices中去
    if (f >= facesArraySize)

    continue;

    model->vertices[vIndex + 0] = verts[(faces[f + 0] - 1) * 3 + 0];
    model->vertices[vIndex + 1] = verts[(faces[f + 0] - 1) * 3 + 1];
    model->vertices[vIndex + 2] = verts[(faces[f + 0] - 1) * 3 + 2];
    vIndex += 3;

    // We do the same with the texture coordinate data. Since tex coord
    // data in the second thing we app 1 to f (v/vt/vn).
    if(model->texCoords)

    {
    model->texCoords[tIndex + 0] = texC[(faces[f + 1] - 1) * 2 + 0];
    model->texCoords[tIndex + 1] = texC[(faces[f + 1] - 1) * 2 + 1];
    tIndex += 2;
    }

    // We do the same with the normal coordinate data.
    if(model->normals)

    {
    model->normals[nIndex + 0] = norms[(faces[f + 2] - 1) * 3 + 0];
    model->normals[nIndex + 1] = norms[(faces[f + 2] - 1) * 3 + 1];
    model->normals[nIndex + 2] = norms[(faces[f + 2] - 1) * 3 + 2];
    nIndex += 3;
    }
    }

    // Delete temp data.
    delete[] verts;

    delete[] norms;
    delete[] texC;
    delete[] faces;

    return model;
    }


    void FreeModel(stObjModel *model)
    {
    if(!model) return;

    // Release all resources.
    if(model->vertices) delete[] model->vertices;

    model->vertices = NULL;
    if(model->normals) delete[] model->normals;
    model->normals = NULL;
    if(model->texCoords) delete[] model->texCoords;
    model->texCoords = NULL;

    delete model;
    model = NULL;
    }

    main.cpp

    #include<d3d9.h>
    #include<d3dx9.h>
    #include"objLoader.h"

    #pragma comment(lib, "d3d9.lib")
    #pragma comment(lib, "d3dx9.lib")


    #define WINDOW_CLASS "UGPDX"
    #define WINDOW_NAME "OBJ Model Loading"
    #define WINDOW_WIDTH 640
    #define WINDOW_HEIGHT 480
    #define FULLSCREEN 0

    // Function Prototypes...
    bool InitializeD3D();

    bool InitializeObjects();
    void RenderScene();
    void Shutdown();


    // Global window handle.
    HWND g_hwnd = 0;



    // Direct3D object and device.
    LPDIRECT3D9 g_D3D = NULL;

    LPDIRECT3DDEVICE9 g_D3DDevice = NULL;


    // Matrices.
    D3DXMATRIX g_projection;

    D3DXMATRIX g_worldMatrix;
    D3DXMATRIX g_ViewMatrix;


    // Vertex buffer to hold the geometry.
    LPDIRECT3DVERTEXBUFFER9 g_vertexBuffer = NULL;



    // A structure for our custom vertex type
    struct stD3DVertex

    {
    float x, y, z;
    float nx, ny, nz;
    unsigned long color;
    };

    // Our custom FVF, which describes our custom vertex structure
    #define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE)



    // Model we are loading.
    stObjModel *g_model;


    // These are the x and y rotations for our object.
    float g_xRot = 0.0f;

    float g_yRot = 0.0f;


    // Scene light source.
    D3DLIGHT9 g_light;



    LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    static POINT oldMousePos;
    static POINT currentMousePos;
    static bool isMouseActive;

    switch(msg)
    {
    case WM_DESTROY:
    case WM_CLOSE:
    PostQuitMessage(0);
    return 0;
    break;

    case WM_KEYUP:
    if(wParam == VK_ESCAPE) PostQuitMessage(0);
    break;

    case WM_LBUTTONDOWN:
    oldMousePos.x = currentMousePos.x = LOWORD(lParam);
    oldMousePos.y = currentMousePos.y = HIWORD(lParam);
    isMouseActive = true;
    break;

    case WM_LBUTTONUP:
    isMouseActive = false;
    break;

    case WM_MOUSEMOVE:
    currentMousePos.x = LOWORD (lParam);
    currentMousePos.y = HIWORD (lParam);

    if(isMouseActive)
    {
    g_xRot -= (currentMousePos.x - oldMousePos.x);
    g_yRot -= (currentMousePos.y - oldMousePos.y);
    }

    oldMousePos.x = currentMousePos.x;
    oldMousePos.y = currentMousePos.y;
    break;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
    }


    int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmdLine, int show)
    {
    // Register the window class
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,

    GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
    WINDOW_CLASS, NULL };
    RegisterClassEx(&wc);

    // Create the application's window
    HWND hWnd = CreateWindow(WINDOW_CLASS, WINDOW_NAME, WS_OVERLAPPEDWINDOW,

    100, 100, WINDOW_WIDTH, WINDOW_HEIGHT,
    GetDesktopWindow(), NULL, wc.hInstance, NULL);

    // Show the window
    ShowWindow(hWnd, SW_SHOWDEFAULT);

    UpdateWindow(hWnd);

    // Record for global.
    g_hwnd = hWnd;


    // Initialize Direct3D
    if(InitializeD3D())

    {
    // Enter the message loop
    MSG msg;

    ZeroMemory(&msg, sizeof(msg));

    while(msg.message != WM_QUIT)
    {
    if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    else
    RenderScene();
    }
    }

    // Release any and all resources.
    Shutdown();


    // Unregister our window.
    UnregisterClass(WINDOW_CLASS, wc.hInstance);

    return 0;
    }


    bool InitializeD3D()
    {
    D3DDISPLAYMODE displayMode;

    // Create the D3D object.
    g_D3D = Direct3DCreate9(D3D_SDK_VERSION);

    if(g_D3D == NULL) return false;

    // Get the desktop display mode.
    if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode)))

    return false;

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory(&d3dpp, sizeof(d3dpp));

    if(FULLSCREEN)
    {
    d3dpp.Windowed = FALSE;
    d3dpp.BackBufferWidth = WINDOW_WIDTH;
    d3dpp.BackBufferHeight = WINDOW_HEIGHT;
    }
    else
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = displayMode.Format;
    d3dpp.BackBufferCount = 1;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;


    // Create the D3DDevice
    if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd,

    D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE,
    &d3dpp, &g_D3DDevice))) return false;

    // Initialize any objects we will be displaying.
    if(!InitializeObjects()) return false;


    return true;
    }


    bool InitializeObjects()
    {
    // Set default rendering states.
    g_D3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

    g_D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    g_D3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);


    // Setup the g_light source and material.
    g_light.Type = D3DLIGHT_DIRECTIONAL;

    g_light.Direction = D3DXVECTOR3(0.0f, 0.0f, 1.0f);

    D3DCOLORVALUE white;
    white.a = white.r = white.g = white.b = 1;

    g_light.Diffuse = white;
    g_light.Specular = white;

    g_D3DDevice->SetLight(0, &g_light);
    g_D3DDevice->LightEnable(0, TRUE);


    // Load the model from the file.
    g_model = LoadOBJModel("SmoothCube.obj");

    if(!g_model) return false;

    //
    CObjModelManager::GetSingleton().LoadObjModel("SmoothCube.obj");

    //

    // Allocate temp D3D array for model data.
    stD3DVertex *objData = new stD3DVertex[g_model->numFaces * 3]; // 每个面有3个顶点
    int size = sizeof(stD3DVertex) * (g_model->numFaces * 3);


    // 方案1
    int tmp1 = 0;

    int tmp2 = 0;
    for (int i=0; i<CObjModelManager::GetSingleton().m_vecObjModel[0].m_nFaces * 3; ++i)
    {
    objData[i].x = CObjModelManager::GetSingleton().m_vecObjModel[0].m_vecVertex[tmp1].m_x;
    objData[i].y = CObjModelManager::GetSingleton().m_vecObjModel[0].m_vecVertex[tmp1].m_y;
    objData[i].z = CObjModelManager::GetSingleton().m_vecObjModel[0].m_vecVertex[tmp1].m_z;
    tmp1 ++;

    objData[i].nx = CObjModelManager::GetSingleton().m_vecObjModel[0].m_vecNormalVertex[tmp2].m_x;
    objData[i].ny = CObjModelManager::GetSingleton().m_vecObjModel[0].m_vecNormalVertex[tmp2].m_y;
    objData[i].nz = CObjModelManager::GetSingleton().m_vecObjModel[0].m_vecNormalVertex[tmp2].m_z;

    tmp2 ++;

    objData[i].color = D3DCOLOR_XRGB(255,255,255);
    }

    //

    // 方案2
    // Copy model data into vertex buffer.
    //int v = 0, n = 0;
    //for(int i = 0; i < g_model->numFaces * 3; i++)
    //{
    // objData[i].x = g_model->vertices[v++];
    // objData[i].y = g_model->vertices[v++];
    // objData[i].z = g_model->vertices[v++];
    // objData[i].nx = g_model->normals[n++];
    // objData[i].ny = g_model->normals[n++];
    // objData[i].nz = g_model->normals[n++];
    // objData[i].color = D3DCOLOR_XRGB(255,255,255);
    //}

    // Create the vertex buffer.
    if(FAILED(g_D3DDevice->CreateVertexBuffer(size, 0,

    D3DFVF_VERTEX, D3DPOOL_DEFAULT,
    &g_vertexBuffer, NULL))) return false;

    // Fill the vertex buffer.
    void *ptr;


    if(FAILED(g_vertexBuffer->Lock(0, size,
    (void**)&ptr, 0))) return false;

    memcpy(ptr, objData, size);

    g_vertexBuffer->Unlock();

    if(objData) delete[] objData;

    // Set the projection matrix.
    D3DXMatrixPerspectiveFovLH(&g_projection, D3DX_PI / 4,

    WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f);

    g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);

    // Define camera information.
    D3DXVECTOR3 cameraPos(0.0f, 0.0f, -5.0f);

    D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 upDir(0.0f, 1.0f, 0.0f);

    // Build view matrix.
    D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos,

    &lookAtPos, &upDir);

    return true;
    }


    void RenderScene()
    {
    // Clear the backbuffer.
    g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,

    D3DCOLOR_XRGB(0,0,0), 1.0f, 0);

    // Begin the scene. Start rendering.
    g_D3DDevice->BeginScene();


    // Apply the view (camera).
    g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);


    // Used to rotate by mouse.
    D3DXMATRIX rot, rotX, rotY;


    // Set the rot value to the matrix. Convert deg to rad.
    D3DXMatrixRotationX(&rotX, -g_yRot / 180.0f * 3.141592654f);

    D3DXMatrixRotationY(&rotY, g_xRot / 180.0f * 3.141592654f);

    // Set the rotation matrix.
    rot = rotX * rotY;

    g_D3DDevice->SetTransform(D3DTS_WORLD, &rot);

    // Draw the model.
    g_D3DDevice->SetStreamSource(0, g_vertexBuffer, 0, sizeof(stD3DVertex));

    g_D3DDevice->SetFVF(D3DFVF_VERTEX);
    g_D3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, g_model->numFaces);

    // End the scene. Stop rendering.
    g_D3DDevice->EndScene();


    // Display the scene.
    g_D3DDevice->Present(NULL, NULL, NULL, NULL);

    }


    void Shutdown()
    {
    if(g_D3DDevice != NULL) g_D3DDevice->Release();
    g_D3DDevice = NULL;

    if(g_D3D != NULL) g_D3D->Release();
    g_D3D = NULL;

    if(g_vertexBuffer != NULL) g_vertexBuffer->Release();
    g_vertexBuffer = NULL;

    if(g_model) FreeModel(g_model);
    g_model = NULL;
    }







  • 相关阅读:
    hdu 1524
    hdu 1536
    转载一篇博弈博弈入门的好文章
    nim 博弈
    WPF 从Main函数启动
    C# map network drive sample
    Predicate 学习
    WPF 绑定到附加属性 绑定到只读属性
    WPF 带有watermark的文本输入框
    使用Windows服务发布WCF服务
  • 原文地址:https://www.cnblogs.com/kex1n/p/2186361.html
Copyright © 2020-2023  润新知