当前位置: 首页 > article >正文

Direct2D 极速教程(1) —— 画图形

极速导航

    • Direct2D 简介
    • 创建新项目:001-DrawGraphics
    • 弄一个白窗口
    • 在窗口上画图


Direct2D 简介


在这里插入图片描述

在这里插入图片描述


大家在学 WINAPI 的时候的时候有没有想过,怎么在一副窗口上画图呢?大家知道 Windows 系统是 GUI 图形用户界面 系统,以 Graphics 图形 为卖点嘛,肯定需要一个东西 (子系统) 来画图,于是我们熟知的 GDI (Graphics Device Interface,图形设备接口) 应运而生。GDI 是图形显示与硬件的桥梁,有了它我们就能画图了:


在这里插入图片描述

这是实打实用 GDI 实现的软件光栅化画 3D 模型,太恐怖了!

原文地址:用 windows GDI 实现软光栅化渲染器–gdi3d(开源)

然而 GDI 可是用纯 C 语言写出来的 API!GDI 编程时时刻刻都要依赖设备上下文 (就是 HDC)设备句柄!纯 C-style 的代码写起来可费力不少,而且 GDI 的缺陷也逐渐显露出来,例如说什么绘制精度不高啊,支持颜色不够啊,只支持 BMP 位图啊,容易出现锯齿啊等等。

于是在 Windows 2000 的时候,微软又推出了 GDI+ ,这个 API 是基于 C++ 写的 GDI 加强版,写代码方便了不少,而且解决了上述 GDI 中出现的问题:


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

用 GDI+ 画圆,边缘锯齿感明显减轻了很多

GDI+ 换来了好的表现效果,那么代价呢?绘制效率降低,所以 GDI+ 画图速度是明显慢于 GDI 的,一般只有 10 fps 左右。

怎么才能画的又快又好呢?GDI 和 GDI+ 都是 软件渲染 (CPU 渲染) 的,软件不行,可以用 硬件 (GPU) 啊!


在这里插入图片描述


其实在 Windows 95 的时候,微软就发布了第一代 DirectX 套件 ,里面就已经有初步支持硬件加速的 DirectShow 和 DirectDraw 了 (注意因为那时候 GPU 发展尚未成型,所以说是初步支持硬件加速,渲染的大头还落在 CPU 上),后面 GPU 逐步发展到能和 CPU 平起平坐的阶段,别的厂家已经推出相关支持的渲染 API,微软坐不住了啊!之前设计的太乱,设计的不好,我就重新整合!把 DirectShow 和 DirectDraw 统统重新整合到一个新的 API 里!

在 Windows 7 发布的时候 (2009),微软给开发者们一个大大的惊喜:Direct2D,硬件加速下的 2D 图形渲染时代正式拉开帷幕:


在这里插入图片描述
在这里插入图片描述


创建新项目:001-DrawGraphics


  • 打开 VS2022,新建空项目

在这里插入图片描述
在这里插入图片描述


  • 解决方案名为 “D2D”,项目名称为 “001-DrawGraphics”,位置选桌面,然后按"创建"

在这里插入图片描述


  • 右键项目 -> “链接器” -> “系统” -> “子系统” -> 选择"窗口" -> 按"确定"

在这里插入图片描述
在这里插入图片描述


  • 右键项目新建源文件,命名为 “main.cpp”

在这里插入图片描述


弄一个白窗口


废话少说,我们直接开始:

#include<Windows.h>
#include<wrl.h>
#include<d2d1.h>

#pragma comment(lib, "d2d1.lib")

LRESULT CALLBACK callBackFunc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hins, HINSTANCE hPrev, LPSTR lpstr, int cmdShow)
{
	WNDCLASS wc = {};
	wc.hInstance = hins;
	wc.lpszClassName = L"D2D";
	wc.lpfnWndProc = callBackFunc;

	RegisterClass(&wc);

	HWND hwnd = CreateWindow(wc.lpszClassName, L"你好!Direct 2D", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hins, NULL);

	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}

LRESULT CALLBACK callBackFunc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{

	case WM_DESTROY: {
		PostQuitMessage(0);
	} break;

	default: return DefWindowProc(hwnd, msg, wParam, lParam);
	}

	return 0;
}


在这里插入图片描述


在窗口上画图


#include<Windows.h>
#include<wrl.h>
#include<d2d1.h>

#pragma comment(lib, "d2d1.lib")

using namespace Microsoft::WRL;

LRESULT CALLBACK callBackFunc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

ComPtr<ID2D1Factory> m_D2DFactory;				// D2D 工厂
ComPtr<ID2D1HwndRenderTarget> m_RenderTarget;	// 窗口渲染目标
ComPtr<ID2D1SolidColorBrush> m_Brush;			// 纯色画刷


