微软的的东西还是很庞大,很复杂,很不好用....但是看到directX自带的那些sample的时候,还是果断呆掉了,我想说,我也要做出这个!
接着是花了将近一天的时间完成来搞定微软的这一套图形开发的环境。
准备工作:
win7旗舰版 vs2008 express(比较轻量) directX 9.0SDK 网上能下到得最新版的是2010年的那个版本,Microsoft DirectX SDK (June 2010),微软官网下载不了。
接下来可以动手了。
1)先把VS2008装好,下载好镜像之后大小不到1G。
用驱动精灵装载,然后运行,选择visual c++,大概20分钟搞定。
2)装directX的sdk,500多M,双击运行,一路下一步就可以。
3)新建一个win32应用程序项目,添加sdk的头文件和库文件。
Tools-Options-Project and Solutions-VC++ Directories里面
添加DirectX安装目录下的Include到Include
添加DirectX安装目录下的Lib/X86到库包含目录
项目上右击->属性->连接器->输入->附加依赖项中添加d3d9.lib d3dx9.lib winmm.lib
4)代码清单
新建一个main.cpp,代码如下:
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: d3dinit.cpp
//
// Author: Frank Luna (C) All Rights Reserved
//
// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0
//
// Desc: Demonstrates how to initialize Direct3D, how to use the book's framework
// functions, and how to clear the screen to black. Note that the Direct3D
// initialization code is in the d3dUtility.h/.cpp files.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#include "d3dUtility.h"
//
// Globals
//
IDirect3DDevice9* Device = 0;
//
// Framework Functions
//
bool Setup()
{
// Nothing to setup in this sample.
return true;
}
void Cleanup()
{
// Nothing to cleanup in this sample.
}
bool Display(float timeDelta)
{
if( Device ) // Only use Device methods if we have a valid device.
{
// Instruct the device to set each pixel on the back buffer black -
// D3DCLEAR_TARGET: 0x00000000 (black) - and to set each pixel on
// the depth buffer to a value of 1.0 - D3DCLEAR_ZBUFFER: 1.0f.
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
// Swap the back and front buffers.
Device->Present(0, 0, 0, 0);
}
return true;
}
//
// WndProc
//
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_DESTROY:
::PostQuitMessage(0);
break;
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
::DestroyWindow(hwnd);
break;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
//
// WinMain
//
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE prevInstance,
PSTR cmdLine,
int showCmd)
{
if(!d3d::InitD3D(hinstance,
640, 480, true, D3DDEVTYPE_HAL, &Device))
{
::MessageBox(0, "InitD3D() - FAILED", 0, 0);
return 0;
}
if(!Setup())
{
::MessageBox(0, "Setup() - FAILED", 0, 0);
return 0;
}
d3d::EnterMsgLoop( Display );
Cleanup();
Device->Release();
return 0;
}
代码说明:
Setup: 程序设置和初始化都放在这里,比如资源分配,检查设备性能等;
Cleanup:用于释放在Setup函数中分配的资源;
Display:在该函数中实现全部的绘制代码以及相邻帧之间应执行的操作。
新建d3dUtility类,代码如下。
d3dUtility.h
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: d3dUtility.h // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Provides utility functions for simplifying common tasks. // ////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef __d3dUtilityH__ #define __d3dUtilityH__ #include <d3dx9.h> #include <string> namespace d3d { bool InitD3D( HINSTANCE hInstance, // [in] Application instance. int width, int height, // [in] Backbuffer dimensions. bool windowed, // [in] Windowed (true)or full screen (false). D3DDEVTYPE deviceType, // [in] HAL or REF IDirect3DDevice9** device);// [out]The created device. int EnterMsgLoop( bool (*ptr_display)(float timeDelta)); LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); template<class T> void Release(T t) { if( t ) { t->Release(); t = 0; } } template<class T> void Delete(T t) { if( t ) { delete t; t = 0; } } } #endif // __d3dUtilityH__
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: d3dUtility.cpp
//
// Author: Frank Luna (C) All Rights Reserved
//
// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0
//
// Desc: Provides utility functions for simplifying common tasks.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#include "d3dUtility.h"
bool d3d::InitD3D(
HINSTANCE hInstance,
int width, int height,
bool windowed,
D3DDEVTYPE deviceType,
IDirect3DDevice9** device)
{
//
// Create the main application window.
//
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)d3d::WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "Direct3D9App";
if( !RegisterClass(&wc) )
{
::MessageBox(0, "RegisterClass() - FAILED", 0, 0);
return false;
}
HWND hwnd = 0;
hwnd = ::CreateWindow("Direct3D9App", "Direct3D9App",
WS_EX_TOPMOST,
0, 0, width, height,
0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/);
if( !hwnd )
{
::MessageBox(0, "CreateWindow() - FAILED", 0, 0);
return false;
}
::ShowWindow(hwnd, SW_SHOW);
::UpdateWindow(hwnd);
//
// Init D3D:
//
HRESULT hr = 0;
// Step 1: Create the IDirect3D9 object.
IDirect3D9* d3d9 = 0;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if( !d3d9 )
{
::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
return false;
}
// Step 2: Check for hardware vp.
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
int vp = 0;
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
// Step 3: Fill out the D3DPRESENT_PARAMETERS structure.
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = windowed;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// Step 4: Create the device.
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT, // primary adapter
deviceType, // device type
hwnd, // window associated with device
vp, // vertex processing
&d3dpp, // present parameters
device); // return created device
if( FAILED(hr) )
{
// try again using a 16-bit depth buffer
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT,
deviceType,
hwnd,
vp,
&d3dpp,
device);
if( FAILED(hr) )
{
d3d9->Release(); // done with d3d9 object
::MessageBox(0, "CreateDevice() - FAILED", 0, 0);
return false;
}
}
d3d9->Release(); // done with d3d9 object
return true;
}
int d3d::EnterMsgLoop( bool (*ptr_display)(float timeDelta) )
{
MSG msg;
::ZeroMemory(&msg, sizeof(MSG));
static float lastTime = (float)timeGetTime();
while(msg.message != WM_QUIT)
{
if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else
{
float currTime = (float)timeGetTime();
float timeDelta = (currTime - lastTime)*0.001f;
ptr_display(timeDelta);
lastTime = currTime;
}
}
return msg.wParam;
}
代码说明:
initD3D:对应用程序主窗口进行了初始化并执行Direct3D的初始化过程。
EnterMsgLoop:封装应用程序的消息循环。
Release:模版函数,为了方便地释放COM接口并将其设置为NULL;
Delete:模版函数,为了方便地删除堆中的对象,并将对应的指针赋值为NULL;
WndProc:应用程序主窗口的窗口过程函数。
确认和编译,运行,结果如下:
6)运行一下sdk中的sample
找到sdk中的sample文件夹,选一个对应得vs2008项目文件,例如这个MultiAnimation。
打开之后直接F5,编译运行。如果能够编译成功,那么环境可以确定配置成功了。
1)首先得确认sdk和vs的版本,理论上vs2008或者vs2005会比较好一些,之前我一直用的是2010,编译的时候总是出bug,无解。
sdk最好选最新的版本,主要是文档比较齐全。
2)遇到无法解释某个函数或变量,Undefined reference of ....
检查对应的库或头文件是否包含进来。
3)编译会提示cannot convert wchar to LPCSTR之类的提示.这个是因为使用了Unicode的原因(在DirectX的示例文件中都使用了Unicode).解决方案有下面几种:
-按alt-f7打开配置文件,在Configuration Property中的General菜单中,Character Set选择Not set,把所有的字符串前面的L都取消.因为L".."是宏(具体参见MSDN)
-如果想继续使用Unicode,可以使用下面的方法:把Character Set选择为Unicode,所有的字符串都加入L"..."作为Unicode表示,这样有个好处是如果你的软件要支持多种语言这是比较方便的.
Dire