65.9K
CodeProject 正在变化。 阅读更多。
Home

DirectX 9 SDK with .NET Forms (C++)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (2投票s)

2009年9月6日

CPOL

5分钟阅读

viewsIcon

52974

downloadIcon

785

展示了如何将 DirectX 渲染窗口实现到 .NET Form 中。

引言

在互联网上搜索时,可以清楚地发现,找到一个像样的教程来实现 DirectX 9.0c 到 .NET Forms 是几乎不可能的。即使你找到了,很可能它也是为 C# 设计的。

如果你想知道为什么程序员会想要这样做,这是我的个人回答:

与 Win32 API 相比,.NET Forms 在项目中更容易包含,管理起来也更方便。唯一的缺点是 .NET Forms 是为 C# 设计的,而不是 C++。但是,通过几行简单的代码,你可以修改你的程序,使其能够利用 C# 库(特别是 .NET Forms)。如果你试图构建自己的关卡编辑器,而不想处理 Win32 带来的混乱,这会是理想的选择。

如果你正在阅读本教程,那么我期望你知道如何做到以下几点:

  • 具备 C++ 的中级知识。
  • 了解如何使用 DirectX9 SDK,如果不知道:www.directxtutorial.com
  • 我还假定你拥有自己的 Visual Studio。 (注意:我使用的是 Microsoft 的 Visual C++ Express Edition;如果你使用的是 Visual Studio 2005,可能会有一些细微的差别。)
  • 此外,我假定你的电脑上已安装 DirectX SDK。

编写代码

首先,你需要配置 C++ 编译器,使其能够使用 C# 的库。要做到这一点,请转到菜单栏,选择“Project”,然后选择“Properties”。会弹出一个窗口,转到“Configuration Properties”并选择“General”。现在,转到标记为“Common Language Runtime Support”的框,并将其更改为/clr。这样我们就可以在代码中使用 C# 的库和命名空间了。

创建一个新的 C++ 文件作为程序的入口点(我将称之为main.cpp)。然后,创建一个新的 Windows Form 作为头文件(在 Visual C++ -> UI 下)(我将称之为DX9Forms.hDX9Forms.cpp)。将 Windows Form 添加到你的头文件中应该已经创建了头文件(*.h*)和代码文件(*.cpp*)。如果没有,请添加一个代码文件并记住包含你的 Form。现在,开始编写这个程序的主入口点,我将使用WinMain()

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                   LPSTR lpCmdLine, int nCmdShow)

现在,包含你所有的头文件:

#include "iostream"
#include "windows.h"
#include "DX9Form.h"
#include "d3d9.h"
using namespace Forms_DX9;

最后,你只需要一行代码来运行 Form:

Application::Run(gcnew DX9Form());

稍后我们将修改 DX9Form 类的构造函数;目前请保持原样。

在整个本教程的过程中,main.cpp 的内容不会有太大变化。

//--------------------------------
//File: main.cpp
//--------------------------------

#include "iostream"
#include "windows.h"
#include "DX9Form.h"
#include "d3d9.h"

//Use the Forms_DX9 namespace containing the DX9Form class

using namespace Forms_DX9;

//--------------------------------
// Main Program
//--------------------------------

//Entry Point
int WINAPI WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow)
{
    //Run the Application
    Application::Run(gcnew DX9Form());
}

转到“DX9Form.h”文件,你应该处于 Designer 视图。在你的 Form 中创建一个 Panel(这个程序不是必需的,但我发现使用 Panel 的坐标比手动输入坐标更容易)。

现在,查看“DX9Form.h”的代码。大部分代码已经由 Visual Studio 生成。(如果你以前从未使用过 C++ 中的 Forms,这可能会有点压倒性;我建议你稍微尝试一下,以便熟悉使用它。)

#pragma once 下输入此内容:

#using "System.dll"
#include <d3d9.h>
#include <windows.h>
#pragma comment (lib, "d3d9.lib")

正如你可能看到的,我们正在使用System.dll,一个 C# 库。

现在我们需要定义两个全局变量,一个用于 LPDIRECT3D9,另一个用于 LPDIRECT3DDEVICE9

然而,如果直接将它们用作传统的全局变量,程序将无法编译,所以将它们都放入一个名为 'globals' 的命名空间中,并将它们定义为静态成员。

namespace globals
{
    static LPDIRECT3DDEVICE9 d3ddev;
    static LPDIRECT3D9 d3d;
}

using namespace globals;

现在我们需要修改由 Visual Studio 生成的 DX9Forms 类的构造函数。

protected:

    bool mReleased;
    HWND hDX9;

public:

