Win7图形四大件(D3D、D2D、DWrite、WIC)初始化及使用

文 号

831858

1 回复 / 239 浏览


acmilan12 天前 -2017-03-15 14:27831858

Win7添加了很多图形API,其中以下图形API可以配合使用:

  • Direct3D 10.1——三维绘图和特效
  • Direct2D 1.0——二维绘图
  • DirectWrite 1.0——文字绘制
  • Windows Image Component——图像编解码

兼容性注意事项:

  • D2D1.0一定要配合D3D10.1使用,不要用其它版本,不然放到没打IE10/11的Win7下面会不能运行
  • 创建WIC工厂对象一定要用CLSID_WICImagingFactory1,不要用CLSID_WICImagingFactory(2),不然没打IE10/11的Win7下面同样不能运行
  • 为保险起见,建议在引入任何头文件之前
    #define _WIN32_WINNT 0x0601

Direct2D仅支持PBGRA格式,即预乘的BGRA格式,不支持RGBA格式,所以:

  • 一定要使用D3D10_CREATE_DEVICE_BGRA_SUPPORT创建D3D设备
  • 要使用DXGI_FORMAT_B8G8R8A8_UNORM创建交换链和缓冲区
  • 图像也要转换为GUID_WICPixelFormat32bppPBGRA格式

274249

以下是源代码。

为了简单起见,省去了所有的严重错误处理,仅保留对非严重错误的处理。

#define _WIN32_WINNT 0x0601
#include <windows.h>
#include <math.h>
#include <d3d10_1.h>
#include <d2d1.h>
#include <dwrite.h>
#include <wincodec.h>
#include <directxmath.h>
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "dwrite.lib")
#pragma comment(lib, "d3d10_1.lib")

HINSTANCE hInst;
HWND hMainWnd;
BOOL realtime = FALSE; // 实时绘图标志

LRESULT __stdcall WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// Win32错误处理,这个程序暂时没用到
void ShowSysError(DWORD errcode)
{
	wchar_t *lpMsgBuf = NULL;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		errcode,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR)&lpMsgBuf,
		0, NULL);
	MessageBox(NULL, lpMsgBuf, L"错误", MB_ICONERROR);
	LocalFree(lpMsgBuf);
}

// 入口点
int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	wchar_t *szCmdLine, int nShowCmd)
{
	HRESULT hr = CoInitialize(NULL); // WIC图片解码器要求初始化COM

									 // 注册窗口类别
	WNDCLASS wc;
	wc.style = CS_VREDRAW | CS_HREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInst = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); // 注意!防闪烁:NULL_BRUSH
	wc.lpszMenuName = NULL;
	wc.lpszClassName = L"MainWndClass";
	if (!RegisterClass(&wc))
		return 0;

	// 创建窗口,可以指定WS_CLIPCHILDREN以支持Win32控件
	RECT rc = { 0, 0, 640, 480 };
	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, FALSE);
	hMainWnd = CreateWindow(L"MainWndClass", L"Main Window", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
		CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL);
	if (!hMainWnd)
		return 0;

	// 显示并第一次绘制窗口
	ShowWindow(hMainWnd, nShowCmd);
	UpdateWindow(hMainWnd);

	// 消息循环
	MSG msg;
	memset(&msg, 0, sizeof msg);
	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			// 进行实时绘图或等待下一个消息
			if (realtime)
				SendMessage(hMainWnd, WM_TIMER, 222, 0);
			else
				WaitMessage();
		}
	}

	CoUninitialize(); // 卸载COM

	return (int)msg.wParam;
}

#define USED3D 1

// 窗口消息处理函数
LRESULT __stdcall WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	// 静态对象
	static ID2D1Factory *d2dfac;
	static IDWriteFactory *dwfac;
	static IWICImagingFactory *wicfac;
#if USED3D
	static ID3D10Device1 *d3ddev;
	static IDXGISwapChain *swpch;
	static ID3D10RenderTargetView *d3drtv;
#else
	static ID2D1HwndRenderTarget *hwndrt;
