directdraw:通向DirectDraw的捷径

作者:Johnny Watson 译者:蓝色feel From:www.x-temple.com

    这篇文章描述了怎样通过使用DirectX SDK中通用库文件来轻松地建立个 DirectDraw对象及其显示表面(surface)(这篇文章)对那些想要在不破坏原应用架构情况下快速掌握它来做些事人特别有帮助,请注意事实上这些类中抽象了相当多且复杂事物因此我强烈地推荐你在掌握它们功能同时尽量关注下其底层实现这样有助于你尽快掌握它们工作方式

1.DirectDraw安装 

    在本文中我假定你拥有微软公司 Visual C , 和 DirectX 8.1 SDK如果没有,就快去准备份吧 首先启动你 Visual C, 创建个新 Win32 应用工程 然后进入 你 DirectX SDK 文件夹中 multimedia\common\ 目录 , 拷贝 dxutil.h 和 ddutil.h 至你新建工程目录下 然后将你 DirectX SDK文件夹中 \multimedia\common\src目录下dxutil.cpp 和 ddutil.cpp 也拷贝至你新建工程目录下把 4个文件加入你工程, 然后连接上下列库文件: dxguid.lib ddraw.lib,winmm.lib现在你创建个新 C源文件文件, 而且也把它加入你工程 这些是整个教程中我们将会用到工作文件

2.DirectDraw代码

    既然我们已经准备好了, 让我们开始写些代码什么实在东西吧!



# WIN32_LEAN_AND_MEAN

# <windows.h>

# "dxutil.h"
# "ddutil.h"


     这是标准代码# WIN32_LEAN_AND_MEAN,这句是指示编译器不要包含和MFC相关操作( 只是个好练习——如果你不在使用 MFC) 然后我们包括 dxutil.h 和 ddutil.h这是两个很有用头文件 他们能够使你以种比通常DirectX编程更轻松方式来工作



//globals

bool g_bActive = false;

CDisplay *g_pDisplay = NULL;
CSurface *g_pText = NULL;


//function prototypes

