初始化Direct3D(4)

1.5初始化Direct3D实例

在本例程中,初始化了一个Direct3D应用程序并用黑色填充显示窗口(如图1.7)。

图1.7

所有的应用程序都包含了d3dUtility.h和d3dUtility.cpp这两个文件,它们所包含的函数实现了所有Direct3D应用程序都要去做的一些常见的功能。例如:创建一个窗口、初始化Direct3D、进入程序的消息循环等。

1.5.1d3dUtility.h/cpp

让我们先熟悉一下d3dUtility.h/cpp所提供的函数。d3dUtility.h如下:

#include <d3dx9.h>
    template<typename T>
void safe_release(T obj)
    {
if(obj == NULL)
return;
        obj->Release();
        obj = NULL;
    }
    template<typename T>
void safe_delete(T obj)
    {
if(obj == NULL)
return;
        delete obj;
        obj = NULL;
    }
///////////////////////////////////////////////////////////////////////////////////
    typedef bool (*DISPLAY_FUNC_PTR)(float timeDelta);
bool init_d3d(HINSTANCE instance,            // application instance
int width, int height,        // backbuffer dimensions
bool is_window,                // true - windowed mode, false - full screen mode.
              D3DDEVTYPE device_type,        // HAL or REF
                  IDirect3DDevice9** device);    // the create device
int enter_msg_loop(DISPLAY_FUNC_PTR display);
    LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

init_d3d——初始化一个应用程序主窗口并进行Direct3D的初始化。如果成功,则输出IDirect3DDevice9接口指针。从它的参数我们可以发现,我们能够设置窗口的大小和以窗口模式运行还是全屏模式运行。要知道它实现的细节,请看示例代码。

//-----------------------------------------------------------------------
    // Initialize windows and direct 3D.
    //-----------------------------------------------------------------------
bool init_d3d(HINSTANCE instance,            // application instance
int width, int height,        // backbuffer dimensions
bool is_window,                // true - windowed mode, false - full screen mode.
              D3DDEVTYPE device_type,        // HAL or REF
                  IDirect3DDevice9** device)    // the create device
{
const char* classname = "Direct3D9App";
        WNDCLASS wc;
        wc.style         = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc   = wnd_proc;
        wc.cbClsExtra    = 0;
        wc.cbWndExtra    = 0;
        wc.hInstance     = instance;
        wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        wc.hCursor         = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
        wc.lpszMenuName  = NULL;
        wc.lpszClassName = classname;
if(! RegisterClass(&wc))
        {
            MessageBox(NULL, "RegisterClass() - failed.", NULL, MB_OK);
return false;
        }
        HWND hwnd = CreateWindow(classname, "Direct3D9App", WS_EX_TOPMOST,
                                 0, 0, width, height, NULL, NULL, instance, NULL);
if(hwnd == NULL)
        {
            MessageBox(NULL, "CreateWindow() - failed.", NULL, MB_OK);
return false;
        }
        ShowWindow(hwnd, SW_SHOW);
        UpdateWindow(hwnd);
// initialize D3D
        // step 1: Create the IDirect3D9 object.
        IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if(d3d9 == NULL)
        {
            MessageBox(NULL, "Direct3DCreate9() - failed.", NULL, MB_OK);
return false;
        }
// step 2: check for hardware vertex presentation.
        D3DCAPS9 caps;   
        d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, device_type, &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                        = is_window;
        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.
if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, device_type, hwnd, vp, &d3dpp, device)))
        {
// try again using a 16-bit depth buffer
            d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, device_type, hwnd, vp, &d3dpp, device)))
            {
                d3d9->Release();    // done with d3d9 object
            MessageBox(NULL, "CreateDevice() - failed.", NULL, MB_OK);
return false;
            }
        }
        d3d9->Release();        // done with d3d9 object
return true;
    }

enter_msg_loop——这个函数封装了应用程序的消息循环。它需要输入一个显示函数的函数指针,显示函数为程序中绘制图形的代码块,这样做是为了使显示函数能够在空闲的时候被调用并显示场景,它的实现如下:

//-----------------------------------------------------------------------
    // Enter windows message loop and render game frames if there is no message
    // comes from thread message queue.
    //-----------------------------------------------------------------------