#endif
	static ID2D1RenderTarget *rt;
	static ID2D1Bitmap *bmpPenguins;
	// 每次进入都要用到的对象
	HRESULT hr;
	RECT rc;
	GetClientRect(hWnd, &rc);
	int width = rc.right - rc.left;
	int height = rc.bottom - rc.top;
	// 自绘按钮状态
	static RECT rcbtn = { 10, 10, 100, 50 };
	static RECT rcbtn2 = { 10 + 5, 10 + 5, 100 + 5, 50 + 5 };
	static int trbtn = 0;
	// 窗口创建
	if (msg == WM_CREATE) {
		// 创建D2D、DWrite、WIC根工厂
		hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dfac);
		hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), (IUnknown**)&dwfac);
		// 注意!一定要用CLSID_WICImagingFactory1,不要用默认的CLSID_WICImagingFactory(2),否则需要安装IE11
		hr = CoCreateInstance(CLSID_WICImagingFactory1, NULL, CLSCTX_INPROC_SERVER, __uuidof(wicfac), (void**)&wicfac);
#if USED3D
		// 创建D3D设备和DXGI交换链,包括后台缓冲区
		DXGI_SWAP_CHAIN_DESC swapDesc;
		memset(&swapDesc, 0, sizeof swapDesc);
		swapDesc.BufferDesc.Width = width;
		swapDesc.BufferDesc.Height = height;
		swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // 注意!D2D兼容选项:BGRA
		swapDesc.BufferDesc.RefreshRate.Numerator = 60;
		swapDesc.BufferDesc.RefreshRate.Denominator = 1;
		swapDesc.SampleDesc.Count = 1;
		swapDesc.SampleDesc.Quality = 0;
		swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		swapDesc.BufferCount = 1;
		swapDesc.OutputWindow = hWnd;
		swapDesc.Windowed = TRUE;
		swapDesc.Flags = 0;
		hr = D3D10CreateDeviceAndSwapChain1(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL,
			D3D10_CREATE_DEVICE_BGRA_SUPPORT, // 重要!D2D兼容选项:BGRA
			D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &swapDesc, &swpch, &d3ddev);
		if (FAILED(hr))
		{
			hr = D3D10CreateDeviceAndSwapChain1(NULL, D3D10_DRIVER_TYPE_WARP, NULL,
				D3D10_CREATE_DEVICE_BGRA_SUPPORT,
				D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &swapDesc, &swpch, &d3ddev);
		}
		// 禁止Alt-Enter
		IDXGIFactory *dxgifac;
		hr = swpch->GetParent(__uuidof(dxgifac), (void**)&dxgifac);
		hr = dxgifac->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
		dxgifac->Release();
		// 创建渲染对象
		SendMessage(hWnd, WM_SIZE, SIZE_RESTORED, MAKELPARAM(width, height));
#else
		// 直接创建D2D渲染对象
		hr = d2dfac->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
			D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),
			&hwndrt);
		hr = hwndrt->QueryInterface(__uuidof(ID2D1RenderTarget), (void**)&rt);
#endif
		// 解码图片
		IWICBitmapDecoder *wicdec;
		hr = wicfac->CreateDecoderFromFilename(L"Penguins.jpg", NULL, GENERIC_READ,
			WICDecodeMetadataCacheOnDemand, &wicdec);
		if (SUCCEEDED(hr))
		{
			// 获取第一帧
			IWICBitmapFrameDecode *wicorgfmt;
			hr = wicdec->GetFrame(0, &wicorgfmt);
			// 转换为D2D可用的PBGRA格式
			IWICFormatConverter *wicd2dfmt;
			hr = wicfac->CreateFormatConverter(&wicd2dfmt);
			hr = wicd2dfmt->Initialize(wicorgfmt, GUID_WICPixelFormat32bppPBGRA,
				WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
			// 创建D2D位图
			hr = rt->CreateBitmapFromWicBitmap(wicd2dfmt, &bmpPenguins);
			// 释放临时对象
			wicdec->Release();
			wicorgfmt->Release();
			wicd2dfmt->Release();
		}
		else
		{
			MessageBox(hWnd, L"找不到Penguins.jpg", L"警告", MB_ICONWARNING);
		}
		return 0;
	}
	// 窗口大小变化
	if (msg == WM_SIZE) {
#if USED3D
		// 释放旧对象
		if (rt) {
			rt->Release();
			rt = NULL;
		}
		if (d3drtv) {
			d3drtv->Release();
			d3drtv = NULL;
		}
		if (swpch && d2dfac && d3ddev) {
			// 调整后台缓冲区
			hr = swpch->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0);
			// 获取后台缓冲区
			ID3D10Texture2D *backbuffer;
			hr = swpch->GetBuffer(0, __uuidof(backbuffer), (void**)&backbuffer);
			IDXGISurface *surf;
			hr = backbuffer->QueryInterface(__uuidof(surf), (void**)&surf);
			// 创建D2D渲染对象
			float dpix, dpiy;
			d2dfac->GetDesktopDpi(&dpix, &dpiy);
			hr = d2dfac->CreateDxgiSurfaceRenderTarget(surf,
				D2D1::RenderTargetProperties(
					D2D1_RENDER_TARGET_TYPE_DEFAULT,
					D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
					dpix,
					dpiy,
					D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT
				),
				&rt);
			// 创建D3D渲染对象(不一定用得到)
			hr = d3ddev->CreateRenderTargetView(backbuffer, NULL, &d3drtv);
			// 释放临时对象
			backbuffer->Release();
			surf->Release();
		}
