Windows编程 我与Direct的第一次 简单颜色显示的实现

版本:VS2015 语言:C++

 

最近简直忙死了。晚上抽空把博客写了。

 

这几天也是深深感觉到自己能力的不足,最近貌似要开3D项目了,比起在老代码上爬滚,还是想写自己的新代码啊。

 

嗯嗯,Windows编程还是得继续看、日语得继续学,然后是cocos3d啊。看来真得把周末玩的时候贡献出来了。善始善终,把空轨sc白金后开始撸上面的东西。

 

进入正题。

 

想要使用Direct,第一步当然是导包,先使用以下链接把需要的包放到工程底下:

链接:http://pan.baidu.com/s/1eS5F3Ce 密码:gwny

 Windows编程 我与Direct的第一次 简单颜色显示的实现_第1张图片

 

这是我整个的工程目录,其中lib放lib资源,include放头文件。嗯,好了,这样完毕之后就是要在工程里面导入了。

 

如果看过第一节Windows编程博客的话,应该对这个东西了如指掌了:

1.VC++目录中添加include头文件目录;

2.在链接器——常规——附加库目录中添加lib目录;

3.在链接器——输入——附加依赖项中添加两个lib:dxguid.lib和ddraw.lib。

 

然后就正式进入代码。看过前一节的玩家可能会在想我之前要说的T3D控制台程序去哪了?

 

嗯,现在给大家:

// 主函数,程序入口
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR    lpCmdLine,
	_In_ int       nCmdShow)
{
	// 创建窗口类
	WNDCLASSEX wndclass;
	wndclass.cbSize = sizeof(WNDCLASSEX);
	wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;	//窗口的样式:改变宽度刷新、改变高度刷新、分配设备描述表、双击信息
	wndclass.lpfnWndProc = WindowProc;	//回调函数
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	//任务栏上的图标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);	//光标的读取
	wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);	//窗口背景
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = TEXT("MyFirstWindow");	//窗口的名字
	wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);	//应用上的图标
	if (!RegisterClassEx(&wndclass))
		return 0;
																
	// 创建窗口,上面的窗口类是一个模版,可以根据上面的模版创建多个窗口,但请注意第二个参数
	HWND hwnd = CreateWindowEx(NULL,//WS_EX_TOPMOST,	//窗口特性,注释里设置为永远在最上方显示
		TEXT("MyFirstWindow"),	//窗口名称,一定要和窗口类的lpszClassName对应
		TEXT("我与DDraw的第一次"),	//标题
											WS_POPUP | WS_VISIBLE,	//无边框样式配合下面的尺寸实现全屏显示
		0, 0,	//左上角坐标
		SCREEN_WIDTH, SCREEN_HEIGHT,
		NULL,	//父窗口句柄,如果是桌面则为NULL
		NULL,	//菜单窗口句柄
		hInstance,	//应用程序实例
		NULL	//高级特性
		);
	if (!hwnd)	//创建失败返回
		return 0;

	main_window_handle = hwnd;

	MSG msg;	//消息缓存

	srand(GetTickCount());	//随机一个种子

	Game_Init();	//游戏初始化

	// 进入主循环
	while (true)
	{
		DWORD start_time = GetTickCount();	//获取当前时间

		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))	//有消息事件,注意最后一个参数,如果设置为PM_NOREMOVE的话不会销毁消息队列中的消息
		{
			if (msg.message == WM_QUIT)
				break;
			TranslateMessage(&msg);	//转译消息
			DispatchMessage(&msg);	//将消息发送给WindowProc函数处理

		}
		else	//没有消息
		{
			//游戏主循环
			Game_Main();

			// 延时代码,锁定30帧
			while ((GetTickCount() - start_time) < 33);

		}
	}

	Game_Shutdown();	//游戏结束

	return msg.wParam;
}


没错就是在之前循环的框架上家了三个函数:Game_Init、Game_Main、Game_Shutdown,所以我就没有说。

 

我现在的内容是第六章了,第五章的内容实际上就是一些关于COM(Direct设计原理)的解释,就跳过了。

 

然后来看看第六章的代码,注意把代码放在主函数的上面:

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)	//判断当前的按键是否被按下

HWND main_window_handle = NULL;	//当前窗口
LPDIRECTDRAW7 lpdd = NULL;	//Direct7对象,下称d7

LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;	//主显示表面指针
DDSURFACEDESC2 ddsd;	//主显示表面的描述

LPDIRECTDRAWPALETTE lpddpal = NULL;	//调色板
PALETTEENTRY palette[256];	//调色板数据


