《Direct3D中的2D编程》讲如何使用Direct3D来实现被淘汰掉的directdraw所能实现的功能
即讲了如何把已淘汰的DirectDraw里实现的功能转化为Direct3D的等价形式
《Direct3D中的2D编程》用的已经是很古老的DX8,讲当微软将directdraw从DX8中去掉时,那些游戏程序员要如何从directdraw中迁移到directx3D中去绘制2D图形
本人试验环境:win10, vs2019 社区版,下载安装 Microsoft DirectX SDK (June 2010)
因为下载的是DX2010, 而此书作者用的是DX8,懒得再折腾在本机中换成DX8,于是做了下面这样一个小试验,最后编译通过
===============当时安装Microsoft DirectX SDK 2010的注意事项===================================
Microsoft DirectX SDK 2010 版本下载 http://www.microsoft.com/en-us/download/details.aspx?id=6812
Version:
Date Published:
9.29.1962
6/7/2010
File name:
File size:
DXSDK_Jun10.exe
571.7 MB
下载好后,先安装Microsoft DirectX SDK (June 2010),安装包名字叫DXSDK_Jun10.exe,
如果安装完毕前出错,则卸载电脑中vc++2010的86和x64 redistribution (10.0.xxx ,xxx 高于30319,大概就是这个数字,总之开头是30,后面3位数记不清),再重新安装一遍Microsoft DirectX SDK (June 2010) ,
然后在VS2019的编译按钮旁边,下拉框选择【Debug】 【x86】,然后点击左侧栏的项目名称,打开 项目-属性-配置属性-VC++目录 (或直接按ALT+F7 打开VC++目录)
把下面两个目录分别添加进包含目录和库目录,注意前提是 Microsoft DirectX SDK (June 2010)安装包一定要安装在D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)
包含目录:D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include;
库目录: D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86;
原因:编译时vs2019需要寻找的链接文件 d3dx9.lib 和d3d9.lib 就在D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86 目录下
而编译时vs2019需要包含的头文件 d3d9.h (direct3D的头文件)就在 D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include 目录下
==========================================================================================
找来《Direct3D中的2D编程》一书的随书源码的第一个例子程序,编译,一堆报错,好吧,于是开始修改例子源码
// WindowsProject1.cpp : 定义应用程序的入口点。
//来自于《Direct3D中的2D编程》一书的随书源码 D:\C++入门2021.12.29\游戏编程入门第4版及随书源码\Direct3D中的2D编程\2DIn3D\chap01\Example01_1
//Example1_1
//main.cpp
//Ernest Pazera
//04OCT2001
//TGO-01-C
//Libs: d3d8.lib (这里表示作者用的是DX8)
//该书用的是DX8,无法编译通过,会报错,需修改源代码中以下这些内容
// 头文件#include "d3d8.h" 修改为 #include "d3d9.h" //include direct3d9 stuff
//添加 #pragma comment(lib,"d3d9.lib")
// 将源码中 Direct3DCreate8(D3D_SDK_VERSION) 改为 Direct3DCreate9(D3D_SDK_VERSION)
// 将三处字符串中的IDirect3D8 都改为 IDirect3D9,这样程序运行结果会在输出的文本文件中显示是IDirect3D9 对象产生了,释放了
// 另外,按ALT+F7 配置属性-高级-字符集中将 Unicode字符集改为多字节字符集
//把D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include; 添加到项目属性-VC++目录的包含目录中
//把D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86; 添加到项目属性-VC++目录的库目录中
// 特别注意:如果你编译时候选择【x64】,那么应该需要把 D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x64; 添加到项目属性-VC++目录的库目录中
//如果你选择【release】编译,也需要同样进行VC++目录中的包含目录和库目录的设置,方法同上
修改完毕,此时无任何语法错误显示,且点击能顺利编译链接成功的源码如下:
#include <windows.h> //include windows stuff
#include <stdio.h> //standard input/output
#include "d3d9.h" //include direct3d9 stuff
#pragma comment(lib,"d3d9.lib") // 一定要加这一句,否则报错: LNK2019 无法解析的外部符号 _Direct3DCreate9@4,函数 "void __cdecl Prog_Init(void)" (?Prog_Init@@YAXXZ) 中引用了该符号 WindowsProject1 D:\c++_test\2DIn3D\WindowsProject1\WindowsProject1.obj 1
#pragma warning( disable : 4996)
//或将pragma warning( disable : 4996)替换为 #define _CRT_SECURE_NO_WARNINGS
//用以解决error C4996: 'freopen': This function or variable may be unsafe. Consider using freopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. 的安全检查错误的方法
//参考这篇帖子 https://blog.csdn.net/dan15188387481/article/details/49622783
//constants
//window class name
const char* WINDOWCLASS = "3D42DGP";
//window title
const char* WINDOWTITLE = "Example 1.1 (TGO-01-C): Creating and Destroying an IDirect3D8 object";
//globals
//instance handle
HINSTANCE g_hInstance = NULL;
//window handle
HWND g_hWnd = NULL;
//IDirect3D8 pointer
IDirect3D9* g_pd3d = NULL;
//function prototypes
//winmain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
//window procedure
LRESULT CALLBACK TheWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//initialization
void Prog_Init();
//clean up
void Prog_Done();
//window procedure
LRESULT CALLBACK TheWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
//which message did we get?
switch (uMsg)
{
case WM_DESTROY: //window being destroyed
{
//quit
PostQuitMessage(0);
//message handled, return 0
return (0);
} break;
default: //all other messages, send to default handler
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
}
}
//winmain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
//grab instance handle
g_hInstance = hInstance;
//redirect stderr and stdout output
freopen("stderr.txt", "w", stderr); // 添加 #pragma warning( disable : 4996),否则vs2019会抱怨,说你用的函数不够安全,需要用添加_s版本的同名函数
freopen("stdout.txt", "w", stdout); // 添加 #pragma warning( disable : 4996),否则vs2019会抱怨,说你用的函数不够安全,需要用添加_s版本的同名函数
//fill in window class
WNDCLASSEX wc;
wc.cbClsExtra = 0; //no extra class information
wc.cbSize = sizeof(WNDCLASSEX); //size of structure
wc.cbWndExtra = 0; //no extra window information
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //black brush
wc.hCursor = NULL; //no cursor
wc.hIcon = NULL; //no icon
wc.hIconSm = NULL; //no small icon
wc.hInstance = g_hInstance; //instance handle
wc.lpfnWndProc = TheWindowProc; //window procedure
wc.lpszClassName = WINDOWCLASS; //name of class
wc.lpszMenuName = NULL; //no menu
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC; //class styles
//register window class
RegisterClassEx(&wc);
//create window
g_hWnd = CreateWindowEx(0, WINDOWCLASS, WINDOWTITLE, WS_OVERLAPPEDWINDOW, 0, 0, 320, 240, NULL, NULL, g_hInstance, NULL);
//show the window
ShowWindow(g_hWnd, nShowCmd);
//initialization
Prog_Init();
MSG msg;
//message pump
for (; ; )
{
//check for a message
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
//message exists
//check for quit message
if (msg.message == WM_QUIT) break;
//translate the message
TranslateMessage(&msg);
//dispatch the message
DispatchMessage(&msg);
}
}
//clean up
Prog_Done();
//exit
return (msg.wParam);
}
//initialization
void Prog_Init()
{
//create the IDirect3D8 object
g_pd3d = Direct3DCreate9(D3D_SDK_VERSION);
//error check
if (g_pd3d)
{
//success
fprintf(stdout, "IDirect3D9 object created successfully.\n");
}
else
{
//failure
fprintf(stderr, "IDirect3D9 object creation failed.\n");
}
}
//clean up
void Prog_Done()
{
//safe release of IDirect3D8 object
if (g_pd3d)
{
//release
g_pd3d->Release();
//set to null
g_pd3d = NULL;
//report action
fprintf(stdout, "IDirect3D9 object released.\n");
}
}
总结:虽然这是一本古老的书,但到现在为止,很多想学习windows下游戏开发的热爱者,还是会随便从网上当一本游戏编程书籍,很大概率就会下到一本什么书呢,一本里面写满DirectDraw的函数的书!而这种技术已经淘汰很久很久了,完全跟不上时代!
但是,这类书中又有很多有参考价值的部分,比如算法,空间几何,那些图形学,AI,以及其他乱七八糟的好东西,这样,这本书你到底看还是不看?食之无味弃之可惜,但又如蚊子叮铁牛无从下嘴,因为连第一个例子都无法编译通过。。。
现在明白了,是被过气的directdraw 给坑了,那么,
你可以选择学习虽然老一点,但仍具有一定实用性的DX9或DX10,而此时你最需要的就是一本教你如何从directdraw迁移到Direcx3D的使用方法的书,把老书中源码修改一下,能够编译通过跑起来,老书的剩余价值便可充分利用了
ps: 虽然这是一个很小白很小白的试验小例子,但却很重要,因为很大概率的,如果你连这个第一步都搞不定,则极有可能永远失去对windows游戏开发的兴趣,就此错失领略一个无比瑰丽迷人领域的宝贵机会!