#else
		if (hwndrt)
			hr = hwndrt->Resize(D2D1::SizeU(LOWORD(lParam), HIWORD(lParam)));
#endif
		return 0;
	}
	// 鼠标左键按下
	if (msg == WM_LBUTTONDOWN) {
		POINT pt;
		SetCapture(hWnd);
		pt.x = LOWORD(lParam);
		pt.y = HIWORD(lParam);
		if (PtInRect(&rcbtn, pt))
			trbtn = 5;
		if (PtInRect(&rcbtn2, pt))
			trbtn = 5;
		InvalidateRect(hWnd, NULL, TRUE);
		return 0;
	}
	// 鼠标左键弹起
	if (msg == WM_LBUTTONUP) {
		trbtn = 0;
		ReleaseCapture();
		InvalidateRect(hWnd, NULL, TRUE);
		return 0;
	}
	// 需要绘图(WM_PAINT)或实时绘图(WM_TIMER,222)见入口点内部的消息循环
	if (msg == WM_PAINT || (msg == WM_TIMER && wParam == 222)) {
		// 移除WM_PAINT消息
		if (msg == WM_PAINT)
		{
			PAINTSTRUCT ps;
			HDC hdc = BeginPaint(hWnd, &ps);
			EndPaint(hWnd, &ps);
		}

		// 防崩溃
		if (!rt) return 0;
#if USED3D
		if (!swpch) return 0;
#endif

		// 创建临时资源
		ID2D1SolidColorBrush *brtransblue;
		ID2D1SolidColorBrush *brtransblack;
		ID2D1SolidColorBrush *brwhite;
		IDWriteTextFormat *tfsegoeui;
		hr = rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Blue, 0.5f), &brtransblue);
		hr = rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Gray, 0.5f), &brtransblack);
		hr = rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), &brwhite);
		hr = dwfac->CreateTextFormat(L"Segoe UI", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
			DWRITE_FONT_STRETCH_NORMAL, 12, L"", &tfsegoeui);
		hr = tfsegoeui->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
		hr = tfsegoeui->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);

		// 开始绘制
		rt->BeginDraw();
		rt->Clear(D2D1::ColorF(D2D1::ColorF::Wheat));

		// 绘制按钮
		rt->FillRoundedRectangle(D2D1::RoundedRect(
			D2D1::Rect(rcbtn2.left, rcbtn2.top, rcbtn2.right, rcbtn2.bottom),
			10, 10),
			brtransblack);
		rt->FillRoundedRectangle(D2D1::RoundedRect(
			D2D1::Rect(rcbtn.left + trbtn, rcbtn.top + trbtn, rcbtn.right + trbtn, rcbtn.bottom + trbtn),
			10, 10),
			brtransblue);
#define str L"按钮1"
		rt->DrawText(str, lstrlen(str), tfsegoeui,
			D2D1::Rect(rcbtn.left + trbtn, rcbtn.top + trbtn, rcbtn.right + trbtn, rcbtn.bottom + trbtn),
			brwhite);
#undef str

		// 绘制图片
		if (bmpPenguins)
			rt->DrawBitmap(bmpPenguins, &D2D1::RectF(100, 100, 420, 340));

		// 结束绘制
		hr = rt->EndDraw();
#if USED3D
		// D3D上屏
		hr = swpch->Present(0, 0);
