优化Duilib图片属性解析代码,提升绘制效率

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 转载请说明原出处,谢谢~·http://blog.csdn.net/zhuhongshu/article/details/51245751         好长时间没写duilib博客了,最近在写毕业设计,毕设的软件界面自然就用比较熟悉的Duilib来搞了,正好把Duilib的一些地方一起改改。

转载请说明原出处,谢谢~·http://blog.csdn.net/zhuhongshu/article/details/51245751


         好长时间没写duilib博客了,最近在写毕业设计,毕设的软件界面自然就用比较熟悉的Duilib来搞了,正好把Duilib的一些地方一起改改。


         Duilib的图片绘制代码中有个影响性能的地方,所有的控件的图片绘制都是调用CControlUI的DrawImage函数,而此函数调用了CRenderEngine的DrawImageString函数。在绘制图片时,DrawImageString会解析图片字符串的属性,然后找到对片的HBITMAP资源,最后调用真正的绘图函数去绘制。问题就在于每绘制一个图片都会再次解析一次字符串,当界面比较复杂,而且图片字符串也比较复杂时,这个解析的过程就影响了程序效率。


         实际上这个字符串在被赋值后,只需要解析一次,然后缓存起来就可以了,在绘制图片时直接用缓存好的图片属性数据。使用内存换效率的方法可以进一步提高Duilib的效率。


        写了一个图片属性解析类,代替原本的图片字符串,并且去掉了原本的DrawImageString函数。


class UILIB_API CImageAttribute
{
public:
	CImageAttribute();
	CImageAttribute(const CImageAttribute&);
	const CImageAttribute& operator=(const CImageAttribute&);
	virtual ~CImageAttribute();

    CDuiString GetAttributeString() const;
	void SetAttributeString(LPCTSTR pStrImageAttri);
	void ModifyAttribute(LPCTSTR pStrModify);
	bool LoadImage(CPaintManagerUI* pManager);
	bool IsLoadSuccess();

	operator LPCTSTR() const;
	bool operator ==(LPCTSTR pStrImage) const;
	const CDuiString& operator=(const CDuiString& src);
	const CDuiString& operator=(const TCHAR ch);
	const CDuiString& operator=(LPCTSTR pstr);
private:
	void Clone(const CImageAttribute&);
	void Clear();
	void ParseAttribute(LPCTSTR pStrImageAttri);

protected:
	friend class CRenderEngine;
	CDuiString	m_sImageAttribute;

	CDuiString	m_sImage;
	CDuiString	m_sResType;
	TImageInfo	*m_imageInfo;
	bool		m_bLoadSuccess;