int WINAPI WinMain(HINSTANCE hins, HINSTANCE hPrev, LPSTR lpstr, int cmdShow)
{
	WNDCLASS wc = {};
	wc.hInstance = hins;
	wc.lpszClassName = L"D2D";
	wc.lpfnWndProc = callBackFunc;

	RegisterClass(&wc);

	HWND hwnd = CreateWindow(wc.lpszClassName, L"你好!Direct 2D", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hins, NULL);

	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}

LRESULT CALLBACK callBackFunc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_CREATE: {	// 在这里创建 D2D 设备

		// 创建 D2D 工厂
		D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, m_D2DFactory.GetAddressOf());

		D2D1_RENDER_TARGET_PROPERTIES properties = {};
		properties.dpiX = 0;
		properties.dpiY = 0;
		properties.type = D2D1_RENDER_TARGET_TYPE_HARDWARE;					// 硬件渲染
		properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;	// 开启 alpha 混合
		properties.pixelFormat.format = DXGI_FORMAT_R8G8B8A8_UNORM;

		D2D1_HWND_RENDER_TARGET_PROPERTIES Hwndproperties = {};
		Hwndproperties.hwnd = hwnd;											// 窗口句柄
		Hwndproperties.pixelSize.width = 640;								// 渲染目标宽度
		Hwndproperties.pixelSize.height = 480;								// 渲染目标高度
		Hwndproperties.presentOptions = D2D1_PRESENT_OPTIONS_NONE;			// 自动选择呈现模式

		// 创建窗口渲染目标
		m_D2DFactory->CreateHwndRenderTarget(properties, Hwndproperties, &m_RenderTarget);

		// 创建纯色画刷
		m_RenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Blue), &m_Brush);

	} break;

	case WM_PAINT: {	// 在这里进行绘制操作

		m_RenderTarget->BeginDraw();

		m_RenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::LightSteelBlue));	// 清空窗口
		
		const UINT square_length = 40;		// 正方形边长
		const UINT begin_pos_x = 100;		// 正方形起始位置 (x轴)
		const UINT begin_pos_y = 20;		// 正方形起始位置 (y轴)
		bool is_black = true;
		
		D2D1_RECT_F rect = {};

		for (int i = 0; i < 11; i++)
		{
			for (int j = 0; j < 11; j++)
			{
				rect.left = begin_pos_x + j * square_length;
				rect.right = rect.left + square_length;
				rect.top = begin_pos_y + i * square_length;
				rect.bottom = rect.top + square_length;

				// 设置画刷颜色
				if (is_black) m_Brush->SetColor(D2D1::ColorF(D2D1::ColorF::Black));
				else m_Brush->SetColor(D2D1::ColorF(D2D1::ColorF::White));

				m_RenderTarget->FillRectangle(rect, m_Brush.Get());		// 绘制矩形
				
				is_black = !is_black;
			}
		}

		m_RenderTarget->EndDraw();

	} break;

	case WM_DESTROY: {
		PostQuitMessage(0);
	} break;

	default: return DefWindowProc(hwnd, msg, wParam, lParam);
	}

	return 0;
}


在这里插入图片描述



下一篇教程,我们要用 Direct2D 画一个淳平。


http://www.kler.cn/a/523961.html

相关文章:

  • (2)SpringBoot自动装配原理简介
  • 在php中怎么打开OpenSSL
  • MV结构下设置Qt表格的代理
  • 面试经典150题——图
  • 阿里云域名备案
  • 中文输入法方案
  • Linux 学习笔记__Day3
  • 零刻SER7接口及配置跑分
  • AI 浪潮席卷中国年,开启科技新春新纪元
  • 创作三载·福启新章2025
  • 解决 -bash rz:command not found
  • [权限提升] 操作系统权限介绍
  • 二叉树-堆(补充)
  • 动态规划DP 数字三角型模型 最低通行费用(题目详解+C++代码完整实现)
  • vue中onclick如何调用methods中的方法
  • Zookeeper(32) Zookeeper的版本号(version)是什么?
  • 【BUUCTF】[羊城杯 2020]Blackcat1
  • ultralytics 是什么?
  • STM32简介
  • MySQL(单表访问)
  • 代码随想录算法【Day34】
  • [ABC137E] Coins Respawn 题解
  • YOLOv11-ultralytics-8.3.67部分代码阅读笔记-block.py
  • LTV预估 | 大R挖掘器ExpLTV
  • LeetCode-3433. 统计用户被提及情况
  • OpenBMC:简介