#endif

		// 释放临时资源
		if (tfsegoeui) tfsegoeui->Release();
		if (brwhite) brwhite->Release();
		if (brtransblack) brtransblack->Release();
		if (brtransblue) brtransblue->Release();
		return 0;
	}
	if (msg == WM_DESTROY) {
		// 释放静态对象
		if (bmpPenguins) {
			bmpPenguins->Release();
			bmpPenguins = NULL;
		}
		if (rt) {
			rt->Release();
			rt = NULL;
		}
#if USED3D
		if (d3drtv) {
			d3drtv->Release();
			d3drtv = NULL;
		}
		if (swpch) {
			swpch->Release();
			swpch = NULL;
		}
		if (d3ddev) {
			d3ddev->Release();
			d3ddev = NULL;
		}
#else
		if (hwndrt) {
			hwndrt->Release();
			hwndrt = NULL;
		}
#endif
		if (wicfac) {
			wicfac->Release();
			wicfac = NULL;
		}
		if (dwfac) {
			dwfac->Release();
			dwfac = NULL;
		}
		if (d2dfac) {
			d2dfac->Release();
			d2dfac = NULL;
		}
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

[修改于 11 天前 - 2017-03-16 02:05:07]


acmilan12 天前 -2017-03-15 16:35831861

一个更复杂的程序——透明带阴影的按钮+旋转的企鹅照片和炫彩字体

二进制程序:

效果图:

274253

源代码:

#define _WIN32_WINNT 0x0601
#include <windows.h>
#include <math.h>
#include <d3d10_1.h>
#include <d2d1.h>
#include <dwrite.h>
#include <wincodec.h>
#include <directxmath.h>
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "dwrite.lib")
#pragma comment(lib, "d3d10_1.lib")

HINSTANCE hInst;
HWND hMainWnd;
BOOL realtime = TRUE; // 实时绘图标志

LRESULT __stdcall WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// Win32错误处理,这个程序暂时没用到
void ShowSysError(DWORD errcode)
{
	wchar_t *lpMsgBuf = NULL;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		errcode,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR)&lpMsgBuf,
		0, NULL);
	MessageBox(NULL, lpMsgBuf, L"错误", MB_ICONERROR);
	LocalFree(lpMsgBuf);
}

// 入口点
int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	wchar_t *szCmdLine, int nShowCmd)
{
	HRESULT hr = CoInitialize(NULL); // WIC图片解码器要求初始化COM

									 // 注册窗口类别
	WNDCLASS wc;
	wc.style = CS_VREDRAW | CS_HREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInst = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); // 注意!防闪烁:NULL_BRUSH
	wc.lpszMenuName = NULL;
	wc.lpszClassName = L"MainWndClass";
	if (!RegisterClass(&wc))
		return 0;

	// 创建窗口,可以指定WS_CLIPCHILDREN以支持Win32控件
	RECT rc = { 0, 0, 640, 480 };
	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, FALSE);
	hMainWnd = CreateWindow(L"MainWndClass", L"Main Window", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
		CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL);
	if (!hMainWnd)
		return 0;

	// 显示并第一次绘制窗口
	ShowWindow(hMainWnd, nShowCmd);
	UpdateWindow(hMainWnd);

	// 消息循环
	MSG msg;
	memset(&msg, 0, sizeof msg);
	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			// 进行实时绘图或等待下一个消息
			if (realtime)
				SendMessage(hMainWnd, WM_TIMER, 222, 0);
			else
				WaitMessage();
		}
	}

	CoUninitialize(); // 卸载COM

	return (int)msg.wParam;
}

// 窗口消息处理函数
LRESULT __stdcall WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	// 静态对象
	static ID2D1Factory *d2dfac;
	static IDWriteFactory *dwfac;
	static IWICImagingFactory *wicfac;
	static ID3D10Device1 *d3ddev;
	static IDXGISwapChain *swpch;
	static ID3D10RenderTargetView *d3drtv;
	static ID2D1RenderTarget *rt;
	static ID2D1Bitmap *bmpPenguins;
	static ID3D10Texture2D *tx2dPic;
	static ID3D10ShaderResourceView *tx2dPicSRV;
	static ID2D1RenderTarget *rtPic;
	static ID3D10Effect *eff;
	static ID3D10InputLayout *inlayoutPic;
	static ID3D10Buffer *vbPic;
	// 每次进入都要用到的对象
	HRESULT hr;
	RECT rc;
	GetClientRect(hWnd, &rc);
	int width = rc.right - rc.left;
	int height = rc.bottom - rc.top;
	// 自绘按钮状态
	static RECT rcbtn = { 10, 10, 100, 50 };
	static RECT rcbtn2 = { 10 + 5, 10 + 5, 100 + 5, 50 + 5 };
	static int trbtn = 0;
	// D3D效果文件
	static char efftxt[] = R"EFFECTS(
