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






4.67/5 (2投票s)
展示了如何将 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.h和DX9Forms.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 关闭时触发并释放 d3ddev
和 d3d
。
要创建一个事件,请在 Form 设计器中选择你的 Form,然后转到 Properties 窗口,在 Properties 窗口中,转到 Events(由闪电图标表示)。要创建一个新事件,只需双击你希望事件触发的旁边的框(在这种情况下是 Shown
)。事件创建后,你应该会被重定向到相应的代码。
现在,像对待函数一样对待该事件,并在大括号之间编写你的代码。你需要调用 initD3D()
并渲染第一帧。
private: System::Void DX9Form_Shown(System::Object^ sender, System::EventArgs^ e)
{
initD3D(hDX9);
render();
}
现在为 FormClosing
创建另一个事件;我们需要释放 d3ddev
和 d3d
。
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));
}
编译并运行它;它应该可以正常工作;如果不行,我已经包含了可以下载的源代码。