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;
}







posted @ 2011-09-23 16:18  小 楼 一 夜 听 春 雨  阅读(2005)  评论(1编辑  收藏  举报