float4x4 matWorld;
float4x4 matViewAndProj;
float timerad;
Texture2D tx2dPic;
SamplerState tx2dPicSampStat
{
	Texture = tx2dPic;
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

void PicVS(float4 pos0 : POSITION, float2 tex0 : TEXCOORD,
		out float4 pos1 : SV_POSITION, out float2 tex1 : TEXCOORD)
{
	pos1 = mul(mul(pos0, matWorld), matViewAndProj);
	tex1 = tex0;
	return;
}

float4 PicPS(float4 pos : SV_Position,
		float2 tex0 : TEXCOORD) : SV_Target
{
	return tx2dPic.Sample(tx2dPicSampStat, tex0);
}

RasterizerState rasstate
{
	CULLMODE = 1;
};

technique10 Pic {
	pass P0 {
		SetVertexShader(CompileShader(vs_4_0, PicVS()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_0, PicPS()));
		SetRasterizerState(rasstate);
	}
}
)EFFECTS";
	// 窗口创建
	if (msg == WM_CREATE) {
		// 创建D2D、DWrite、WIC根工厂
		hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dfac);
		hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), (IUnknown**)&dwfac);
		// 注意!一定要用CLSID_WICImagingFactory1,不要用默认的CLSID_WICImagingFactory(2),否则需要安装IE11
		hr = CoCreateInstance(CLSID_WICImagingFactory1, NULL, CLSCTX_INPROC_SERVER, __uuidof(wicfac), (void**)&wicfac);
		// 创建D3D设备和DXGI交换链,包括后台缓冲区
		DXGI_SWAP_CHAIN_DESC swapDesc;
		memset(&swapDesc, 0, sizeof swapDesc);
		swapDesc.BufferDesc.Width = width;
		swapDesc.BufferDesc.Height = height;
		swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // 注意!D2D兼容选项:BGRA
		swapDesc.BufferDesc.RefreshRate.Numerator = 60;
		swapDesc.BufferDesc.RefreshRate.Denominator = 1;
		swapDesc.SampleDesc.Count = 1;
		swapDesc.SampleDesc.Quality = 0;
		swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		swapDesc.BufferCount = 1;
		swapDesc.OutputWindow = hWnd;
		swapDesc.Windowed = TRUE;
		swapDesc.Flags = 0;
		hr = D3D10CreateDeviceAndSwapChain1(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL,
			D3D10_CREATE_DEVICE_BGRA_SUPPORT, // 重要!D2D兼容选项:BGRA
			D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &swapDesc, &swpch, &d3ddev);
		if (FAILED(hr))
		{
			hr = D3D10CreateDeviceAndSwapChain1(NULL, D3D10_DRIVER_TYPE_WARP, NULL,
				D3D10_CREATE_DEVICE_BGRA_SUPPORT, // 重要!D2D兼容选项:BGRA
				D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, &swapDesc, &swpch, &d3ddev);
		}
		// 禁止Alt-Enter
		IDXGIFactory *dxgifac;
		hr = swpch->GetParent(__uuidof(dxgifac), (void**)&dxgifac);
		hr = dxgifac->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
		dxgifac->Release();
		// 创建渲染对象
		SendMessage(hWnd, WM_SIZE, SIZE_RESTORED, MAKELPARAM(width, height));
		// 解码图片
		IWICBitmapDecoder *wicdec;
		hr = wicfac->CreateDecoderFromFilename(L"Penguins.jpg", NULL, GENERIC_READ,
			WICDecodeMetadataCacheOnDemand, &wicdec);
		if (SUCCEEDED(hr))
		{
			// 获取第一帧
			IWICBitmapFrameDecode *wicorgfmt;
			hr = wicdec->GetFrame(0, &wicorgfmt);
			// 转换为D2D可用的PBGRA格式
			IWICFormatConverter *wicd2dfmt;
			hr = wicfac->CreateFormatConverter(&wicd2dfmt);
			hr = wicd2dfmt->Initialize(wicorgfmt, GUID_WICPixelFormat32bppPBGRA,
				WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
			// 创建D2D位图
			hr = rt->CreateBitmapFromWicBitmap(wicd2dfmt, &bmpPenguins);
			// 释放临时对象
			wicdec->Release();
			wicorgfmt->Release();
			wicd2dfmt->Release();
		}
		else
		{
			MessageBox(hWnd, L"找不到Penguins.jpg", L"警告", MB_ICONWARNING);
		}
		// 创建独立纹理以及D3D资源对象
		D3D10_TEXTURE2D_DESC tx2dPicDesc;
		tx2dPicDesc.Width = 320;
		tx2dPicDesc.Height = 240;
		tx2dPicDesc.MipLevels = 1;
		tx2dPicDesc.ArraySize = 1;
		tx2dPicDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
		tx2dPicDesc.SampleDesc.Count = 1;
		tx2dPicDesc.SampleDesc.Quality = 0;
		tx2dPicDesc.Usage = D3D10_USAGE_DEFAULT;
		tx2dPicDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
		tx2dPicDesc.CPUAccessFlags = 0;
		tx2dPicDesc.MiscFlags = 0;
		hr = d3ddev->CreateTexture2D(&tx2dPicDesc, NULL, &tx2dPic);
		hr = d3ddev->CreateShaderResourceView(tx2dPic, NULL, &tx2dPicSRV);
		// 创建对于纹理的渲染对象
		IDXGISurface *surfPic;
		hr = tx2dPic->QueryInterface(__uuidof(surfPic), (void**)&surfPic);
		hr = d2dfac->CreateDxgiSurfaceRenderTarget(surfPic,
			D2D1::RenderTargetProperties(
				D2D1_RENDER_TARGET_TYPE_DEFAULT,
				D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
				96,
				96,
				D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT
			),
			&rtPic);
		surfPic->Release();
		// 创建效果
		ID3D10Blob *effcode = NULL, *errmsg = NULL;
		hr = D3D10CompileEffectFromMemory(efftxt, strlen(efftxt), "main.cpp:efftxtPic",
			NULL, NULL, 0, 0, &effcode, &errmsg);
		if (FAILED(hr) && errmsg)
		{
			OutputDebugStringA((char*)errmsg->GetBufferPointer());
#ifdef _M_IX86
			__asm int 3
#else
			DebugBreak();
#endif
		}
		hr = D3D10CreateEffectFromMemory(effcode->GetBufferPointer(), effcode->GetBufferSize(), 0, d3ddev, NULL, &eff);
		ID3D10EffectPass *pass = eff->GetTechniqueByName("Pic")->GetPassByName("P0");
		D3D10_PASS_DESC passdesc;
		hr = pass->GetDesc(&passdesc);
		// 创建输入格式
		D3D10_INPUT_ELEMENT_DESC inputlayout[] = {
			{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
			{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		};
		hr = d3ddev->CreateInputLayout(inputlayout, 2, passdesc.pIAInputSignature,
			passdesc.IAInputSignatureSize, &inlayoutPic);
		// 创建顶点缓冲区
		float buf[] = {
			-2.0f, 1.5f, 0.0f, 0.0f, 0.0f,
			2.0f, 1.5f, 0.0f, 1.0f, 0.0f,
			2.0f, -1.5f, 0.0f, 1.0f, 1.0f,
			-2.0f, 1.5f, 0.0f, 0.0f, 0.0f,
			2.0f, -1.5f, 0.0f, 1.0f, 1.0f,
			-2.0f, -1.5f, 0.0f, 0.0f, 1.0f,
		};
		D3D10_BUFFER_DESC bufdesc;
		bufdesc.ByteWidth = sizeof buf;
		bufdesc.Usage = D3D10_USAGE_DEFAULT;
		bufdesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
		bufdesc.CPUAccessFlags = 0;
		bufdesc.MiscFlags = 0;
		D3D10_SUBRESOURCE_DATA subresdata;
		subresdata.pSysMem = buf;
		subresdata.SysMemPitch = 0;
		subresdata.SysMemSlicePitch = 0;
		hr = d3ddev->CreateBuffer(&bufdesc, &subresdata, &vbPic);
		return 0;
	}
	// 窗口大小变化
	if (msg == WM_SIZE) {
		// 释放旧对象
		if (rt) {
			rt->Release();
			rt = NULL;
		}
		if (d3drtv) {
			d3drtv->Release();
			d3drtv = NULL;
		}
		if (swpch && d2dfac && d3ddev) {
			// 调整后台缓冲区
			hr = swpch->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0);
			// 获取后台缓冲区
			ID3D10Texture2D *backbuffer;
			hr = swpch->GetBuffer(0, __uuidof(backbuffer), (void**)&backbuffer);
			IDXGISurface *surf;
			hr = backbuffer->QueryInterface(__uuidof(surf), (void**)&surf);
			// 创建D2D渲染对象
			float dpix, dpiy;
			d2dfac->GetDesktopDpi(&dpix, &dpiy);
			hr = d2dfac->CreateDxgiSurfaceRenderTarget(surf,
				D2D1::RenderTargetProperties(
					D2D1_RENDER_TARGET_TYPE_DEFAULT,
					D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
					dpix,
					dpiy,
					D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT
				),
				&rt);
			// 创建D3D渲染对象
			hr = d3ddev->CreateRenderTargetView(backbuffer, NULL, &d3drtv);
			// 释放临时对象
			backbuffer->Release();
			surf->Release();
		}
		return 0;
	}
	// 鼠标左键按下
	if (msg == WM_LBUTTONDOWN) {
		POINT pt;
		SetCapture(hWnd);
		pt.x = LOWORD(lParam);
		pt.y = HIWORD(lParam);
		if (PtInRect(&rcbtn, pt))
			trbtn = 5;
		if (PtInRect(&rcbtn2, pt))
			trbtn = 5;
		InvalidateRect(hWnd, NULL, TRUE);
		return 0;
	}
	// 鼠标左键弹起
	if (msg == WM_LBUTTONUP) {
		trbtn = 0;
		ReleaseCapture();
		InvalidateRect(hWnd, NULL, TRUE);
		return 0;
	}
	// 需要绘图(WM_PAINT)或实时绘图(WM_TIMER,222)见入口点内部的消息循环
	if (msg == WM_PAINT || (msg == WM_TIMER && wParam == 222)) {
		// 移除WM_PAINT消息
		if (msg == WM_PAINT)
		{
			PAINTSTRUCT ps;
			HDC hdc = BeginPaint(hWnd, &ps);
			EndPaint(hWnd, &ps);
		}

		// 防崩溃
		if (!rt) return 0;
		if (!swpch) return 0;

		// 创建临时资源
		ID2D1SolidColorBrush *brtransblue;
		ID2D1SolidColorBrush *brtransblack;
		ID2D1SolidColorBrush *brwhite;
		IDWriteTextFormat *tfsegoeui;
		hr = rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Blue, 0.5f), &brtransblue);
		hr = rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Gray, 0.5f), &brtransblack);
		hr = rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), &brwhite);
		hr = dwfac->CreateTextFormat(L"Segoe UI", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
			DWRITE_FONT_STRETCH_NORMAL, 12, L"", &tfsegoeui);
		hr = tfsegoeui->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
		hr = tfsegoeui->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);

		// 开始底部绘制
		rt->BeginDraw();
		rt->Clear(D2D1::ColorF(D2D1::ColorF::Wheat));

		// 绘制按钮
		rt->FillRoundedRectangle(D2D1::RoundedRect(
			D2D1::Rect(rcbtn2.left, rcbtn2.top, rcbtn2.right, rcbtn2.bottom),
			10, 10),
			brtransblack);
		rt->FillRoundedRectangle(D2D1::RoundedRect(
			D2D1::Rect(rcbtn.left + trbtn, rcbtn.top + trbtn, rcbtn.right + trbtn, rcbtn.bottom + trbtn),
			10, 10),
			brtransblue);
