zoukankan      html  css  js  c++  java
  • 初始化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这三个库!

    下载源码

  • 相关阅读:
    [Swift]LeetCode241. 为运算表达式设计优先级 | Different Ways to Add Parentheses
    [Swift]LeetCode240. 搜索二维矩阵 II | Search a 2D Matrix II
    使用ADO.NET对SQL Server数据库进行訪问
    JavaScript中面向对象那点事
    总结文件操作函数(二)-C语言
    UVa
    深入研究java.lang.Object类
    TCP/IP具体解释--TCP/IP可靠的原理 滑动窗体 拥塞窗体
    W5500EVB UDP模式的測试与理解
    仿新浪首页、主题、详情页,纯html静态页面
  • 原文地址:https://www.cnblogs.com/flying_bat/p/1108364.html
Copyright © 2011-2022 走看看