	RECT	m_rcDest;
	RECT	m_rcSource;
	RECT	m_rcCorner;
	BYTE	m_bFade;
	DWORD	m_dwMask;
	bool	m_bHole;
	bool	m_bTiledX;
	bool	m_bTiledY;

};

	CImageAttribute::CImageAttribute()
	{
		Clear();
	}

	CImageAttribute::CImageAttribute(const CImageAttribute& image)
	{
		Clone(image);
	}

	const CImageAttribute& CImageAttribute::operator=(const CImageAttribute& image)
	{
		Clone(image);
		return *this;
	}

	void CImageAttribute::Clone(const CImageAttribute& image)
	{
		m_sImageAttribute = image.m_sImageAttribute;

		m_sImage = image.m_sImage;
		m_sResType = image.m_sResType;
		m_imageInfo = image.m_imageInfo;
		m_bLoadSuccess = image.m_bLoadSuccess;

		m_rcDest = image.m_rcDest;
		m_rcSource = image.m_rcSource;
		m_rcCorner = image.m_rcCorner;
		m_bFade = image.m_bFade;
		m_dwMask = image.m_dwMask;
		m_bHole = image.m_bHole;
		m_bTiledX = image.m_bTiledX;
		m_bTiledY = image.m_bTiledY;
	}

	CImageAttribute::~CImageAttribute()
	{

	}

	CDuiString CImageAttribute::GetAttributeString() const
	{
		return m_sImageAttribute;
	}

	void CImageAttribute::SetAttributeString(LPCTSTR pStrImageAttri)
	{
		if (m_sImageAttribute == pStrImageAttri)
			return;

		Clear();

		m_sImageAttribute = pStrImageAttri;
		m_sImage = m_sImageAttribute;
		ParseAttribute(pStrImageAttri);
	}

	bool CImageAttribute::LoadImage(CPaintManagerUI* pManager)
	{
		if (m_imageInfo != NULL)
			return true;
		if (!m_bLoadSuccess)
			return false;

		const TImageInfo* data = NULL;
		if (m_sResType.IsEmpty())
		{
			data = pManager->GetImageEx((LPCTSTR)m_sImage, NULL, m_dwMask);
		}
		else
		{
			data = pManager->GetImageEx((LPCTSTR)m_sImage, (LPCTSTR)m_sResType, m_dwMask);
		}
		if (data == NULL)
		{
			m_bLoadSuccess = false;
			return false;
		}
		else
		{
			m_bLoadSuccess = true;
		}
		
		if (m_rcSource.left == 0 && m_rcSource.right == 0 && m_rcSource.top == 0 && m_rcSource.bottom == 0)
		{
			m_rcSource.right = data->nX;
			m_rcSource.bottom = data->nY;
		}
		if (m_rcSource.right > data->nX) m_rcSource.right = data->nX;
		if (m_rcSource.bottom > data->nY) m_rcSource.bottom = data->nY;
		m_imageInfo = const_cast<TImageInfo*>(data);

		return true;
	}

	bool CImageAttribute::IsLoadSuccess()
	{
		return !m_sImageAttribute.IsEmpty() && m_bLoadSuccess;
	}

	void CImageAttribute::ModifyAttribute(LPCTSTR pStrModify)
	{
		ParseAttribute(pStrModify);
	}

	void CImageAttribute::Clear()
	{
		m_sImageAttribute.Empty();
		m_sImage.Empty();
		m_sResType.Empty();
		m_imageInfo = NULL;
		m_bLoadSuccess = true;
		ZeroMemory(&m_rcDest, sizeof(RECT));
		ZeroMemory(&m_rcSource, sizeof(RECT));
		ZeroMemory(&m_rcCorner, sizeof(RECT));
		m_bFade = 0xFF;
		m_dwMask = 0;
		m_bHole = false;
		m_bTiledX = false;
		m_bTiledY = false;
	}

	void CImageAttribute::ParseAttribute(LPCTSTR pStrImage)
	{
		if (pStrImage == NULL)
			return;

		// 1、aaa.jpg
		// 2、file='aaa.jpg' res='' restype='0' dest='0,0,0,0' source='0,0,0,0' corner='0,0,0,0' 
		// mask='#FF0000' fade='255' hole='false' xtiled='false' ytiled='false'
		CDuiString sItem;
		CDuiString sValue;
		LPTSTR pstr = NULL;

		while (*pStrImage != _T('\0'))
		{
			sItem.Empty();
			sValue.Empty();
			while (*pStrImage > _T('\0') && *pStrImage <= _T(' ')) pStrImage = ::CharNext(pStrImage);
			while (*pStrImage != _T('\0') && *pStrImage != _T('=') && *pStrImage > _T(' '))
			{
				LPTSTR pstrTemp = ::CharNext(pStrImage);
				while (pStrImage < pstrTemp)
				{
					sItem += *pStrImage++;
				}
			}
			while (*pStrImage > _T('\0') && *pStrImage <= _T(' ')) pStrImage = ::CharNext(pStrImage);
			if (*pStrImage++ != _T('=')) break;
			while (*pStrImage > _T('\0') && *pStrImage <= _T(' ')) pStrImage = ::CharNext(pStrImage);
			if (*pStrImage++ != _T('\'')) break;
			while (*pStrImage != _T('\0') && *pStrImage != _T('\''))
			{
				LPTSTR pstrTemp = ::CharNext(pStrImage);
				while (pStrImage < pstrTemp)
				{
					sValue += *pStrImage++;
				}
			}
			if (*pStrImage++ != _T('\'')) break;
			if (!sValue.IsEmpty())
			{
				if (sItem == _T("file") || sItem == _T("res"))
				{
					m_sImage = sValue;
				}
				else if (sItem == _T("restype"))
				{					
					m_sResType = sValue;
				}
				else if (sItem == _T("dest"))
				{
					m_rcDest.left = _tcstol(sValue.GetData(), &pstr, 10);  ASSERT(pstr);
					m_rcDest.top = _tcstol(pstr + 1, &pstr, 10);    ASSERT(pstr);
					m_rcDest.right = _tcstol(pstr + 1, &pstr, 10);  ASSERT(pstr);
					m_rcDest.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
				}
				else if (sItem == _T("source"))
				{
					m_rcSource.left = _tcstol(sValue.GetData(), &pstr, 10);  ASSERT(pstr);
					m_rcSource.top = _tcstol(pstr + 1, &pstr, 10);    ASSERT(pstr);
					m_rcSource.right = _tcstol(pstr + 1, &pstr, 10);  ASSERT(pstr);
					m_rcSource.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
				}
				else if (sItem == _T("corner"))
				{
					m_rcCorner.left = _tcstol(sValue.GetData(), &pstr, 10);  ASSERT(pstr);
					m_rcCorner.top = _tcstol(pstr + 1, &pstr, 10);    ASSERT(pstr);
					m_rcCorner.right = _tcstol(pstr + 1, &pstr, 10);  ASSERT(pstr);
					m_rcCorner.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
				}
				else if (sItem == _T("mask"))
				{
					if (sValue[0] == _T('#')) m_dwMask = _tcstoul(sValue.GetData() + 1, &pstr, 16);
					else m_dwMask = _tcstoul(sValue.GetData(), &pstr, 16);
				}
				else if (sItem == _T("fade"))
				{
					m_bFade = (BYTE)_tcstoul(sValue.GetData(), &pstr, 10);
				}
				else if (sItem == _T("hole"))
				{
					m_bHole = (_tcscmp(sValue.GetData(), _T("true")) == 0);
				}
				else if (sItem == _T("xtiled"))
				{
					m_bTiledX = (_tcscmp(sValue.GetData(), _T("true")) == 0);
				}
				else if (sItem == _T("ytiled"))
				{
					m_bTiledY = (_tcscmp(sValue.GetData(), _T("true")) == 0);
				}
			}
			if (*pStrImage++ != _T(' ')) break;
		}
	}

	CImageAttribute::operator LPCTSTR() const
	{
		return m_sImageAttribute;
	}

	bool CImageAttribute::operator==(LPCTSTR pStrImage) const
	{
		return m_sImageAttribute == pStrImage;
	}

	const CDuiString& CImageAttribute::operator=(const CDuiString& src)
	{
		SetAttributeString(src);
		return m_sImageAttribute;
	}

	const CDuiString& CImageAttribute::operator=(LPCTSTR lpStr)
	{
		SetAttributeString(lpStr);
		return m_sImageAttribute;
	}

	const CDuiString& CImageAttribute::operator=(const TCHAR ch)
	{
		m_sImageAttribute = ch;
		SetAttributeString(m_sImageAttribute);
		return m_sImageAttribute;
	}

       对CControlUI控件的修改如下:

bool CControlUI::DrawImage(HDC hDC, CImageAttribute& image, const RECT& rcDest, LPCTSTR pStrModify /*= NULL*/)
{
	if (!image.LoadImage(m_pManager))
		return false;

	if (pStrModify != NULL)
	{
		CImageAttribute modifyImage = image;
		modifyImage.ModifyAttribute(pStrModify);
		return CRenderEngine::DrawImage(hDC, m_pManager, rcDest, m_rcPaint, modifyImage);
	}
	return CRenderEngine::DrawImage(hDC, m_pManager, rcDest, m_rcPaint, image);
}

       为CRenderEngine类新增DrawImage函数代替DrawImageString函数:

bool CRenderEngine::DrawImage(HDC hDC, CPaintManagerUI* pManager, const RECT& rcControl, const RECT& rcPaint, CImageAttribute& image)
{
	if ((pManager == NULL) || (hDC == NULL))
		return false;

	if (image.m_sImage.IsEmpty())
		return false;

	TImageInfo* data = image.m_imageInfo;
	if (!data) return false;

	RECT rcDest = image.m_rcDest;
	rcDest.left += rcControl.left;
	rcDest.top += rcControl.top;
	rcDest.right = rcDest.left + rcControl.right;
	if (rcDest.right > rcControl.right)
		rcDest.right = rcControl.right;
	rcDest.bottom = rcDest.top + rcControl.bottom;
	if (rcDest.bottom > rcControl.bottom)
		rcDest.bottom = rcControl.bottom;

	RECT rcTemp;
	if (!::IntersectRect(&rcTemp, &rcDest, &rcControl)) return true;
	if (!::IntersectRect(&rcTemp, &rcDest, &rcPaint)) return true;

	CRenderEngine::DrawImage(hDC, data->hBitmap, rcDest, rcPaint, image.m_rcSource, image.m_rcCorner,
		pManager->IsBackgroundTransparent() ? true : data->alphaChannel,
		image.m_bFade, image.m_bHole, image.m_bTiledX, image.m_bTiledY);

	return true;
}


