DirectX9学习-装载位图

发布于 2020-05-16  191 次阅读


装载位图,由于d3d本身不知道如何装载位图,所以我这次要用到d3dx9.h 和d3dx9.lib,但是查资料,VS2015本身的内置库的话是不包括d3dx9.h的,因为这个库属于工具库而非dx核心库,查找官方文档发现如果要用这个D3DX,就只能去下载d3d的sdk,官方的话是:

D3DX is not considered the canonical API for using Direct3D in Windows 8 and later and therefore isn't included with the corresponding Windows SDK.

#include<d3dx9.h>
#pragma comment(lib,"d3dx9.lib")

就能正确的使用这个库中提供的工具了。

今天先把环境配好,明天开始学习如何装载位图。

今天学习如何装载位图

比较重要的函数是

HRESULT D3DXLoadSurfaceFromFile(
  LPDIRECT3DSURFACE9 pDestSurface,
  CONST PALETTEENTRY pDestPalette,
  CONST RECT* pDestRect,
  DWORD Filter,
  D3DCOLOR ColorKey,
  D3DXIMAGE_INFO* pSrcInfo
 )

这个函数能够从指定文件中加载图像到指定表面(几乎所有静态图片格式)

还有就是利用

d3ddev->StretchRect(surface, NULL, backbuffer, NULL, D3DTEXF_NONE);

把图片拉伸成窗口大小,这样在改变窗口大小的同时图片大小也会改变,图片会一直填充窗口。

表面在创建的时候大小制定的稍微大一些,这样图片看起来就不会很模糊。

下面是代码:

#include<Windows.h>
#include<d3d9.h>
#include<d3dx9.h>
#include<iostream>
using namespace std;
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
 
const string APPTITLE = "Direct3D_Windowed";
const int SCREEN_W = 1024;
const int SCREEN_H = 768;
 
const LPSTR FineNames[5] = 
{
	"D:\\Personal\\Documents\\My Pictures\\00eb096a08d184f145da2ca64b4b45e905d18c53.jpg",
	"D:\\Personal\\Documents\\My Pictures\\i1XfcG5JX8KqO.jpg",
	"D:\\Personal\\Documents\\My Pictures\\20151016033822677.jpg",
	"D:\\Personal\\Documents\\My Pictures\\20150615122310_MYFPz.jpeg",
	"D:\\Personal\\Documents\\My Pictures\\20130116175135_2C285 (1).jpeg"
};
 
int pictureIndex = 0;
 
//D3D设置
LPDIRECT3D9 d3d = NULL;
LPDIRECT3DDEVICE9 d3ddev = NULL;
LPDIRECT3DSURFACE9 backbuffer = NULL;
LPDIRECT3DSURFACE9 surface = NULL;
bool GameOver = false;
 
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
 
//GameInit
bool Game_Init(HWND hwnd)
{
	//初始化D3D
	d3d = Direct3DCreate9(D3D_SDK_VERSION);
	if (d3d == NULL)
	{
		MessageBox(hwnd, "Error Initialize D3D9", "ERROR", MB_OK);
		return false;
	}
	
	//设置呈现参数
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));	
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferWidth = SCREEN_W;
	d3dpp.BackBufferHeight = SCREEN_H;
	d3dpp.hDeviceWindow = hwnd;
	
	//创建D3D的设备
	d3d->CreateDevice(
		D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		hwnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp,
		&d3ddev
		);
	
	if (d3ddev == NULL)
	{
		MessageBox(hwnd, "Error Create D3DDEV", "ERROR", MB_OK);
		return false;
	}
	
	//清除缓冲区
	d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0F, 0);
	//让backbuffer指向后台缓冲区
	d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
	//创建一个表面 surface指针指向这个表面
	HRESULT hResult
		= d3ddev->CreateOffscreenPlainSurface(
			SCREEN_W,    //表面的宽
			SCREEN_H,	//表面的高
			D3DFMT_X8R8G8B8,	//格式
			D3DPOOL_DEFAULT,	//所用的内存池
			&surface,			//表面的指针
			NULL				//预留
		);	
	if (hResult != D3D_OK)
		return false;
	//加载图片
	hResult = D3DXLoadSurfaceFromFile(
		surface,	//需要画图的表面
		NULL,		//调色板 ?
		NULL,		//矩形
		FineNames[0],//源文件名字(路径)
		NULL,		//源矩形
		D3DX_DEFAULT,//图片填充样式
		0,			//透明
		NULL		//图片信息(通常为NULL)
	);
	if (hResult != D3D_OK)
		return false;
 
	return true;
 
 
	//初始化完成
	return true;
}
 