int enter_msg_loop(DISPLAY_FUNC_PTR display)
    {
        MSG msg;
        ZeroMemory(&msg, sizeof(MSG));
// The timeGetTime function retrieves the system time, in milliseconds.
        // The system time is the time elapsed since Windows was started.   
static float last_time = (float) timeGetTime();
while(msg.message != WM_QUIT)
        {
// The PeekMessage function dispatches incoming sent messages, checks the thread message queue for a
            // posted message, and retrieves the message (if any exist).
            //
            // If a message is available, the return value is nonzero.
            // If no messages are available, the return value is zero.
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
else
            {
float curr_time  = (float) timeGetTime();
float time_delta = (curr_time - last_time) * 0.001f;
                display(time_delta);
                last_time = curr_time;
            }
        }
return (int) msg.wParam;
    }

与“time”有关的代码用于计算每次调用显示函数的时间间隔,即是每帧的时间。

safe_release——这个模版函数能方便的释放COM接口并将它们的值设为NULL

safe_delete——这个模版函数能方便的删除一个对象并将指向其的指针设为NULL

wnd_proc——应用程序主窗口的回调函数

1.5.2 实例框架

通过实例框架,我们形成了一种通用的方法去构造示例程序。每一个例程都含有三个函数的实现,当然这不包括回调函数和WinMain主函数。这三个函数用特定的代码实现特定的功能。这三个函数是:

bool setup()——在这个函数里,我们将准备一切该程序需要用到的东西,包括资源的分配,检查设备能力,设置应用程序的状态

void clearup()——这个函数将释放Setup()中分配的资源,如分配的内存。

bool display(float time_delta)——这个函数包含所有与我们绘图和显示有关的代码。参数timeDelta为每一帧的间隔时间,用来控制每秒的帧数。

这个示例程序将创建并初始化一个Direct3D应用程序,并用黑色填充屏幕。注意,我们使用了通用函数简化了初始化过程。

/*********************************************************************************
    PURPOISE:
        Demonstrates how to initialize Direct3D, how to use framework functions,
        and how to clear the screen to black.    
    *********************************************************************************/
    #include "D3DUtility.h"
    IDirect3DDevice9* g_device = NULL;
bool setup()
    {
// nothing to setup in this sample
return true;
    }
void cleanup()
    {
// nothing to cleanup in this sample
}
bool display(float timeDelta)
    {
// Only use Device methods if we have a valid device.
if(g_device == NULL)
return false;
// 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.
    g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
// swap the back and front buffers
    g_device->Present(NULL, NULL, NULL, NULL);
return true;
    }
    LRESULT CALLBACK wnd_proc(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);
    }
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show)
    {
if(! init_d3d(inst, 640, 480, true, D3DDEVTYPE_HAL, &g_device))
        {
            MessageBox(NULL, "init_d3d() - failed.", 0, MB_OK);
return 0;
        }
if(! setup())
        {
            MessageBox(NULL, "Steup() - failed.", 0, MB_OK);
return 0;
        }
        enter_msg_loop(display);
        cleanup();
        g_device->Release();
return 0;
    }

Display方法调用了IDirect3DDevice::Clear方法,分别用黑色和1.0填充后备表面和深度/模版缓冲。如果应用程序不停止的话,我们会一直执行这个操作。IDirect3DDevice::Clear声明如下:

HRESULT Clear( DWORD Count, CONST D3DRECT * pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil );

Count——pRects 组中的矩形的个数

pRects——将要清除的屏幕矩形的数组,这使我们可以清除屏幕的某一部分

Flags——指定在哪些表面上执行清除表面的操作

         D3DCLEAR_TARGET——目的表面,通常为后备表面

         D3DCLEAR_ZBUFFER——深度缓冲

         D3DCLEAR_STENCIL——模版缓冲

Color——使用什么颜色填充清除的表面

Z——设置深度缓冲的值

Stencil——设置模版缓冲的值

屏幕被填充后,要调用IDirecte3DDevice9::Present方法进行后备表面的交换。

Windows 回调函数为一组事件集,即,我们可按ESC键让程序退出。

最后,WinMain按如下步骤运行:

1. 初始化主显示窗口和Direct3D

2. 调用setup进行程序的准备工作

3. 使用display函数作为参数进入消息循环

4. 清除应用程序最后释放IDirecte3DDevice9对象

注意:不要忘了在你的工程中加入d3d9.lib、d3dx9.lib、winmm.lib这三个库!

下载源码

posted @ 2008-03-16 13:24  至尊王者  阅读(1568)  评论(0编辑  收藏  举报