总结:

        这次修改的内容比较多,因为每个控件原本都有图片字符串,所以我把很多控件的绘制代码对应的修改了,这些就不贴了。所有控件的修改我都提交到我个人的Duilib库中: 点击打开链接


Redrain QQ:491646717 2016.4.26

目录
相关文章
|
6天前
|
XML 存储 数据格式
RAG效果优化:高质量文档解析详解
本文关于如何将非结构化数据(如PDF和Word文档)转换为结构化数据,以便于RAG(Retrieval-Augmented Generation)系统使用。
|
9天前
|
机器学习/深度学习 数据采集 存储
一文读懂蒙特卡洛算法:从概率模拟到机器学习模型优化的全方位解析
蒙特卡洛方法起源于1945年科学家斯坦尼斯劳·乌拉姆对纸牌游戏中概率问题的思考,与约翰·冯·诺依曼共同奠定了该方法的理论基础。该方法通过模拟大量随机场景来近似复杂问题的解,因命名灵感源自蒙特卡洛赌场。如今,蒙特卡洛方法广泛应用于机器学习领域,尤其在超参数调优、贝叶斯滤波等方面表现出色。通过随机采样超参数空间,蒙特卡洛方法能够高效地找到优质组合,适用于处理高维度、非线性问题。本文通过实例展示了蒙特卡洛方法在估算圆周率π和优化机器学习模型中的应用,并对比了其与网格搜索方法的性能。
80 1
|
11天前
|
开发者 图形学 Java
揭秘Unity物理引擎核心技术:从刚体动力学到关节连接,全方位教你如何在虚拟世界中重现真实物理现象——含实战代码示例与详细解析
【8月更文挑战第31天】Unity物理引擎对于游戏开发至关重要,它能够模拟真实的物理效果,如刚体运动、碰撞检测及关节连接等。通过Rigidbody和Collider组件,开发者可以轻松实现物体间的互动与碰撞。本文通过具体代码示例介绍了如何使用Unity物理引擎实现物体运动、施加力、使用关节连接以及模拟弹簧效果等功能,帮助开发者提升游戏的真实感与沉浸感。
27 1
|
11天前
|
开发者 图形学 API
从零起步,深度揭秘:运用Unity引擎及网络编程技术,一步步搭建属于你的实时多人在线对战游戏平台——详尽指南与实战代码解析,带你轻松掌握网络化游戏开发的核心要领与最佳实践路径
【8月更文挑战第31天】构建实时多人对战平台是技术与创意的结合。本文使用成熟的Unity游戏开发引擎,从零开始指导读者搭建简单的实时对战平台。内容涵盖网络架构设计、Unity网络API应用及客户端与服务器通信。首先,创建新项目并选择适合多人游戏的模板,使用推荐的网络传输层。接着,定义基本玩法,如2D多人射击游戏,创建角色预制件并添加Rigidbody2D组件。然后,引入网络身份组件以同步对象状态。通过示例代码展示玩家控制逻辑,包括移动和发射子弹功能。最后,设置服务器端逻辑,处理客户端连接和断开。本文帮助读者掌握构建Unity多人对战平台的核心知识,为进一步开发打下基础。
32 0
|
11天前
|
开发者 图形学 C#
揭秘游戏沉浸感的秘密武器:深度解析Unity中的音频设计技巧,从背景音乐到动态音效,全面提升你的游戏氛围艺术——附实战代码示例与应用场景指导
【8月更文挑战第31天】音频设计在游戏开发中至关重要,不仅能增强沉浸感,还能传递信息,构建氛围。Unity作为跨平台游戏引擎,提供了丰富的音频处理功能,助力开发者轻松实现复杂音效。本文将探讨如何利用Unity的音频设计提升游戏氛围,并通过具体示例代码展示实现过程。例如,在恐怖游戏中,阴森的背景音乐和突然的脚步声能增加紧张感;在休闲游戏中,轻快的旋律则让玩家感到愉悦。
24 0
|
11天前
|
开发者 图形学 C#
深度解密:Unity游戏开发中的动画艺术——Mecanim状态机如何让游戏角色栩栩如生:从基础设置到高级状态切换的全面指南,助你打造流畅自然的游戏动画体验
【8月更文挑战第31天】Unity动画系统是游戏开发的关键部分,尤其适用于复杂角色动画。本文通过具体案例讲解Mecanim动画状态机的使用方法及原理。我们创建一个游戏角色并设计行走、奔跑和攻击动画,详细介绍动画状态机设置及脚本控制。首先导入动画资源并添加Animator组件,然后创建Animator Controller并设置状态间的转换条件。通过编写C#脚本(如PlayerMovement)控制动画状态切换,实现基于玩家输入的动画过渡。此方法不仅适用于游戏角色,还可用于任何需动态动画响应的对象,增强游戏的真实感与互动性。
31 0
|
11天前
|
开发者 图形学 iOS开发
掌握Unity的跨平台部署与发布秘籍,让你的游戏作品在多个平台上大放异彩——从基础设置到高级优化,深入解析一站式游戏开发解决方案的每一个细节,带你领略高效发布流程的魅力所在
【8月更文挑战第31天】跨平台游戏开发是当今游戏产业的热点,尤其在移动设备普及的背景下更为重要。作为领先的游戏开发引擎,Unity以其卓越的跨平台支持能力脱颖而出,能够将游戏轻松部署至iOS、Android、PC、Mac、Web及游戏主机等多个平台。本文通过杂文形式探讨Unity在各平台的部署与发布策略,并提供具体实例,涵盖项目设置、性能优化、打包流程及发布前准备等关键环节,助力开发者充分利用Unity的强大功能,实现多平台游戏开发。
28 0
|
11天前
|
图形学 开发者
【Unity光照艺术手册】掌握这些技巧,让你的游戏场景瞬间提升档次:从基础光源到全局光照,打造24小时不间断的视觉盛宴——如何运用代码与烘焙创造逼真光影效果全解析
【8月更文挑战第31天】在Unity中,合理的光照与阴影设置对于打造逼真环境至关重要。本文介绍Unity支持的多种光源类型,如定向光、点光源、聚光灯等,并通过具体示例展示如何使用着色器和脚本控制光照强度,模拟不同时间段的光照变化。此外,还介绍了动态和静态阴影、全局光照及光照探针等高级功能,帮助开发者创造丰富多样的光影效果,提升游戏沉浸感。
26 0
|
11天前
|
开发者 图形学 UED
深度解析Unity游戏开发中的性能瓶颈与优化方案:从资源管理到代码执行,全方位提升你的游戏流畅度,让玩家体验飞跃性的顺滑——不止是技巧,更是艺术的追求
【8月更文挑战第31天】《Unity性能优化实战:让你的游戏流畅如飞》详细介绍了Unity游戏性能优化的关键技巧,涵盖资源管理、代码优化、场景管理和内存管理等方面。通过具体示例,如纹理打包、异步加载、协程使用及LOD技术,帮助开发者打造高效流畅的游戏体验。文中提供了实用代码片段,助力减少内存消耗、提升渲染效率,确保游戏运行丝滑顺畅。性能优化是一个持续过程,需不断测试调整以达最佳效果。
25 0
|
11天前
|
开发者 C# Windows
WPF与游戏开发:当桌面应用遇见游戏梦想——利用Windows Presentation Foundation打造属于你的2D游戏世界,从环境搭建到代码实践全面解析新兴开发路径
【8月更文挑战第31天】随着游戏开发技术的进步,WPF作为.NET Framework的一部分,凭借其图形渲染能力和灵活的UI设计,成为桌面游戏开发的新选择。本文通过技术综述和示例代码,介绍如何利用WPF进行游戏开发。首先确保安装最新版Visual Studio并创建WPF项目。接着,通过XAML设计游戏界面,并在C#中实现游戏逻辑,如玩家控制和障碍物碰撞检测。示例展示了创建基本2D游戏的过程,包括角色移动和碰撞处理。通过本文,WPF开发者可更好地理解并应用游戏开发技术,创造吸引人的桌面游戏。
36 0

热门文章

最新文章

推荐镜像

更多