DX9Form(HINSTANCE hInstance)
{

    mReleased = false;
    mInit = false;

    InitializeComponent();

    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = NULL;
    wc.lpszClassName = "WindowClass";

    RegisterClassEx(&wc);

    hDX9 = CreateWindowEx(NULL, "WindowClass", NULL, WS_CHILD,
            this->panel1->ClientRectangle.X, this->panel1->ClientRectangle.Y,
            this->panel1->Width, this->panel1->Height,
            (HWND)(void*)this->panel1->Handle.ToPointer(),
            NULL,
            hInstance,
            NULL);

    ShowWindow(hDX9, SW_SHOW); 
}

在这段代码中,我们修改了构造函数,并在 DX9Form 类中添加了一个布尔值和一个指向我们渲染窗口的 Window Handle(hDX9)。我们使用 panel1 来指定窗口的创建位置和大小;如果你做过 Win32 API 编程,这应该看起来很熟悉。

现在我们需要实现两个函数:initD3D()render()initD3D() 创建一个 DirectX 设备。render() 清除窗口并渲染一帧。

以下是定义:

protected: void initD3D(HWND hHandle);

public : static void render();

DX9Forms.cpp 中编写这些函数:

//File: DX9Form.cpp
#include "DX9Form.h"

using namespace Forms_DX9;
using namespace globals;

void DX9Form::initD3D(HWND hHandle)
{

    globals::d3d = Direct3DCreate9(D3D_SDK_VERSION);
    // create the Direct3D interface

    D3DPRESENT_PARAMETERS d3dpp;
    // create a struct to hold various device information

    ZeroMemory(&d3dpp, sizeof(d3dpp)); // clear out the struct for use

    d3dpp.Windowed = true; // program windowed, not fullscreen

    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames

    d3dpp.hDeviceWindow = hHandle;
    // set the window to be used by Direct3D

    // create a device class using this information
    // and information from the d3dpp stuct
    globals::d3d->CreateDevice(D3DADAPTER_DEFAULT,
            D3DDEVTYPE_HAL,
            hHandle,
            D3DCREATE_SOFTWARE_VERTEXPROCESSING,
            &d3dpp,
            &globals::d3ddev);
}

void DX9Form::render(void)
{

    // clear the window to a deep blue
    globals::d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, 
                              D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
    globals::d3ddev->BeginScene(); // begins the 3D scene

    // do 3D rendering on the back buffer here
    globals::d3ddev->EndScene(); // ends the 3D scene
    globals::d3ddev->Present(NULL, NULL, NULL, NULL);
    // displays the created frame
}

现在我们需要编写窗口协议;当调用 WM_PAINT 消息时,DirectX 设备将进行渲染。

//File: DX9Form.cpp

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    switch (message)
    {
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        }
        break;
        case WM_PAINT:
        {
            DX9Form::render();
            return 0;
        }
        break;
    }
    return DefWindowProc (hWnd, message, wParam, lParam);
}

事件

我们快完成了。现在我们只需要定义两个事件;一个将在 Form 首次显示时触发并调用 initD3D(),另一个将在 Form 关闭时触发并释放 d3ddevd3d

要创建一个事件,请在 Form 设计器中选择你的 Form,然后转到 Properties 窗口,在 Properties 窗口中,转到 Events(由闪电图标表示)。要创建一个新事件,只需双击你希望事件触发的旁边的框(在这种情况下是 Shown)。事件创建后,你应该会被重定向到相应的代码。

现在,像对待函数一样对待该事件,并在大括号之间编写你的代码。你需要调用 initD3D() 并渲染第一帧。

private: System::Void DX9Form_Shown(System::Object^ sender, System::EventArgs^ e) 
{ 
    initD3D(hDX9);
    render();
}

现在为 FormClosing 创建另一个事件;我们需要释放 d3ddevd3d

private: System::Void DX9Form_FormClosing(System::Object^ sender, 
                 System::Windows::Forms::FormClosingEventArgs^ e) 
{
    if (!mReleased)
    {
        globals::d3ddev->Release();
        globals::d3d->Release();
        mReleased = true;
    }
}

最后,我们需要调整 main.cpp 中的代码,因为我们已经改变了 DX9Form 的构造函数。

//new line: Application::Run(gcnew DX9Form(hInstance));
//--------------------------------
//File: main.cpp
//--------------------------------

#include "iostream"
#include "windows.h"
#include "DX9Form.h"
#include "d3d9.h"

//Use the Forms_DX9 namespace containing the DX9Form class
using namespace Forms_DX9;

//--------------------------------
// Main Program
//--------------------------------

//Entry Point
int WINAPI WinMain(HINSTANCE hInstance,
            HINSTANCE hPrevInstance,
            LPSTR lpCmdLine,
            int nCmdShow)
{
    //Run the Application
    Application::Run(gcnew DX9Form(hInstance));
}

编译并运行它;它应该可以正常工作;如果不行,我已经包含了可以下载的源代码。

© . All rights reserved.