bool InitDD(HWND);
void CleanUp;
void GameLoop;


    代码自身说很清楚不是吗?我们个全局变量g_bActive个让我们应用知道是否应该运行游戏标志 如果我们没有这个全局变量, 我们应用可能在它自己被注销的後还在尝试着在我们已经创建 DirectDraw 表面上画点儿什么呢!虽然这通常是个在结束时候出现个不大问题但它会导致个非法操作我们并不想那样,不是吗? g_pDisplay 是我们显示对象CDisplay 在 ddutil.h 中是最主要它控制着我们前后缓冲区并提供些针对该缓冲区功能,如访问及存储缓冲区将表面写入缓冲区创建个表面等等 g_pText 是个文本表面 我们将会在这个表面 (你或许已经有所理解 ) 的上写文本, 然后将它传送到我们屏幕的上 注意它们两者都是指向对象指针, 而且被化为NULL
     现在来看看原型 InitDD 只是用来化 DirectDraw 多亏了 DirectDraw 通用文件(common files),这还算是个简单( 但是晚些时候我们才会接触到它们) CleanUp了对象 g_pDisplay 析构来释放 ( release)我们所创建DirectDraw对象及其表面很明显 GameLoop 则是将来用来放你游戏地方


    LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg,
                                WPARAM wParam, LPARAM lParam)
    {
        switch(uMsg)
        {
             WM_CREATE:
                InitDD(hWnd);
                g_bActive=true;
                ;
             WM_CLOSE:
                g_bActive=false;
                CleanUp;
                DestroyWindow(hWnd);
                ;
             WM_DESTROY:
                PostQuitMessage(0);
                ;
             WM_MOVE:
                g_pDisplay->UpdateBounds;
                ;
             WM_SIZE:
                g_pDisplay->UpdateBounds;
                ;
            default:
                 DefWindowProc(hWnd,uMsg,wParam,lParam);
                ;
        }
         0;
    }


     这里是标准 Windows 消息处理机制代码 当产生 WM_CREATE 消息时我们化 DirectDraw, 并将我们全局变量 g_bActive 设定为true这样就可以执行游戏循环 GameLoop当消息 WM_CLOSE 被传递时候,我们就把全局变量 g_bActive 设定为 false ( 这样我们应用就不会在它自己被注销的後还在尝试着向我们已经创建 DirectDraw 表面上写数据了)然后 CleanUp ,最终注销我们窗口处理 WM_MOVE 和 WM_SIZE 事件非常重要若处理不当DirectDraw 将不顾窗口本身是否已经被移动或重新设定其大小仍然在屏幕上原来位置上继续作画从而造成

    bool InitDD(HWND hWnd)
    {
        //dd init code
        g_pDisplay = CDisplay;

        (FAILED(g_pDisplay->CreateWindowedDisplay(hWnd,640,480)))
        {
            MessageBox(NULL,"Failed to Initialize DirectDraw",
                        "DirectDraw Initialization
            Failure",MB_OK|MB_ICONERROR);
             false;
        }
         true;
    }


     该死 InitDD ... 不过别急它只不过几行而已! 这儿就是通常那些个库文件用武的地现在那些妨碍我们建立 DirectDraw 对象冗长玩意儿已被我们轻松搞定了而你将会再次注意到它挺麻烦不是吗?如果你真不想弄明白那些惹人烦玩意儿那么至少你得知道个梗概吧!如果你得回去改变协作等级什么它也许帮得上忙注意到这是个返回 bool 值, 因此如果你不厌倦话, 你应当做检查(基于你所可以理解篇幅问题的原因我决定在这篇文章中省略)

    void CleanUp
    {
        SAFE_DELETE(g_pDisplay);
    }


     真是够简单! 这个了在 dxutil.h 中定义宏 SAFE_DELETE 来删除我们显示对象同时析构

    void MainLoop
    {
        g_pDisplay->CreateSurfaceFromText(&g_pText,NULL,"DDraw using Common Files",
        RGB(0,0,0),RGB(0,255,0));

        g_pDisplay->Clear(0);
        g_pDisplay->Blt(0,0,g_pText,0);
        g_pDisplay->Present;

        g_pText->Destroy;
    }


     这儿就是你将来放游戏地方 为了要给你个表面对象(surface object)如何工作例子我们已经做了个简单文本表面而且写了些文本上去注意我们在最後释放(destroy)了全局指针变量 g_pText否则每次循环它都将被重新创建次,直到吃光最后点儿内存

     WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        LPSTR lpCmdLine, iShowCmd)
    {
        WNDCLASSEX wc;
        HWND hWnd;
        MSG lpMsg;

        wc.cbClsExtra=0;
        wc.cbSize=(WNDCLASSEX);
        wc.cbWndExtra=0;
        wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
        wc.hCursor=LoadCursor(NULL,IDC_ARROW);
        wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
        wc.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
        wc.hInstance=hInstance;
        wc.lpfnWndProc=WndProc;
        wc.lpszClassName="wc";
        wc.lpszMenuName=0;
        wc.style=CS_HREDRAW|CS_VREDRAW;

        (!RegisterClassEx(&wc))
        {
            MessageBox(NULL,"Couldn't Register Window Class",
                        "Window Class Registration
                        Failure",MB_OK|MB_ICONERROR);
             0;
        }

        hWnd = CreateWindowEx(NULL,"wc","DirectDraw Common Files in Action",
                                WS_POPUPWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,640,480,0,0,
                                hInstance,0);
        (hWnd NULL)
        {
            MessageBox(NULL,"Failed to Create Window","Window Creation
                        Failure", MB_OK|MB_ICONERROR);
             0;
        }

        ShowWindow(hWnd,SW_SHOW);
        UpdateWindow(hWnd);

        while(lpMsg.message != WM_QUIT)
        {
            (PeekMessage(&lpMsg,0,0,0,PM_REMOVE))
            {
                TranslateMessage(&lpMsg);
                DispatchMessage(&lpMsg);
            }
             (g_bActive)
            {
                MainLoop;
            }
        }
         lpMsg.wParam;
    }


     这就是我们应用中最长——WinMain像往常样, 我们创建个窗口类,然后再创建个窗口显示及更新它, 并且进入消息循环看上去主循环区别於平常是我们不想要主游戏进程被消息处理所干扰我们通过观察全局指针变量 g_bActive 状态 来判断该时刻游戏循环是否安全以及在循环中向屏幕上传送(blit)图象而最后全部结束时候我们返回个长指针 lpMsg.wParam.( 至于为什么我实在是不敢肯定可其它每个 Win32 应用都是这样做就是这样)
     实在是太简单了,嗯!?我们只用了 135 行编码就已经将对象写到了屏幕上自由地去进步探究这些类结构,做些载入位图至表面实验等等这是使用 DDraw个很棒捷径它能在不牺牲控制 (你总是能在你需要时候回去编辑那些类) 和性能情况下而使事情变得容易些件事得要注意是在计算机上如果我使用了这个结构却不绘制任何对象到屏幕上, 应用将会锁定( 对这就是我为什麽把文本输出也包括在这里) 如果我说做游戏很大程度上就是把对象传送( blit )到屏幕上大概不会引起什么争议(除非又有些新艺术风格诞生了)
Tags:  directdrawerror directdraw不可用 directdraw加速 directdraw

延伸阅读

最新评论

发表评论