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