#define str L"按钮1"
		rt->DrawText(str, lstrlen(str), tfsegoeui,
			D2D1::Rect(rcbtn.left + trbtn, rcbtn.top + trbtn, rcbtn.right + trbtn, rcbtn.bottom + trbtn),
			brwhite);
#undef str

		// 结束底部绘制
		hr = rt->EndDraw();

		// 释放临时资源
		if (tfsegoeui) tfsegoeui->Release();
		if (brwhite) brwhite->Release();
		if (brtransblack) brtransblack->Release();
		if (brtransblue) brtransblue->Release();

		if (d3ddev && rtPic)
		{
			using namespace DirectX;
			float timerad = GetTickCount() % 2000 / 2000.0f * 2 * XM_PI;

			// 创建临时资源
			ID2D1SolidColorBrush *brred;
			IDWriteTextFormat *tfsegoeuibig;
			hr = rtPic->CreateSolidColorBrush(
				D2D1::ColorF(
					pow(sin(timerad), 2),
					pow(cos(timerad + XM_PI / 6), 2),
					pow(sin(timerad + XM_PI / 3), 2)),
				&brred);
			hr = dwfac->CreateTextFormat(L"Segoe UI", NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
				DWRITE_FONT_STRETCH_NORMAL, 24, L"", &tfsegoeuibig);
			hr = tfsegoeuibig->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
			hr = tfsegoeuibig->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);

			rtPic->BeginDraw();

			// 向纹理绘制图片
			if (bmpPenguins)
				rtPic->DrawBitmap(bmpPenguins, &D2D1::RectF(0, 0, 320, 240));
			else
				rtPic->Clear(D2D1::ColorF(D2D1::ColorF::Blue));
