codice:
#include "mesh.h"
extern IDirect3DDevice9 *g_pDevice;
#define PATH_TO_TEXTURES "Resources/meshes/"
Mesh::Mesh()
{
m_pMesh = NULL;
}
Mesh::Mesh(char fName[])
{
m_pMesh = NULL;
Load(fName);
}
Mesh::~Mesh()
{
Release();
}
HRESULT Mesh::Load(char fName[])
{
Release();
m_white.Ambient = m_white.Specular = m_white.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
m_white.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
m_white.Power = 1.0f;
ID3DXBuffer * adjacencyBfr = NULL;
ID3DXBuffer * materialBfr = NULL;
DWORD noMaterials = NULL;
if(FAILED(D3DXLoadMeshFromX((LPCWSTR)fName, D3DXMESH_MANAGED, g_pDevice, &adjacencyBfr, &materialBfr, NULL, &noMaterials, &m_pMesh)))
return E_FAIL;
D3DXMATERIAL *mtrls = (D3DXMATERIAL*)materialBfr->GetBufferPointer();
for(int i=0;i<(int)noMaterials;i++)
{
m_materials.push_back(mtrls[i].MatD3D);
if(mtrls[i].pTextureFilename != NULL)
{
char textureFileName[90];
strcpy(textureFileName, PATH_TO_TEXTURES);
strcat(textureFileName, mtrls[i].pTextureFilename);
IDirect3DTexture9 * newTexture = NULL;
D3DXCreateTextureFromFile(g_pDevice, (LPCWSTR)textureFileName, &newTexture);
m_textures.push_back(newTexture);
}
else m_textures.push_back(NULL);
}
m_pMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE,
(DWORD*)adjacencyBfr->GetBufferPointer(), NULL, NULL, NULL);
adjacencyBfr->Release();
materialBfr->Release();
return S_OK;
}
void Mesh::Render()
{
int numMaterials = (int)m_materials.size();
for(int i=0;i<numMaterials;i++)
{
if(m_textures[i] != NULL)
g_pDevice->SetMaterial(&m_white);
else g_pDevice->SetMaterial(&m_materials[i]);
g_pDevice->SetTexture(0, m_textures[i]);
m_pMesh->DrawSubset(i);
}
}
void Mesh::Release()
{
if(m_pMesh != NULL)
{
m_pMesh->Release();
m_pMesh = NULL;
}
int numTextures = (int)m_textures.size();
for(int i=0;i<numTextures;i++)
if(m_textures[i] != NULL)
m_textures[i]->Release();
m_textures.clear();
m_materials.clear();
}
application.cpp (il file principale)
codice:
#include <windows.h>
#include <d3dx9.h>
#include <fstream>
#include "mesh.h"
using namespace std;
//Global Variables
IDirect3DDevice9* g_pDevice = NULL;
ID3DXSprite* g_pSprite = NULL;
ID3DXFont* g_pFont = NULL;
ID3DXEffect* g_pEffect = NULL;
ofstream g_debug("debug.txt");
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
bool KeyDown(int vk_code){return (GetAsyncKeyState(vk_code) & 0x8000) ? true : false;}
bool KeyUp(int vk_code){return (GetAsyncKeyState(vk_code) & 0x8000) ? false : true;}
class Application
{
public:
Application();
~Application();
HRESULT Init(HINSTANCE hInstance, bool windowed);
void Update(float deltaTime);
void Render();
void Cleanup();
void Quit();
void DeviceLost();
void DeviceGained();
private:
HWND m_mainWindow;
D3DPRESENT_PARAMETERS m_present;
bool m_deviceLost;
Mesh m_soldier;
float m_angle;
};
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
//User specified events
switch( msg )
{
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
Application app;
if(FAILED(app.Init(hInstance, true)))
return 0;
MSG msg;
memset(&msg, 0, sizeof(MSG));
//Keep track of the time
DWORD startTime = GetTickCount();
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else //Otherwise update the game
{
//Calculate the delta time
DWORD t = GetTickCount();
float deltaTime = (t - startTime)*0.001f;
//Update the application
app.Update(deltaTime);
//Render the application
app.Render();
startTime = t;
}
}
//Release all resources
app.Cleanup();
//... and Quit!
return (int)msg.wParam;
}
Application::Application()
{
m_angle = 0.0f;
}
Application::~Application()
{
if(g_debug.good())
{
g_debug.close();
}
}
HRESULT Application::Init(HINSTANCE hInstance, bool windowed)
{
g_debug << "Application Started \n";
//Create Window Class
WNDCLASS wc;
memset(&wc, 0, sizeof(WNDCLASS));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"D3DWND";
RECT rc = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
//Register Class and Create new Window
RegisterClass(&wc);
m_mainWindow = CreateWindow(L"D3DWND", //Window class to use
L"Character Animation with Direct3D: Example 2.1", //Title
WS_OVERLAPPEDWINDOW, //Style
0, //X
0, //Y
rc.right - rc.left, //Width
rc.bottom - rc.top, //Height
NULL, //Parent Window
NULL, //Menu
hInstance, //Application Instance
0); //Param
SetCursor(NULL);
ShowWindow(m_mainWindow, SW_SHOW);
UpdateWindow(m_mainWindow);
//Create IDirect3D9 Interface
IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if(d3d9 == NULL)
{
g_debug << "Direct3DCreate9() - FAILED \n";
return E_FAIL;
}
//Check that the Device supports what we need from it
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
//Check vertex & pixelshader versions
if(caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
{
g_debug << "Warning - Your graphic card does not support vertex and pixelshaders version 2.0 \n";
}
//Set D3DPRESENT_PARAMETERS
m_present.BackBufferWidth = WINDOW_WIDTH;
m_present.BackBufferHeight = WINDOW_HEIGHT;
m_present.BackBufferFormat = D3DFMT_A8R8G8B8;
m_present.BackBufferCount = 2;
m_present.MultiSampleType = D3DMULTISAMPLE_NONE;
m_present.MultiSampleQuality = 0;
m_present.SwapEffect = D3DSWAPEFFECT_DISCARD;
m_present.hDeviceWindow = m_mainWindow;
m_present.Windowed = windowed;
m_present.EnableAutoDepthStencil = true;
m_present.AutoDepthStencilFormat = D3DFMT_D24S8;
m_present.Flags = 0;
m_present.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
m_present.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
//Hardware Vertex Processing
int vp = 0;
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
//Create the IDirect3DDevice9
if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow, vp, &m_present, &g_pDevice)))
{
g_debug << "Failed to create IDirect3DDevice9 \n";
return E_FAIL;
}
//Release IDirect3D9 interface
d3d9->Release();
//Load Application Specific resources here...
D3DXCreateFont(g_pDevice, 20, 0, FW_BOLD, 1, false,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont);
//Create Sprite
D3DXCreateSprite(g_pDevice, &g_pSprite);
//Load Effect
ID3DXBuffer *pErrorMsgs = NULL;
HRESULT hRes = D3DXCreateEffectFromFile(g_pDevice, L"lighting.fx", NULL, NULL, D3DXSHADER_DEBUG, NULL, &g_pEffect, &pErrorMsgs);
if(FAILED(hRes) && (pErrorMsgs != NULL)) //Failed to create Effect
{
MessageBox(NULL, (LPCWSTR)pErrorMsgs->GetBufferPointer(), L"Effect Error", MB_OK);
return E_FAIL;
}
//Load Soldier Mesh
m_soldier.Load("soldier.X");
m_deviceLost = false;
return S_OK;
}
void Application::DeviceLost()
{
//Device lost happens at ALT + TAB and similar events
try
{
g_pFont->OnLostDevice();
g_pSprite->OnLostDevice();
g_pEffect->OnLostDevice();
m_deviceLost = true;
}
catch(...)
{
g_debug << "Error occured in Application::DeviceLost() \n";
}
}
void Application::DeviceGained()
{
try
{
g_pDevice->Reset(&m_present);
g_pFont->OnResetDevice();
g_pSprite->OnResetDevice();
g_pEffect->OnResetDevice();
m_deviceLost = false;
}
catch(...)
{
g_debug << "Error occured in Application::DeviceGained() \n";
}
}
void Application::Update(float deltaTime)
{
try
{
//Check for lost device
HRESULT coop = g_pDevice->TestCooperativeLevel();
if(coop != D3D_OK)
{
if(coop == D3DERR_DEVICELOST)
{
if(m_deviceLost == false)
DeviceLost();
}
else if(coop == D3DERR_DEVICENOTRESET)
{
if(m_deviceLost == true)
DeviceGained();
}
Sleep(100);
return;
}
//Camera Rotation
m_angle += deltaTime;
//Keyboard input
if(KeyDown(VK_ESCAPE))
{
Quit();
}
if(KeyDown(VK_RETURN) && KeyDown(18)) //ALT + RETURN
{
//Switch between windowed mode and fullscreen mode
m_present.Windowed = !m_present.Windowed;
DeviceLost();
DeviceGained();
if(m_present.Windowed)
{
RECT rc = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
SetWindowPos(m_mainWindow, HWND_NOTOPMOST, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_SHOWWINDOW);
UpdateWindow(m_mainWindow);
}
}
}
catch(...)
{
g_debug << "Error in Application::Update() \n";
}
}
void Application::Render()
{
if(!m_deviceLost)
{
try
{
D3DXMATRIX identity, shadow;
D3DXMatrixIdentity(&identity);
//Set ground plane + light position
D3DXPLANE ground(0.0f, 1.0f, 0.0f, 0.0f);
D3DXVECTOR4 lightPos(-20.0f, 75.0f, -120.0f, 0.0f);
//Create the shadow matrix
D3DXMatrixShadow(&shadow, &lightPos, &ground);
//Create Transformation Matrices
D3DXMATRIX view, proj, world;
D3DXMatrixIdentity(&world);
D3DXMatrixLookAtLH(&view, &D3DXVECTOR3(cos(m_angle) * 2.0f, 2.0f, sin(m_angle) * 2.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4.0f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 0.1f, 100.0f);
//Set transformation matrices
g_pDevice->SetTransform(D3DTS_WORLD, &world);
g_pDevice->SetTransform(D3DTS_VIEW, &view);
g_pDevice->SetTransform(D3DTS_PROJECTION, &proj);
g_pEffect->SetMatrix("matVP", &(view * proj));
// Clear the viewport
g_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
// Begin the scene
if(SUCCEEDED(g_pDevice->BeginScene()))
{
//Render Soldier
{
g_pEffect->SetMatrix("matW", &identity);
g_pEffect->SetVector("lightPos", &lightPos);
D3DXHANDLE hTech = g_pEffect->GetTechniqueByName("Lighting");
g_pEffect->SetTechnique(hTech);
g_pEffect->Begin(NULL, NULL);
g_pEffect->BeginPass(0);
m_soldier.Render();
g_pEffect->EndPass();
g_pEffect->End();
}
//Render Shadow
{
g_pEffect->SetMatrix("matW", &shadow);
D3DXHANDLE hTech = g_pEffect->GetTechniqueByName("Shadow");
g_pEffect->SetTechnique(hTech);
g_pEffect->Begin(NULL, NULL);
g_pEffect->BeginPass(0);
m_soldier.Render();
g_pEffect->EndPass();
g_pEffect->End();
}
// End the scene.
g_pDevice->EndScene();
g_pDevice->Present(0, 0, 0, 0);
}
}
catch(...)
{
g_debug << "Error in Application::Render() \n";
}
}
}
void Application::Cleanup()
{
if(g_pSprite != NULL) g_pSprite->Release();
if(g_pFont != NULL) g_pFont->Release();
if(g_pDevice != NULL) g_pDevice->Release();
if(g_pEffect != NULL) g_pEffect->Release();
g_debug << "Application Terminated \n";
}
void Application::Quit()
{
DestroyWindow(m_mainWindow);
PostQuitMessage(0);
}