int SCREEN_WIDTH = 640;	//显示宽度
int SCREEN_HEIGHT = 480;	//显示高度
int SCREEN_BPP = 32;	//色深,现在的机子只能设置为32位,书上可能还是8位的

// 游戏初始化
int Game_Init(void* params = NULL)
{
	// 基础设置
	if (FAILED(DirectDrawCreateEx(NULL, (void**)&lpdd, IID_IDirectDraw7, NULL)))	//获取d7对象
		return 0;
	if (FAILED(lpdd->SetCooperativeLevel(main_window_handle,
		//DDSCL_NORMAL
		DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT
		)))	//跟windows协作等级设置为全屏,这是最常用的参数
		return 0;
	if (FAILED(lpdd->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0, 0)))	//设置显示模式,如果设置为8位会直接出错
		return 0;


	// 开始创建显示主界面
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	ddsd.dwFlags = DDSD_CAPS;	//表明ddsCaps是个有效成员
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;	//表明该界面是主界面

	lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL);	//根据界面描述创建主界面

	// 开始创建调色板
	for (int color = 1; color < 255; ++color)	//随机颜色
	{
		palette[color].peRed = rand() % 256;
		palette[color].peGreen = rand() % 256;
		palette[color].peBlue = rand() % 256;
		palette[color].peFlags = PC_NOCOLLAPSE;	//不需要系统的协助
	}
	palette[0].peRed = 0;	//将黑色设置为0
	palette[0].peGreen = 0;
	palette[0].peBlue = 0;
	palette[0].peFlags = PC_NOCOLLAPSE;
	palette[255].peRed = 255;	//将白色设置为255
	palette[255].peGreen = 255;
	palette[255].peBlue = 255;
	palette[255].peFlags = PC_NOCOLLAPSE;
	
	lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE,	//创建调色板
		palette,
		&lpddpal,
		NULL);

	lpddsprimary->SetPalette(lpddpal);	//主界面与调色板关联

	return 1;
}

// 游戏结束
int Game_Shutdown(void* params = NULL)
{
	// 释放初始化时创建的对象
	if (NULL != lpddpal)
	{
		lpddpal->Release();
		lpddpal = NULL;
	}

	if (NULL != lpddsprimary)
	{
		lpddsprimary->Release();
		lpddsprimary = NULL;
	}

	if (NULL != lpdd)	//d7对象不为空的情况下释放
	{
		lpdd->Release();
		lpdd = NULL;
	}

	return 1;
}

// 游戏主循环
int Game_Main(void* params = NULL)
{
	// 判断是否要退出
	if (KEYDOWN(VK_ESCAPE))
		PostMessage(main_window_handle, WM_CLOSE, 0, 0);

	// 清空主界面的描述
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);

	// 开始绘制
	lpddsprimary->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);	//加锁,绘制的代码需要放在加锁之间

	int mempitch = ddsd.lPitch;	//屏幕横向的宽度,y(第y行)乘以该参数就是指向具体的第y行第1个像素
	UCHAR *video_buffer = (UCHAR*)ddsd.lpSurface;	//屏幕的缓冲区

	for (int index = 0; index < 1000; ++index)	//随机显示颜色
	{
		UCHAR color = rand() % 256;
		int x = rand() % 640;
		int y = rand() % (480<<2);	//本来只要%480就行了,但是因为我们色深设置为了32位,所以得进行调整
		video_buffer[x + y*(mempitch>>2)] = color;	//这边也是一样
	}

	lpddsprimary->Unlock(NULL);	//解锁

	return 1;
}


// 消息处理函数,相当于cocos中的callback
LRESULT CALLBACK WindowProc(HWND hwnd,
	UINT msg,
	WPARAM wParam,
	LPARAM IParam)
{
	switch (msg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		DefWindowProc(hwnd, msg, wParam, IParam);	//自动处理其他的消息
		break;
	}
	return (1);
}

看起来很复杂,但是和窗口的创建一样,写一写留个印象就OK。最后结果:

Windows编程 我与Direct的第一次 简单颜色显示的实现_第2张图片

和例子上的结果是一模一样的,就是无法设置8位色深和残念(就你还用8位色深!)。

 

总结:

窗口三步走:1.窗口类;2.窗口对象;3.事件处理。

DDraw五步走:1.d7对象;2.与Windows关联;3.显示模式;4.创建显示主界面;5.创建调色板。

用的时候记得清空描述,并且要加Lock

 

本来打算Windows这块停一下,但是想着这些都是基础,现在不多花点时间看,还有什么时候有时间?


你可能感兴趣的:(DirectX,OpenGL层)