#define str L"画布里的企鹅"
			rtPic->DrawText(str, lstrlen(str), tfsegoeuibig,
				D2D1::Rect(0, 0, 320, 240),
				brred);
#undef str

			// 结束纹理绘制
			hr = rtPic->EndDraw();

			// 释放临时资源
			brred->Release();
			tfsegoeuibig->Release();

			// 设置必要的D3D状态
			// 设置渲染目标
			d3ddev->OMSetRenderTargets(1, &d3drtv, NULL);
			// 设置视口参数
			D3D10_VIEWPORT vp;
			vp.TopLeftX = 0;
			vp.TopLeftY = 0;
			vp.Width = width;
			vp.Height = height;
			vp.MinDepth = 0.0f;
			vp.MaxDepth = 1.0f;
			d3ddev->RSSetViewports(1, &vp);

			// 生成3D参数
			XMMATRIX matWorld = XMMatrixRotationY(timerad);
			XMMATRIX matView = XMMatrixLookAtLH(
				XMVectorSet(0.0f, 3.0f, -8.0f, 0.0f),
				XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f),
				XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f));
			XMMATRIX matProj = XMMatrixPerspectiveFovLH(
				XM_PI / 4, width / (float)height, 1.0f, 100.0f);
			XMMATRIX matViewAndProj = matView * matProj;

			// 上传参数
			eff->GetVariableByName("timerad")->AsScalar()->SetFloat(timerad);
			eff->GetVariableByName("matWorld")->AsMatrix()->SetMatrix((float*)&matWorld);
			eff->GetVariableByName("matViewAndProj")->AsMatrix()->SetMatrix((float*)&matViewAndProj);
			eff->GetVariableByName("tx2dPic")->AsShaderResource()->SetResource(tx2dPicSRV);

			// 设置输入状态
			d3ddev->IASetInputLayout(inlayoutPic);
			UINT stride = 4 * 5, offset = 0;
			d3ddev->IASetVertexBuffers(0, 1, &vbPic, &stride, &offset);
			d3ddev->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

			// 应用效果
			eff->GetTechniqueByName("Pic")->GetPassByName("P0")->Apply(0);

			// 绘制图形
			d3ddev->Draw(6, 0);
		}

		// D3D上屏
		hr = swpch->Present(0, 0);

		// 释放临时资源
		return 0;
	}
	// 窗口结束
	if (msg == WM_DESTROY) {
		// 释放静态对象
		if (vbPic) {
			vbPic->Release();
			vbPic = NULL;
		}
		if (inlayoutPic) {
			inlayoutPic->Release();
			inlayoutPic = NULL;
		}
		if (eff) {
			eff->Release();
			eff = NULL;
		}
		if (rtPic) {
			rtPic->Release();
			rtPic = NULL;
		}
		if (tx2dPicSRV) {
			tx2dPicSRV->Release();
			tx2dPicSRV = NULL;
		}
		if (tx2dPic) {
			tx2dPic->Release();
			tx2dPic = NULL;
		}
		if (bmpPenguins) {
			bmpPenguins->Release();
			bmpPenguins = NULL;
		}
		if (rt) {
			rt->Release();
			rt = NULL;
		}
		if (d3drtv) {
			d3drtv->Release();
			d3drtv = NULL;
		}
		if (swpch) {
			swpch->Release();
			swpch = NULL;
		}
		if (d3ddev) {
			d3ddev->Release();
			d3ddev = NULL;
		}
		if (wicfac) {
			wicfac->Release();
			wicfac = NULL;
		}
		if (dwfac) {
			dwfac->Release();
			dwfac = NULL;
		}
		if (d2dfac) {
			d2dfac->Release();
			d2dfac = NULL;
		}
		PostQuitMessage(0);
		return 0;
	}
	// 其它消息交给系统处理
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

[修改于 11 天前 - 2017-03-16 04:45:13]


返回 Windows开发
返回 本页顶部

想参与大家的讨论?现在就 登陆 或者 注册


nkc Development Server https://github.com/lovetheory/nkc2

科创研究院 (c)2005-2016

蜀ICP备11004945号-2 川公网安备51010802000058号