void Game_Run(HWND hwnd)
{
	if (KEY_DOWN(VK_ESCAPE))
	{
		PostMessage(hwnd, WM_DESTROY, 0, 0);
	}
	
	if (KEY_DOWN(VK_SPACE))
	{
		pictureIndex++;
		if (pictureIndex >= 5)
			pictureIndex = 0;
		HRESULT hResult = D3DXLoadSurfaceFromFile(
			surface,
			NULL,
			NULL,
			FineNames[pictureIndex],
			NULL,
			D3DX_DEFAULT,
			0,
			NULL
		);				
	}
	
	if (!d3ddev)
		return;
	
	
	//开始渲染
	if (d3ddev->BeginScene())
	{
		//在后台缓冲中画图并拉伸至屏幕
		d3ddev->StretchRect(surface, NULL, backbuffer, NULL, D3DTEXF_NONE);
		//停止渲染
		d3ddev->EndScene();
		//copy back buffer to the frame buffer
		d3ddev->Present(NULL, NULL, NULL, NULL);
 
	}
	
}
 
void Game_End(HWND hwnd)
{
	if (d3ddev)
	{
		d3ddev->Release();
		d3ddev = NULL;
	}
	if (d3d)
	{
		d3d->Release();
		d3d = NULL;
	}
}
 
//Win消息处理
LRESULT CALLBACK WinProc(HWND hWnd, UINT message,
	WPARAM wParam, LPARAM lParam)
{
	//HWND:窗口句柄,使用窗口句柄创建一个新的设备环境句柄HDC,只要引用一个窗口或空间就必须得用到窗口句柄
 
	switch (message)
	{		
	case WM_DESTROY:
		GameOver = true;
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevinstance, LPSTR lpCmdLine, int nCmdShow)
{
	//set the new window properties
	WNDCLASSEX wc;
	MSG msg;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;  //在移动或尺寸更新完|高度调整后重新绘制
	wc.lpfnWndProc = (WNDPROC)WinProc;  //返回一个指向回调函数的指针,如果不设定这个值,消息就无法传递给HWND
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = NULL;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "MainWindowClass";
	wc.hIconSm = NULL;
	if (!RegisterClassEx(&wc))
		return FALSE;
	
	//Create a Window
	HWND hwnd = CreateWindow("MainWindowClass",
		APPTITLE.c_str(),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		SCREEN_W, SCREEN_H,
		(HWND)NULL,
		(HMENU)NULL,
		hInstance,
		(LPVOID)NULL
	);
 
	if (hwnd == 0) //创建失败
		return 0;
	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
 
	//初始化
	if (!Game_Init(hwnd))
		return 0;
 
	while (!GameOver)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
 
		}
		Game_Run(hwnd);
	}
	
	Game_End(hwnd);
	return msg.wParam;
}

注:

d3ddev->StretchRect(surface, NULL, backbuffer, NULL, D3DTEXF_NONE);

这句代码是将表面绘制到屏幕,而且是整个表面图片填充到窗口中。

如果添加

RECT rect;
rect.bottom = 510;

rect.top = 50;
rect.left = 50;
rect.right = 510;
d3ddev->StretchRect(surface, NULL, backbuffer, &rect, D3DTEXF_NONE);

则是将整个图片画在了这个矩形的区域内

而如果把代码改成

d3ddev->StretchRect(surface, &rect, backbuffer,NULL, D3DTEXF_NONE);

那么这句代码就只画了图片中矩形的一部分

如果想将表面创建的和图像一样大的话,则需要添加下面代码:

D3DXIMAGE_INFO imageInfo;
hResult = D3DXGetImageInfoFromFile(filename, &imageInfo);
HRESULT hResult
		= d3ddev->CreateOffscreenPlainSurface(
			imageInfo.Width,    //表面的宽			
			imageInfo.Height,	//表面的高
D3DFMT_X8R8G8B8, //格式D3DPOOL_DEFAULT, //所用的内存池&surface, //表面的指针NULL //预留);