004:Direct 2D离屏渲染(Qt中实现)

简介:

用QT开发图像显示的小程序,需要一些标注工具,由于用的是opengl渲染,所以就在内存中进行绘制,然后纹理贴图贴出去,发现Qt绘制的效果太差,且速度一般,于是就想着用direct2d来绘制需要的纹理图像。

一、QT:QPainter绘制到QImage

下图是QT直接在QImage对象上绘制的效果,其中QImage长和宽分别为:564 - 466。在打开反走样的设置下,线段和椭圆中的锯齿非常明显,字体绘制的也非常丑陋。

QT绘制代码:

cpp 复制代码
void YGLayerScreen::UpdateQImage(){
	if (m_QImage.isNull())
		return;

	QFont m_Font;
	m_Font.setPixelSize(36);
	m_Font.setStyleStrategy(QFont::PreferAntialias);

	QPainter painter;
	if (!painter.begin(&m_QImage))
		return;

	painter.setPen(QPen(Qt::red, 1));
	painter.setFont(m_Font);

	painter.setRenderHints(QPainter::TextAntialiasing|QPainter::Antialiasing | QPainter::SmoothPixmapTransform);

	painter.drawEllipse(QPoint(m_TextureCol/2, m_TextureRow/2),100,200);
	painter.drawLine(10, 10, m_TextureCol / 2, 30);
	painter.drawText(QPoint(50, 50), QString::fromLocal8Bit("你好123TEXTtext"));
	painter.end();

}

二、Direct2D绘制

QT中Direct2D的配置(非常简单),添加头文件和对应的Lib文件即可,如下:

cpp 复制代码
#include <wrl.h>
#include <windows.h>
#include <d2d1.h>
#include <dwrite.h>
#include <wincodec.h>
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "Dwrite.lib")
#pragma comment(lib, "windowscodecs.lib")

在窗口中随机绘制100个圆形和一个字符串和椭圆,代码如下:

cpp 复制代码
void QtOpenGL::TestDirect2D()
{
	/* 统计运行时间 */
	LARGE_INTEGER start_counter, end_counter, counters, nFreq;
	QueryPerformanceFrequency(&nFreq);
	QueryPerformanceCounter(&start_counter);

	/* 离屏渲染图像的宽高 */
	UINT uiWidth = 512;// 1920;
	UINT uiHeight = 512;// 1080;

	/* IWIC 相关变量 */
	IWICBitmap *pBitmap = NULL;
	IWICImagingFactory* pImageFactory = NULL;

	/* IDWrite 相关变量 */
	IDWriteTextFormat *pTextFormat = NULL;
	IDWriteFactory* pDWriterFactory = NULL;   /* use the DrawText method */
	static const WCHAR msc_fontName[] = L"Verdana";
	static const FLOAT msc_fontSize = 50;


	HRESULT hr = CoCreateInstance(
		CLSID_WICImagingFactory,
		NULL,
		CLSCTX_INPROC_SERVER,
		IID_IWICImagingFactory,
		(LPVOID*)&pImageFactory
	);
	if (SUCCEEDED(hr)) {
		//WICPixelFormatGUID formatGUID = GUID_WICPixelFormat32bppBGRA;
		hr = pImageFactory->CreateBitmap(uiWidth, uiHeight,
			GUID_WICPixelFormat32bppPBGRA,
			WICBitmapCacheOnLoad, &pBitmap);
		if (SUCCEEDED(hr)) {
			int a = 0;
		}
	}

	/* */
	hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED,
		__uuidof(pDWriterFactory),
		reinterpret_cast<IUnknown **>(&pDWriterFactory)
	);

	// Create a DirectWrite text format object.
	hr = pDWriterFactory->CreateTextFormat(msc_fontName, NULL,
		DWRITE_FONT_WEIGHT_NORMAL,
		DWRITE_FONT_STYLE_NORMAL,
		DWRITE_FONT_STRETCH_NORMAL,
		msc_fontSize,
		L"", //locale
		&pTextFormat
	);

	pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
	pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);



	ID2D1Factory *m_pD2DFactory = NULL;

		//ID2D1DCRenderTarget *m_pRenderTarget = NULL;
	hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);

	if (SUCCEEDED(hr))
	{


		// Create a DC render target.
		D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
			D2D1_RENDER_TARGET_TYPE_DEFAULT,
			D2D1::PixelFormat(
				DXGI_FORMAT_B8G8R8A8_UNORM,
				D2D1_ALPHA_MODE_PREMULTIPLIED),
			0,
			0,
			D2D1_RENDER_TARGET_USAGE_NONE,
			D2D1_FEATURE_LEVEL_DEFAULT
		);

		ID2D1RenderTarget* m_Target = NULL;
		hr = m_pD2DFactory->CreateWicBitmapRenderTarget(pBitmap, &props, &m_Target);

		D2D1_SIZE_F rtSize = m_Target->GetSize();
		// Draw a grid background.
		int width = static_cast<int>(rtSize.width);
		int height = static_cast<int>(rtSize.height);

		ID2D1SolidColorBrush* pBlackBrush = NULL;
		hr = m_Target->CreateSolidColorBrush(
			D2D1::ColorF(D2D1::ColorF::Red),//颜色
			&pBlackBrush//接收画刷
		);


		static const WCHAR sc_txt[] = L"你好!Direct 2D!";

		if (SUCCEEDED(hr))
		{
			m_Target->BeginDraw();
			m_Target->Clear(D2D1::ColorF(0.26f, 0.56f, 0.87f));
			m_Target->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(150, 55), 50, 30), pBlackBrush);
			m_Target->DrawTextW(
				sc_txt, 
				ARRAYSIZE(sc_txt) - 1,
				pTextFormat,
				D2D1::RectF(0, 0, uiWidth/2, uiHeight/2),
				pBlackBrush);

			for (int i = 0; i < 100; ++i)
			{
				FLOAT left = rand() % width;
				FLOAT top = rand() % height;
				FLOAT radius = rand() % 200;
				pBlackBrush->SetColor(D2D1::ColorF(rand() % 100 / 100.f, rand() % 100 / 100.f, rand() % 100 / 100.f, 100));
				//CD2DEllipse ellipse(CD2DRectF(left, top, left + radius, top + radius));
				//CD2DSolidColorBrush brush(pRenderTarget, D2D1::ColorF(rand() % 100 / 100.f, rand() % 100 / 100.f, rand() % 100 / 100.f, 100));
				m_Target->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(left, top), radius, radius), pBlackBrush);
				//pRenderTarget->FillEllipse(ellipse, &brush);
			}

			m_Target->EndDraw();
		}


		IWICBitmapLock *pLock = NULL;
		WICRect rcLock = { 0, 0, uiWidth, uiHeight };
		hr = pBitmap->Lock(&rcLock, WICBitmapLockWrite, &pLock);
		if (SUCCEEDED(hr))
		{
			UINT cbBufferSize = 0;
			UINT cbStride = 0;
			BYTE *pv = NULL;

			hr = pLock->GetStride(&cbStride);

			if (SUCCEEDED(hr))
			{
				hr = pLock->GetDataPointer(&cbBufferSize, &pv);
				FILE* pFile = fopen("bmp512.raw", "wb+");
				fwrite(pv, 1, cbBufferSize, pFile);
				fclose(pFile);
			}

			// Clear the image data
			//ZeroMemory(pv, cbBufferSize);

			// Release the bitmap lock.
			pLock->Release();
		}
	}

	if (pBitmap) {
		pBitmap->Release();
	}

	if (pImageFactory) {
		pImageFactory->Release();
	}

	QueryPerformanceCounter(&end_counter);
	counters.QuadPart = end_counter.QuadPart - start_counter.QuadPart;

	LONGLONG fps = nFreq.QuadPart / counters.QuadPart;
	LONGLONG elapsed = counters.QuadPart * 1000 / nFreq.QuadPart;

	qDebug() << "FPS :" << fps << "ms";
	qDebug() << "TIMES :" << elapsed << "ms";
	start_counter = end_counter;
}

绘制效果如下:

三、性能:待测试

由于绘制的内容不同,暂时没对性能进行测试。

相关推荐
陌小呆^O^9 分钟前
Cmakelist.txt之win-c-udp-server
c语言·开发语言·udp
Gu Gu Study16 分钟前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
Mr.Q19 分钟前
OpenCV和Qt坐标系不一致问题
qt·opencv
时光の尘30 分钟前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
以后不吃煲仔饭44 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师1 小时前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
前端拾光者1 小时前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
程序猿阿伟1 小时前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
傻啦嘿哟1 小时前
如何使用 Python 开发一个简单的文本数据转换为 Excel 工具
开发语言·python·excel
大数据编程之光1 小时前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink