﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-&lt;font size=5&gt;李锦俊的blog&lt;/font&gt; 本Blog永久域名:www.lijinjun.com</title><link>http://www.cppblog.com/mybios/</link><description>游戏开发 C++ DirectX 数学 计算机图形学 SQL Server
&lt;BR&gt;
&lt;BR&gt;
&lt;a href="http://www.lijinjun.com" style="font-size:14px;color:#FFFFFF"&gt;返回我的Blog首页&lt;/a&gt;</description><language>zh-cn</language><lastBuildDate>Sun, 05 Jul 2009 20:17:20 GMT</lastBuildDate><pubDate>Sun, 05 Jul 2009 20:17:20 GMT</pubDate><ttl>60</ttl><item><title>在VS2005调试器中显示Unreal3的数据</title><link>http://www.cppblog.com/mybios/archive/2009/05/24/85618.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 24 May 2009 09:13:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2009/05/24/85618.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/85618.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2009/05/24/85618.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/85618.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/85618.html</trackback:ping><description><![CDATA[Unreal3引擎中，大量使用了自定义的模版或数据类型，比如TArray、FName、FString等等，对于这三种数据类型，我们无法在VS2005中直接查看他们的值（起码不能像std::vector/std::string一样直观查看）。<br>通过msdn，得知vs2005的autoexp.dat可以可以给自定义的数据类型编写可视化脚本从而实现直观的调试。<br>经过一番研究，实现了对Unreal3数据类型的直观的可视化调试，方法如下：<br><br>打开vs2005目录中的autoexp.dat文件<br><br>找到[AutoExpand]，在[AutoExpand]的下面添加一行:<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">FNameEntry</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&lt;Name</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">su&gt;</span></div>
<br><br>翻到文件最后，添加以下代码到文件的最后：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">;</span><span style="COLOR: #008000">&nbsp;Unreal格式的数组</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">TArray&lt;*&gt;{<br>&nbsp;&nbsp;&nbsp;&nbsp;children<br>&nbsp;&nbsp;&nbsp;&nbsp;(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#array<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;expr&nbsp;:&nbsp;&nbsp;&nbsp;&nbsp;(($T1*)($c.Data))</span><span style="FONT-WEIGHT: bold; COLOR: #800000">[</span><span style="COLOR: #800000">$i</span><span style="FONT-WEIGHT: bold; COLOR: #800000">]</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size&nbsp;:&nbsp;&nbsp;&nbsp;&nbsp;$c.ArrayNum<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br>&nbsp;&nbsp;&nbsp;&nbsp;)<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;preview<br>&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">[</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$c.ArrayNum&nbsp;</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">](</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#array<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;expr&nbsp;:&nbsp;(($T1*)($c.Data))</span><span style="FONT-WEIGHT: bold; COLOR: #800000">[</span><span style="COLOR: #800000">$i</span><span style="FONT-WEIGHT: bold; COLOR: #800000">]</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size&nbsp;:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$c.ArrayNum<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br>&nbsp;&nbsp;&nbsp;&nbsp;)<br>}<br><br></span><span style="COLOR: #008000">;</span><span style="COLOR: #008000">&nbsp;Unreal格式的FName</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">FName{<br>&nbsp;&nbsp;&nbsp;&nbsp;preview(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">[</span><span style="COLOR: #800000">((FNameEntry**)FName.Names.Data)[$c.Index</span><span style="FONT-WEIGHT: bold; COLOR: #800000">]</span><span style="COLOR: #000000">])<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stringview(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">[</span><span style="COLOR: #800000">((FNameEntry**)FName.Names.Data)[$c.Index</span><span style="FONT-WEIGHT: bold; COLOR: #800000">]</span><span style="COLOR: #000000">])<br>}<br></span><span style="COLOR: #008000">;</span><span style="COLOR: #008000">&nbsp;Unreal格式的字符串</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">FString{<br>&nbsp;&nbsp;&nbsp;&nbsp;preview(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">[</span><span style="COLOR: #800000">$c.Data,su</span><span style="FONT-WEIGHT: bold; COLOR: #800000">]</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stringview(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">[</span><span style="COLOR: #800000">$c.Data,su</span><span style="FONT-WEIGHT: bold; COLOR: #800000">]</span><span style="COLOR: #000000">)<br>}</span></div>
<br>然后，到调试器里尽情看TArray、FString、FName等等平时不容易看的数据吧。效果图就不贴了。<br>此方法可以举一反三，用来实现对任意数据类型的查看。<br><br><br>
<img src ="http://www.cppblog.com/mybios/aggbug/85618.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2009-05-24 17:13 <a href="http://www.cppblog.com/mybios/archive/2009/05/24/85618.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《软件调试》读书随笔续</title><link>http://www.cppblog.com/mybios/archive/2008/12/21/70006.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 21 Dec 2008 09:58:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2008/12/21/70006.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/70006.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2008/12/21/70006.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/70006.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/70006.html</trackback:ping><description><![CDATA[711页 介绍了VC编译器对异常机制的实现方式<br>810页 利用DBGHELP函数回溯栈，可以可编程的记录当时的调用栈详细信息<br>814页 利用RTL函数回溯栈，非常快速的回溯栈，但只记录函数指针，不记录函数名和函数参数，后期如果要看函数名，需要通过PDB文件和UMDH这样的工具来翻译成函数名。但是对于大量的调用速度将会很快。<br>815页 讲述并实现了一个用来检视某地址被访问的记录，能记录下这个地址被访问的时间、调用堆栈等等信息。<br>824页 介绍了使用Windows性能监视器来编写性能监视功能的方法（如监视游戏FPS变化）<br>830页 介绍了/Gh/GH编译开关的作用：监视所有函数的进出 
<img src ="http://www.cppblog.com/mybios/aggbug/70006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2008-12-21 17:58 <a href="http://www.cppblog.com/mybios/archive/2008/12/21/70006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《软件调试》读书随笔</title><link>http://www.cppblog.com/mybios/archive/2008/12/20/69933.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sat, 20 Dec 2008 13:51:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2008/12/20/69933.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/69933.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2008/12/20/69933.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/69933.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/69933.html</trackback:ping><description><![CDATA[<p>几个非常有用的技术：<br>421页 ETW 架构，比较适合用来记录大量日志<br>699页 _heapchk()函数可以手工检查堆内容是否有缓存溢出<br>661页 低碎片堆，内核级别的小内存分配器<br>666页 栈回溯数据库，用来记录所有分配内存时的调用栈信息。</p>
<img src ="http://www.cppblog.com/mybios/aggbug/69933.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2008-12-20 21:51 <a href="http://www.cppblog.com/mybios/archive/2008/12/20/69933.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>介绍本近期出的好书《软件调试》</title><link>http://www.cppblog.com/mybios/archive/2008/12/13/69371.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sat, 13 Dec 2008 14:18:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2008/12/13/69371.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/69371.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2008/12/13/69371.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/69371.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/69371.html</trackback:ping><description><![CDATA[《软件调试》，是2008年6月份出的新书，我觉得比较适合用C++用了比较长时间的人看，这可以提高他们的调试水平。其实，评价一个人是否是编程高手，主要还是看当程序出问题时调试能力。<br>这本书在当当网上打折后是96元。<br>以下是这本书的一些介绍：<br>ACM院士和调试技术先驱Jack B.Dennis教授做历史回顾计算机和操作系统领域资深专家David A.Solomon撰写序言。调试高手笔耕三载集十余年经验成百万言篇，业内专家鼎力相助，汇五十年精华补软件界空白。<br>　　您将学习到：<br>　　CPU的调试支持，包括异常、断点、单步执行、分支监视、JTAG、MCE等。<br>　　Windows操作系统中的调试设施，包括内核调试引擎、用户态调试予系统、验证器、Dr.Watson、WER、ETW、故障转储、WHEA等。<br>　　Visual C／C++编译器的调试支持，包括编译期检查、运行期检查，以及调试符号。<br>　　WinDBG调试器的发展历史、模块结构、工作模型、使用方法、主要调试功能的实现细节，以及遍布全书的应用实例。<br>　　内核调试、用户态调试、JIT调试、远程调试的原理、实现和用法。异常的概念、分发方法、处理方法（SEH、VEH、CppEH），未处理异常，以及编译器编译异常处理代码的方法。<br>　　调试符号的作用、产生过程、存储格式和使用方法。栈和堆的结构布局、工作原理和有关的软件问题，包括栈的自动增长和溢出，缓；中区溢出，溢出攻击，内存泄漏，堆崩溃等。<br>　　软件的可调试性和提高可调试性的方法。<br>　　此外，书中还诠释了很多较难理解的概念，思考了一系列耐人深思和具有普遍意义的问题。本书是对软件调试技术在过去50年中所取得成就的全面展示，也是笔者本人在软件设计和系统开发第一线奋战10多年的经验总结。本书适合每一位希望深刻理解软件和自由驾驭软件的人阅读，不论您是否直接参与软件开发和测试；不论您是热爱软件，还是憎恨软件；不论您是想发现软件中的瑕疵，还是想领略其中蕴含的智慧！<br>　　本书直面软件工程中的最困难任务——侦错<br>　　围绕软件世界中的最强大工具——调试器<br>　　全方位展示了软件调试技术的无比威力和无穷魅力<br>　　80个示例程序的源程序文件和项目文件<br>　　浏览符号文件的SymView工具<br>　　与内核调试引擎对话的KdTalker工具<br>　　直接浏览用户态转储文件的UdmpView工具<br>　　显示CPU执行轨迹（分支）的Cpuwhere工具<br>　　观察IDT、GDT和系统对象的SOZOOmer工具<br>　　本书是对软件调试技术在过去50年中所取得成就的全面展示，也是对作者本人在软件设计和系统开发第一线奋战10多年的经验总结。全书共分6篇30章，选取了大量具有代表性和普遍意义的技术细节进行讨论，包括CPU的调试支持、操作系统的调试支持、编译器的调试支持、WinDBG及其实现等，是学习软件调试技术的宝贵资料。该书可供各大专院校作为教材使用，也可供从事相关工作的人员作为参考用书使用。
<img src ="http://www.cppblog.com/mybios/aggbug/69371.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2008-12-13 22:18 <a href="http://www.cppblog.com/mybios/archive/2008/12/13/69371.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>魔兽争霸3自动拼接地形渲染源码与执行程序下载</title><link>http://www.cppblog.com/mybios/archive/2008/10/31/65636.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Fri, 31 Oct 2008 11:51:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2008/10/31/65636.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/65636.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2008/10/31/65636.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/65636.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/65636.html</trackback:ping><description><![CDATA[这里发的源码是针对上次的文章的源码http://www.cppblog.com/mybios/archive/2008/10/26/65076.html<br><a href="http://www.cppblog.com/Files/mybios/源码与执行程序.part01.rar">http://www.cppblog.com/Files/mybios/源码与执行程序.part01.rar</a><br><a href="http://www.cppblog.com/Files/mybios/源码与执行程序.part02.rar">http://www.cppblog.com/Files/mybios/源码与执行程序.part02.rar</a><br><a href="http://www.cppblog.com/Files/mybios/源码与执行程序.part03.rar">http://www.cppblog.com/Files/mybios/源码与执行程序.part03.rar</a><br><a href="http://www.cppblog.com/Files/mybios/源码与执行程序.part04.rar">http://www.cppblog.com/Files/mybios/源码与执行程序.part04.rar</a><br><a href="http://www.cppblog.com/Files/mybios/源码与执行程序.part05.rar">http://www.cppblog.com/Files/mybios/源码与执行程序.part05.rar</a><br><br>发现有的人运行不了程序，是由于没安装vc2008的redist导致的。请下载安装之：<br><a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=A5C84275-3B97-4AB7-A40D-3802B2AF5FC2&amp;displaylang=zh-cn">http://www.microsoft.com/downloads/details.aspx?FamilyID=A5C84275-3B97-4AB7-A40D-3802B2AF5FC2&amp;displaylang=zh-cn</a><br>
<img src ="http://www.cppblog.com/mybios/aggbug/65636.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2008-10-31 19:51 <a href="http://www.cppblog.com/mybios/archive/2008/10/31/65636.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>魔兽争霸3的自动拼接地形渲染方式</title><link>http://www.cppblog.com/mybios/archive/2008/10/26/65076.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 26 Oct 2008 04:16:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2008/10/26/65076.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/65076.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2008/10/26/65076.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/65076.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/65076.html</trackback:ping><description><![CDATA[<p align=left>源码已发布，请打开下载<a href="http://www.cppblog.com/mybios/archive/2008/10/31/65636.html">http://www.cppblog.com/mybios/archive/2008/10/31/65636.html</a><br>上次发了个这样的图，结果被某些人鄙视了，很郁闷啊。<br><br>我们把一个魔兽3的草地贴图提取出来，并且用下面的分块方法来标示每一块小贴图，然后通过一种特定的方式来组织这些小贴图，形成真正的地表贴图。<br>魔兽争霸编辑器中刷地表时，刷一格就会影响四个周围的渲染块，具体如何影响？请看下图：<br><br>这是贴图的分块索引方法：<br><img height=256 alt="" src="http://www.cppblog.com/images/cppblog_com/mybios/Lords_Grass.tga.jpg" width=512 border=0><br><br><br><br>通过魔兽争霸地图编辑器点一下刷地表草之后，在地图中就会出现一小块绿色草地地表，请注意在图中我用数字1、2、4、8来表示四个渲染块对应的贴图索引，而这个1、2、4、8是固定的。代表的是相对于笔刷位置（笔刷位置是指周围四个渲染块中间位置）来说，左下角的角落贴图索引是1；右下角的角落贴图索引是2；左上角的角落贴图索引是4；右上角的角落贴图索引是8。如下图所示：<br><img height=465 alt="" src="http://www.cppblog.com/images/cppblog_com/mybios/1.jpg" width=651 border=0><br><br><br>如果在已经有草地的地表旁边再点一下刷地表，会刷成如下图这个样子：<br>看明白8+4=12没有？这里是两个角落贴图索引相加后的结果，得到12，就从文章开头的索引贴图中找到12对应的小贴图贴上去。<br>2+1=3同理，用两个角落贴图索引相加后的结果3从索引贴图中找到3对应的小贴图贴上去。<br>这样得到的效果就会变成如下图：<br><img height=531 alt="" src="http://www.cppblog.com/images/cppblog_com/mybios/2.jpg" width=923 border=0><br><br><br>这里有是更复杂的情况，有三个角落相加，1+8+4=13，不过道理都是一样的。<br><img height=768 alt="" src="http://www.cppblog.com/images/cppblog_com/mybios/3.jpg" width=1034 border=0><br><br>最后说一下四周都有贴图的情况，看到中间笔刷位置没有？笔刷左上方有一个贴图，对应的是贴图索引中的0，这是因为他四个角都填充了，所以就需要从0、16~31中随机选择一个小贴图贴上去以完整的填充整个渲染块：<br><img height=768 alt="" src="http://www.cppblog.com/images/cppblog_com/mybios/4.JPG" width=899 border=0><br><br>至此贴图选择的方法已经说完了。<br>至于渲染的方法，都是大同小异，这里就不多说了。<br></p>
<img src ="http://www.cppblog.com/mybios/aggbug/65076.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2008-10-26 12:16 <a href="http://www.cppblog.com/mybios/archive/2008/10/26/65076.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深圳网域高薪诚聘Ogre 3D程序员</title><link>http://www.cppblog.com/mybios/archive/2008/03/19/44855.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Wed, 19 Mar 2008 07:04:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2008/03/19/44855.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/44855.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2008/03/19/44855.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/44855.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/44855.html</trackback:ping><description><![CDATA[<p>深圳网域高薪诚聘:<br>职位:高级3D程序员<br>1、计算机图形学基础扎实，精通D3D或OpenGL。<br>2、精通常见室外、室内渲染技术，如地形渲染、LOD、多叉树、bsp、portal等。<br>3、熟悉各种3D性能优化技术，对3D引擎性能优化有丰富经验。<br>4、精通vertex shader 、 pixel shader 、 HLSL。<br>5、熟悉OGRE等一种或多种常见游戏引擎者优先。<br>6、精通C++，有大型软件系统开发应验者优先。<br>7、熟悉网络游戏，熟悉热爱网络游戏事业，有良好的团队意识和沟通能力</p>
<p>公司地址：深圳市南山高新科技园中区高新四路维用大厦三楼<br>公司网址：<a href="http://www.szdomain.com/">www.szdomain.com</a><br>邮　　箱：<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#109;&#121;&#98;&#105;&#111;&#115;&#64;&#113;&#113;&#46;&#99;&#111;&#109;">mybios@qq.com</a>&nbsp; <br>Q&nbsp;&nbsp;&nbsp; Q: 30743734</p>
<img src ="http://www.cppblog.com/mybios/aggbug/44855.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2008-03-19 15:04 <a href="http://www.cppblog.com/mybios/archive/2008/03/19/44855.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>刚完成了一个基于Ogre渲染的世界编辑器，发图留念</title><link>http://www.cppblog.com/mybios/archive/2008/03/09/44046.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 09 Mar 2008 14:55:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2008/03/09/44046.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/44046.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2008/03/09/44046.html#Feedback</comments><slash:comments>27</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/44046.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/44046.html</trackback:ping><description><![CDATA[<p>这个世界编辑器，从一开始设计的时候就考虑使用即见即所得的形式来实现，地图载入、保存等等操作是独立封装在一个叫DisplaySystem的Dll中，而世界编辑器使用插件的形式来实现各种功能，如：地形编辑插件、网格插件、物件编辑插件、环境编辑插件等等。用插件的形式实现的好处很多，以后要增加新功能的时候世界编辑器本身的代码就不需要修改了。而且对于团队开发也很有利，一个人负责一个插件的开发就可以。<br>发几个图：<br><br>以下是没有启用插件的模式：<br><img src="http://www.cppblog.com/images/cppblog_com/mybios/WorldEditor.jpg" border=0><br><br>以下是启用了地形编辑器插件的模式：<br><img src="http://www.cppblog.com/images/cppblog_com/mybios/TerrainEditor.jpg" border=0><br><br>以下是启用了物件编辑器插件的模式：<br><img height=768 src="http://www.cppblog.com/images/cppblog_com/mybios/NoPlugins.jpg" width=1257 border=0><br></p>
<img src ="http://www.cppblog.com/mybios/aggbug/44046.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2008-03-09 22:55 <a href="http://www.cppblog.com/mybios/archive/2008/03/09/44046.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ogre 的渲染到纹理的关键的3个步骤</title><link>http://www.cppblog.com/mybios/archive/2007/12/27/39764.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Thu, 27 Dec 2007 13:06:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/12/27/39764.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/39764.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/12/27/39764.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/39764.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/39764.html</trackback:ping><description><![CDATA[<p>好久没写技术的东西了。现在辗转间又回到了深圳工作，还是做我喜欢的游戏开发。奉献点东西给大家。</p>
<p><br>1、创建渲染目标纹理，关键要指定TU_RENDERTARGET参数，在创建这个渲染目标纹理的过程中，Ogre会自动调用&nbsp; Root::getSingleton().getRenderSystem()-&gt;attachRenderTarget把这个纹理添加到Root的渲染目标中，也就是说每帧都会渲染到这个纹理。<br>TexturePtr texture = TextureManager::getSingleton().createManual( "RttTex", <br>&nbsp;ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, <br>&nbsp;512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );</p>
<p>2、获得渲染目标，有了渲染目标，才能给目标指定视口和摄像机<br>RenderTarget *rttTex = texture-&gt;getBuffer()-&gt;getRenderTarget();</p>
<p>3、给这个渲染目标指定摄像机，做了这步骤之后，每帧更新时就会把这个摄像机看到的东西渲染到texture中<br>Viewport *v = rttTex-&gt;addViewport( mReflectCam );</p>
<p>4、OK！</p>
<img src ="http://www.cppblog.com/mybios/aggbug/39764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-12-27 21:06 <a href="http://www.cppblog.com/mybios/archive/2007/12/27/39764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>魔兽3贴图方法</title><link>http://www.cppblog.com/mybios/archive/2007/08/28/31043.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Tue, 28 Aug 2007 10:57:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/08/28/31043.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/31043.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/08/28/31043.html#Feedback</comments><slash:comments>16</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/31043.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/31043.html</trackback:ping><description><![CDATA[关键在于他的贴图的索引方式。如下所示。明眼人就能看出规律来。<br>只能说这么多了。公司有保密制度。请见谅！<br><br><img height=256 alt="" src="http://www.cppblog.com/images/cppblog_com/mybios/Lords_Grass.tga.jpg" width=512 border=0>
<img src ="http://www.cppblog.com/mybios/aggbug/31043.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-08-28 18:57 <a href="http://www.cppblog.com/mybios/archive/2007/08/28/31043.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>终于实现了魔兽3贴图算法，发图留念</title><link>http://www.cppblog.com/mybios/archive/2007/08/28/31021.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Tue, 28 Aug 2007 07:00:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/08/28/31021.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/31021.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/08/28/31021.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/31021.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/31021.html</trackback:ping><description><![CDATA[魔兽3的地形贴图算法非常的巧妙。不过，认真观看他的地图编辑器和用工具导出他的地形贴图看看，还是可以摸出规律来的。<br><br><img height=627 alt="" src="http://www.cppblog.com/images/cppblog_com/mybios/WC3.JPG" width=808 border=0>
<img src ="http://www.cppblog.com/mybios/aggbug/31021.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-08-28 15:00 <a href="http://www.cppblog.com/mybios/archive/2007/08/28/31021.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于CEGUI的String的调试问题</title><link>http://www.cppblog.com/mybios/archive/2007/07/29/28914.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 29 Jul 2007 02:17:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/07/29/28914.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/28914.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/07/29/28914.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/28914.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/28914.html</trackback:ping><description><![CDATA[CEGUI的String不是std::string或std::wstring，而是自己实现的一个字符串类，他的功能跟std的string很接近。<br>但是，他支持unicode，内部存储是使用utf32编码规范来存储unicode字符，也就是说&nbsp;typedef&nbsp;&nbsp;uint32&nbsp;utf32; utf32*&nbsp;&nbsp;d_buffer;用这个32位无符号整型的数组来保存unicode字符串。优点是显而易见的，就是世界上所有字符都可以包囊进去，毕竟是32位啊！但是，缺点也出来了，有两点：<br>第一、内存占用过多，一个字符就要占4个字节，也太浪费了点；<br>第二、调试不方便，由于VS2005的调试窗口只支持ansi和utf16的格式，所以，CEGUI的String在调试器中只能看到一堆数字数组，而看不到字符，这是很郁闷的，每次要查看都要翻到内存那里看，而且还一堆乱码，超级麻烦。<br><br>解决办法：修改String类，使用utf16来代替CEGUI的utf32。<br>优点：<br>解决了内存占用过多的问题，一个字符只要2个字节就可以了；<br>解决了调试问题，VS2005直接支持utf16的显示。<br>缺点：<br>可能不支持全世界的字符，因为utf16不能表示超过16位的字符，但是，对于大多数国家的字符来说，已经足够了，毕竟windows2000/xp也是基于utf16编码的。<br><br>然后，下面是修改后的字符串类：<a title=CEGUIString href="http://www.cppblog.com/Files/mybios/CEGUIString.rar">CEGUIString</a><br>
<img src ="http://www.cppblog.com/mybios/aggbug/28914.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-07-29 10:17 <a href="http://www.cppblog.com/mybios/archive/2007/07/29/28914.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在windows下使用patch工具更新源码</title><link>http://www.cppblog.com/mybios/archive/2007/07/28/28900.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sat, 28 Jul 2007 09:09:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/07/28/28900.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/28900.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/07/28/28900.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/28900.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/28900.html</trackback:ping><description><![CDATA[经常在网上看到有人发布patch文件来更新他们的开源代码，例如cegui、ogre等都使用这种形式来修bug或者增加一些小功能。<br>但是，我们下载到的patch文件，貌似是linux/unix的diff工具生成的，要用linux/unix的patch工具才能把补丁文件更新到源码中。<br>后来，我发现了个windows下可以使用的patch工具，网址如下：<a href="http://gnuwin32.sourceforge.net/packages/patch.htm">http://gnuwin32.sourceforge.net/packages/patch.htm</a><br>使用是很简单的，用命令行方式执行：<br>patch 源文件 补丁文件<br><br>例如我们有源文件test.cpp，下载了个补丁文件test.patch，那么执行patch test.cpp test.patch，就会自动把patch里的内容更新到test.cpp中去了。<br><br>PS：cygwin貌似也有这个工具吧。。以前看过里面好像还有diff工具，可以生成patch文件，呵呵。
<img src ="http://www.cppblog.com/mybios/aggbug/28900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-07-28 17:09 <a href="http://www.cppblog.com/mybios/archive/2007/07/28/28900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于GOOF的新版本</title><link>http://www.cppblog.com/mybios/archive/2007/07/18/28250.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Wed, 18 Jul 2007 01:21:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/07/18/28250.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/28250.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/07/18/28250.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/28250.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/28250.html</trackback:ping><description><![CDATA[我们现在用的是比较老的版本了，昨天特意到官网上问那个作者，终于得到了明确答复，说是8月中旬就会发布新版本。贴一些作者说的话：<br><br><span class=postbody><font size=2>Yeah, I'm currently hard at work on the core engine, as the editor is nearly complete. The major feature I need to add for the editor is the ability to add new object definitions without needing to go through text files, but I'm a bit burned out on the editor part so I'm taking a break and working on one of the biggest engine features that needs some work: handling meshes. <br><br>Basically I'm reworking the MeshGameObject class completely so it's more viable for large worlds. <br><br>As far as features go before I release alpha, the list is still sorta large. <br><br>1. Finish the physics system so that it can be used for character movement. <br>2. An attachment system to be able to specify attachment locations on an object and attach any other object to it. <br>3. Mesh animation, animation blending, animation sharing between objects. <br>4. Character class which plays animations based on current state (movement direction, velocity, jumping, strafing, etc.) <br>5. Redo the mesh system (in progress). This is a biggy and involves a lot crazy stuff that is too complex to explain in bullet point. Basically, will be using all of Ogre's advanced features for mesh lods, material lods, etc. but also tie into background resource loading, load only the lods that are necessary, track which lods are currently loaded, etc. <br>6. Ability to add, update and delete meta objects from the editor using property dialog functionality. Once a meta object is updated, call a function on all objects that use that meta data so they can update themselves with newest data. <br>7. Managed material system <br>8. Create plugins of all dlls and dynamically load. <br>9. Create a viewer application that is separate from the editor and can load any world file. <br>10. Update the lighting system, particle system, to use new fading code based on updated mesh code <br><br>Those are my major todos, once finished and tested I release alpha. I will likely update CVS after I get the meta objects finished though. I may also fit in the vegetation system before I release alpha. How long will the above list take? Based on my current speed of development, 3 months. <br><br>I have a core list of features that I think are necessary for an engine, and they include: <br><br>1. Physics simulation, character movement, vehicles, damage, explosions, breakable objects <br>2. Lighting - ambient occlusion, realtime lighting and shadows. Lighting manager is required to control ambient, shadows when moving from interior to exterior <br>3. Trees and vegetation <br>4. Dynamic environment. Sky transitioning, clouds, fog, global ambient, sun position and direction, sun glare, dynamic shadows <br>5. Networking using ReplicaNet. Run GOOF engine in server mode where it doesn't initialize any rendering systems. Update all objects to know whether they're being created on standalone server or not. <br>6. Sound management, 2d sounds, 3d sounds, sound line, background music. <br>7. Doors, triggers, elevators <br>8. In-game cutscenes <br>9. Background loading, resource garbage collection, forced loading <br>10. AI framework <br>11. Character inventory, equipping with 3 clothing types: shared skeleton, individual skeleton, attached to bone <br>12. Terrain with splatting <br><br>The above will take me years unless I have help </font><img alt=Smile src="http://www.ogre3d.org/phpBB2addons/images/smiles/icon_smile.gif" border=0><br><br><span class=postbody><font size=2>Oh yeah, the editor is very nice now, in my opinion. <br><br>Not only did I port to wxWidgets, I fixed and added a lot of general features to the GOOF Engine Editor Tool (the tool for creating scenes for the GOOF engine). <br><br>1. Multi select objects from the selection dialog <br>2. Ctrl drag to box select objects in the viewport, or Alt drag to box unselect, with selection lines to show what you're selecting. <br>3. Option to orient objects to the normal of the collided object when in drag mode. Means you can basically drag things up walls now if you're in a room and the object, such as a painting, will orient to the wall you drag it along. <br>4. Redid the movement axis manipulator so it now moves to exactly where you want it to move to instead of sliding along crazily. <br>5. Added a line that shows what you're linking to when you are in link mode. <br>6. Tree view for the select dialog, with scene hierarchy <br>7. Ability to click and edit partition properties from the same select dialog, and shows objects under their partition with the active partition listed at the top. <br>8. Obviously, all the wxWidgets stuff such as window snapping, toolbar, menu, automatic viewport resizing, view menu which lists windows, redid all the open/save functionality to support a standard file dialog, etc. <br><br>Fixed tons of bugs. Undo system works now. Linking and unlinking objects fixed. Deleting multiple objects fixed when there are parent/child relationships between objects. The movement axis manipulator fixed. Fixed dragging over other objects - the object used to jump around crazily. <br><br>Probably tons more as well, but this is what I remember off the top of my head. </font><br><br><img src="http://www.larabie.net/ogre/GOOFEditorSep29-06.JPG" border=0></span></span>
<img src ="http://www.cppblog.com/mybios/aggbug/28250.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-07-18 09:21 <a href="http://www.cppblog.com/mybios/archive/2007/07/18/28250.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于GOOF的bug问题</title><link>http://www.cppblog.com/mybios/archive/2007/07/16/28157.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Mon, 16 Jul 2007 14:53:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/07/16/28157.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/28157.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/07/16/28157.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/28157.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/28157.html</trackback:ping><description><![CDATA[<p>使用了几天GOOF，发现他存在很多bug啊，什么缓存溢出，数组越界之类的。。很明显这个框架没有真正用在一个项目上的。我列举几个大问题吧。好让大家别到处碰壁。<br>首先，最严重的bug莫过于这个<br>vector&lt;CoreGameObject*&gt;::iterator itr = mObjects.begin();<br>for(; itr != mObjects.end(); ++itr)<br>所有这种写法都是错误的！要改成for(vector&lt;CoreGameObject*&gt;::iterator itr = mObjects.begin();<br>&nbsp;itr != mObjects.end(); ++itr)<br><br>其次，bool EnvironmentGameSystem::save(DataElementPtr element)这个函数没有实现，所以无法保存环境信息。<br><br>还有<br>&nbsp;void GridPartition::enumerateConnectedPartitions(vector&lt;CorePartition*&gt;&amp; connected)<br>&nbsp;{<br>&nbsp;&nbsp;//get surrounding grid cells within a certain radius<br>&nbsp;&nbsp;float loadRadius = mGridPartitionMgr-&gt;getGridCellLoadRadius();</p>
<p>&nbsp;&nbsp;//enumerate partitions<br>&nbsp;&nbsp;vector&lt;CorePartition*&gt; partitions;<br>&nbsp;&nbsp;mGridPartitionMgr-&gt;enumeratePartitions(partitions);</p>
<p>&nbsp;&nbsp;//iterate through and check distance<br>&nbsp;&nbsp;for(vector&lt;CorePartition*&gt;::iterator itr = partitions.begin(); itr != partitions.end(); ++itr)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;float distance = Vector3(getWorldPosition() - (*itr)-&gt;getWorldPosition()).length();<br>&nbsp;&nbsp;&nbsp;// add by 李锦俊 2007-7-16<br>&nbsp;&nbsp;&nbsp;// 不要返回自己作为邻居，会产生bug<br>&nbsp;&nbsp;&nbsp;if(distance &lt; loadRadius &amp;&amp; *itr != this)<br>&nbsp;&nbsp;&nbsp;&nbsp;connected.push_back(*itr);<br>&nbsp;&nbsp;}<br>&nbsp;}<br><br>再给出一个比较严重的bug<br>GOOFTranslationManipulator.h中的<br>&nbsp;&nbsp;// add by 李锦俊 2007-7-12<br>&nbsp;&nbsp;// 不要用魔术数，搞到缓存溢出<br>&nbsp;&nbsp;SceneNode* mNode[AT_LAST];<br>&nbsp;&nbsp;Entity* mEnt[AT_LAST];<br>&nbsp;&nbsp;Entity* mConeEnt[AT_LAST];<br>&nbsp;&nbsp;CollisionShapePtr mCol[AT_LAST];<br>&nbsp;&nbsp;AxisManipulatorHandle* mHandle[AT_LAST];<br><br>另外，CorePartition中的setSkyboxMaterial、setGlobalAmbient之类的代码貌似没用。准备弃之。<br></p>
<br>&nbsp;&nbsp;&nbsp;&nbsp;// add by 李锦俊 2007-7-16<br>&nbsp;&nbsp;&nbsp;&nbsp;// 这个算法暂时有问题，先屏蔽，以后再慢慢解决<br>&nbsp;&nbsp;&nbsp;&nbsp;//disable static geometry until it is fixed<br>&nbsp;&nbsp;&nbsp;&nbsp;if(false)// getStaticGeometryRule() == SGR_ALWAYS || (getStaticGeometryRule() == SGR_WHEN_NOT_PROX_IMMEDIATE &amp;&amp; getPartition()-&gt;getProximity() != CorePartition::PROX_IMMEDIATE)) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;willConvertToStaticGeometry = true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getPartition()-&gt;addObjectToConvertToStaticGeometry(this);<br>&nbsp;&nbsp;&nbsp;&nbsp;}
<img src ="http://www.cppblog.com/mybios/aggbug/28157.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-07-16 22:53 <a href="http://www.cppblog.com/mybios/archive/2007/07/16/28157.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于OGRE渲染引擎的地形插件PLSM2的编辑器GOOF</title><link>http://www.cppblog.com/mybios/archive/2007/07/06/27620.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Fri, 06 Jul 2007 12:28:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/07/06/27620.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/27620.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/07/06/27620.html#Feedback</comments><slash:comments>15</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/27620.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/27620.html</trackback:ping><description><![CDATA[这个地形引擎相当的不错，支持无限大，自动分页，局部载入，支持多贴图。但是，我初次的使用过程中遇到了两个问题，第一是不知道如何增加纹理贴图的数量，第二是不知道为何分页的地方会有裂缝，看来要慢慢阅读他的源码才行。<br><br><img height=768 alt="" src="http://www.cppblog.com/images/cppblog_com/mybios/goof.JPG" width=996 border=0>
<img src ="http://www.cppblog.com/mybios/aggbug/27620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-07-06 20:28 <a href="http://www.cppblog.com/mybios/archive/2007/07/06/27620.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>经过将近一个月的努力，服务器框架终于搭建起来了</title><link>http://www.cppblog.com/mybios/archive/2007/06/05/25605.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Tue, 05 Jun 2007 15:12:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/06/05/25605.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/25605.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/06/05/25605.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/25605.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/25605.html</trackback:ping><description><![CDATA[<p>好久没更新blog了啊。找到新工作都已经很久了，本来在深圳做得好好的，公司突然又搬到杭州来了，没办法，跟着来了杭州。现在我做客户端逻辑与服务器引擎架构一起搞，好晕啊，天天加班做。幸好客户端是用现成的引擎，只是，不太喜欢现在这个引擎，Torque game engine advance，架构实在太差了，以后有机会一定要换成Ogre或Nebula2才行啊。<br><br>现在在开发一款全新的MMORPG游戏，现在是项目立项阶段，需要出技术演示，没办法啊，时间紧迫，我跟另外一个程序主管用了将近一个月完成了项目的第一个里程碑。完成了玩家登录、角色创建/删除、人物行走、多人在线、怪物生成与行走AI等等网络功能了，当然客户端方面也做好了。可惜项目主管不是我，图也不允许抓下来啊，对不起大家了。欢迎加QQ：30743734交流MMORPG开发。<br><br>明天爸爸要做肺部肿瘤切除手术了，祝愿他一切顺利啊，等他痊愈后我发誓要让他过上幸福的晚年生活。祝爸爸健康幸福。。。大伙们帮忙祝福一下吧，谢谢大家了。</p>
爸爸，请原谅儿子我的不孝，路途遥远，不能赶回来陪着您做手术，我以后一定会好好孝顺您的。 
<img src ="http://www.cppblog.com/mybios/aggbug/25605.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-06-05 23:12 <a href="http://www.cppblog.com/mybios/archive/2007/06/05/25605.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一年一度的农历新年快到了，拜个早年，顺便贴我的简历，希望找到好工作</title><link>http://www.cppblog.com/mybios/archive/2007/02/12/18687.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Mon, 12 Feb 2007 07:27:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2007/02/12/18687.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/18687.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2007/02/12/18687.html#Feedback</comments><slash:comments>24</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/18687.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/18687.html</trackback:ping><description><![CDATA[
		<div align="center">
				<table class="MsoNormalTable" cellspacing="0" cellpadding="0" width="650" border="0">
						<tbody>
								<tr>
										<td>
												<br />
												<b>个人基本简历</b>
										</td>
								</tr>
						</tbody>
				</table>
		</div>
		<br />  
<div align="center"><table class="MsoNormalTable" cellspacing="1" cellpadding="0" width="657" border="0"><tbody><tr><td width="105"><br />姓　　名：</td><td width="188"><br />李锦俊 先生</td><td width="105"><br />国　　籍：</td><td><br />中国</td></tr><tr><td width="105"><br />目前住地：</td><td><br />广东江门</td><td><br />民　　族：</td><td><br />汉族</td></tr><tr><td width="105"><br />户 籍 地：</td><td><br />广东江门</td><td><br />身高体重：</td><td><br />170 cm 55 kg</td></tr><tr><td width="105"><br />婚姻状况：</td><td><br />未婚</td><td><br />年　　龄：</td><td><br />25 岁</td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="0" cellpadding="0" width="650" border="0"><tbody><tr><td><br /><b>求职意向及工作经历</b></td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="1" cellpadding="0" width="648" border="0"><tbody><tr><td width="103"><br />应聘职位：</td><td colspan="3"><br />2D/3D游戏开发（技术总监、主程序员、VC++高级程序员）</td></tr><tr><td width="103"><br />工作年限：</td><td width="185"><br />5年</td><td width="103"><br />职　　称：</td><td width="253"><br />高级</td></tr><tr><td width="103"><br />求职类型：</td><td width="185"><br />全职</td><td width="103"><br />可到职日期：</td><td><br />2007年春节之后</td></tr><tr><td width="103"><br />月薪要求：</td><td width="185"><br />8000以上</td><td width="103"><br />希望工作地区：</td><td nowrap=""><br />广州、江门、深圳</td></tr><tr><td width="103"><br />工作经历：</td><td colspan="3"><br />2002.5月～2004.4月 江门高正电脑 VC开发与B/S程序开发 主程序员 <br />2004.4月～2007.2月 长沙新冠数码科技公司 VC开发VOD视频点播系统 技术总监</td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="0" cellpadding="0" width="650" border="0"><tbody><tr><td><br /><b>教育背景</b></td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="1" cellpadding="0" width="648" border="0"><tbody><tr><td><br />毕业院校：</td><td colspan="3"><br />江门杜阮华侨中学 现就读长沙电大</td></tr><tr><td width="100"><br />最高学历：</td><td width="180"><br />高中</td><td width="100"><br />毕业日期：</td><td width="246"><br />2002 年</td></tr><tr><td><br />所学专业：</td><td width="180"><br />软件开发</td><td width="100"><br /> </td><td><br /> </td></tr><tr><td><br />培训经历：</td><td colspan="3"><br />经历了十几年的学校经历 还有很多经验 很早就能接触计算机 <br />1996年开始自学DOS及Windows3.1 <br />1997年开始自学Basic编程语言 <br />1999年开始自学DOS下的C语言编程 <br />2000年开始自学ASP、VB <br />2002年～2004年用VC/ASP/VB，做了十几个项目 <br />2003年开始自学C#.Net，做了两三个项目 <br />2004年至今一直使用VC，独立开发整套点歌系统 <br />2005年至今一直在自学2D/3D相关的技术（高数、图形学、Direct3D、DirectDraw、DirectShow）</td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="0" cellpadding="0" width="650" border="0"><tbody><tr><td><br /><b>语言能力</b></td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="1" cellpadding="0" width="648" border="0"><tbody><tr><td width="100"><br />外　　语：</td><td width="180"><br />英语　一般（能读懂各种英文参考资料）</td><td width="100"><br /> </td><td width="246"><br /> </td></tr><tr><td><br />国语水平：</td><td><br />非常流利</td><td width="100"><br />粤语水平：</td><td><br />非常流利</td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="0" cellpadding="0" width="650" border="0"><tbody><tr><td><br /><b>工作能力及其他专长</b></td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="1" cellpadding="0" width="648" border="0"><tbody><tr><td width="100"><br /> </td><td><br />精通C++语言、能熟练使用常用的设计模式；精通WIN32SDK，MFC开发平台。 <br />自学高等数学、线性代数、计算机图形学等等跟2D/3D有关的数学知识 <br />精通Direct3D、DirectDraw、DirectShow，熟悉其他的DirectX SDK开发。 <br />熟悉开源3D引擎OGRE，曾经自己改中文支持（用FreeType2），用来开发3D 点歌系统 <br />熟悉嵌入式脚本引擎，用以驱动3D点歌系统和计费系统的灵活设置 <br />熟悉Windows网络编程，熟悉TCP/IP协议及Winsock编程技术，用来开发多用户的点歌系统以及酒水传送模块； <br />熟悉windows多线程编程； <br />熟练进行Windows 各种界面开发； <br />熟常用的数据结构和算法，熟悉COM开发； <br />有良好规范的编程习惯； <br />能熟练阅读大量英文文档； <br />有良好的沟通与团队协作能力，能适应较大的工作压力。 <br />能独立策划中型开发项目,通过4年的VC工作开发经验,积累了很多知识,能独立开发VC项目,曾独立开发VOD视频点播系统,包括视频点播前台/计费系统/进销存/超市系统,与硬件衔接的导唱/语音识别/视频切换等等模块的独立开发.开发基于实时3D渲染的全新点歌系统<br />能独立开发B/S模式的应用程序，曾独立开发无线餐饮系统，进销存系统，CRM客户关系管理，OA都能独立开发。 <br />精通VC/ASP/SQL Server/HTML/Java Script等等技术（都是应用到工作中去的技术），曾用ASP.net独立完成一些政府机关的项目，对于ASP.Net和VB都比较熟悉，略懂Java。 <br />另外本人的电脑知识无论软件、硬件都比较熟悉，做出来的软件能跟硬件很好的衔接。精通Word/Excel/Photoshop等等办公应用软件的使用。 <br />因为本人在用友软件的代理商工作过2年时间。所以，对用友/金碟/速达等财务软件有比较系统的理解，并能在上面做二次开发。 <br />自学能力强，性格开朗，工作认真，一丝不苟，工作勤快。。。。</td></tr></tbody></table></div><br />  <br />  <br />  
<div align="center"><table class="MsoNormalTable" cellspacing="0" cellpadding="0" width="650" border="0"><tbody><tr><td><br /><b>个人联系方式</b>　</td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="1" cellpadding="0" width="650" border="0"><tbody><tr><td><br />手　　机：</td><td><br /> 13664915121</td><td><br />ＱＱ号码：</td><td><br />30743734 </td></tr><tr><td><br />电子邮件：</td><td><br />mybios@21cn.com </td><td><br />个人主页：</td><td><br /><a href="/mybios">http://www.cppblog.com/mybios</a></td></tr><tr><td colspan="6"><br /><b>DEMO</b><b>演示</b>　(面试时再带上源码来看)</td></tr><tr height="0"><td width="3"></td><td width="121"></td><td width="189"></td><td width="121"></td><td width="212"></td><td width="3"></td></tr></tbody></table></div><br />  
<div align="center"><table class="MsoNormalTable" cellspacing="1" cellpadding="0" width="635" border="0"><tbody><tr><td width="99"><br />连连看</td><td width="533"><br />基于D3D9的2D游戏，部分用XML＋Lua驱动，核心算法写在C++中，只实现了单机版</td></tr><tr><td width="99"><br />锄大地</td><td width="533"><br />基于D3D9的2D游戏，部分用XML＋Lua驱动，核心算法写在C++中，只实现了单机版自己打自己（没什么意义）</td></tr><tr><td width="99"><br />GUI </td><td width="533"><br />参考了Ogre、irrLicht等等开源引擎做的一个游戏引擎，平台无关、渲染器无关，高度优化的GUI渲染引擎，速度比CEGUI快至少1/3，内存占用比CEGUI少2/3以上。使用了部分设计模式。</td></tr></tbody></table></div><br /> <img src ="http://www.cppblog.com/mybios/aggbug/18687.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2007-02-12 15:27 <a href="http://www.cppblog.com/mybios/archive/2007/02/12/18687.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VS2005类向导的问题</title><link>http://www.cppblog.com/mybios/archive/2006/12/31/17088.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 31 Dec 2006 07:51:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/12/31/17088.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/17088.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/12/31/17088.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/17088.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/17088.html</trackback:ping><description><![CDATA[以前用VS 6和VS2003，类向导生成的都是虚析构函数，但是到了VS2005，默认就不是虚析构函数了。<br />这会带来什么问题？我今天就遇到了一次。当我用VS2005类向导生成一个类，如<br />class BaseClass<br />{<br />public:<br />    BaseClass(){};<br />   ~BaseClass(){};<br />   virtual void VFun() = 0;<br />}<br /><br />然后，再生成一个类继承于他<br />class ProblemClass : public BaseClass<br />{<br />public:<br />    ProblemClass (){};<br />   ~ProblemClass (){};<br />   virtual void VFun(){};<br />}<br /><br />然后，执行以下代码：<br /><br />BaseClass *pClass = new ProblemClass ;<br />delete pClass ;<br /><br />如无以外，在delete的时候就会出现堆错误<br /><img src ="http://www.cppblog.com/mybios/aggbug/17088.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-12-31 15:51 <a href="http://www.cppblog.com/mybios/archive/2006/12/31/17088.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>硬件兼容性的陷阱，DrawIndexedPrimitiveUP的用法</title><link>http://www.cppblog.com/mybios/archive/2006/12/25/16840.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Mon, 25 Dec 2006 07:11:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/12/25/16840.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/16840.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/12/25/16840.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/16840.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/16840.html</trackback:ping><description><![CDATA[好好的一个程序，在我的电脑（ELSA X800 256M显卡）上运行一切正常，拿到别的电脑（845G内置显卡）上。啊。花屏～～赶快调试，幸好公司的电脑也有这种内置显卡的电脑。赶快用远程调试。谁知这一调试，就花了我整整一个上午。。。赶快写下来。。。<br /><br />最终排差的原因是DrawIndexedPrimitiveUP最后一个参数<em>VertexStreamZeroStride</em> ，这个参数是用来指定顶点所占的字节数。我自作聪明的把顶点结构后增加了一个自己用的数据，如：正常的顶点结构<br />struct CUSTOMVERTEX<br />{<br /> FLOAT x, y, z,rhw;<br /> DWORD color;<br /> float u,v;<br />};<br /><br />我改了之后的顶点结构：<br />struct CUSTOMVERTEX<br />{<br /> FLOAT x, y, z,rhw;<br /> DWORD color;<br /> float u,v;<br />DWORD dwMyData; // 用来保存我自己用的数据<br />};<br /><br />结果，在我的显卡上一切正常，这个数据也有用，然后DrawIndexedPrimitiveUP的时候，也会根据最后的参数sizeof(CUSTOMVERTEX)顺利的读取相应的顶点。但是，拿到845G的内置显卡上就死活花屏。后来终于知道是这个原因，于是解决办法就是把dwMyData去掉，放到顶点结构外面去。<br /><br />顺便说说DrawIndexedPrimitiveUP的用法：<br /><strong>HRESULT DrawIndexedPrimitiveUP(</strong><br />  <b>D3DPRIMITIVETYPE</b><i>PrimitiveType</i><b>, // 图原的类型</b><br />  <b>UINT</b><i>MinVertexIndex</i><b>,  // 指定0</b><br />  <b>UINT</b><i>NumVertices</i><b>,  // 指定需要渲染的顶点的数量（如一个矩形可以由4个顶点组成，然后通过顶点索引来达到渲染2个三角形的效果，那么这里就应该填写4，而不是6）</b><br />  <b>UINT</b><i>PrimitiveCount</i><b>, // 要渲染的图原的数量（如一个矩形，由两个三角形组成，就应该填写2）</b><br />  <b>CONST void *</b><i>pIndexData</i><b>, // 索引数据指针</b><br />  <b>D3DFORMAT</b><i>IndexDataFormat</i><strong>, // 索引数据格式，一般为D3DFMT_INDEX16或D3DFMT_INDEX32</strong> <br />  <b>CONST void*</b><i>pVertexStreamZeroData</i><b>, // 顶点数据指针</b><br />  <b>UINT</b><i>VertexStreamZeroStride // 顶点大小一般为sizeof(顶点结构)</i><br /><b>);</b><br /><br />记得默认情况下渲染三角形的顺序是逆时针的（初学者经常范这个错误，本来想渲染一个矩形，结果一个三角形顺时间、另一个三角形逆时针，结果渲染出来只看到一个三角形了，被背面剔除掉了）。<br /><img src ="http://www.cppblog.com/mybios/aggbug/16840.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-12-25 15:11 <a href="http://www.cppblog.com/mybios/archive/2006/12/25/16840.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>3D 引擎中的 GUI 渲染优化补完</title><link>http://www.cppblog.com/mybios/archive/2006/12/24/16795.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 24 Dec 2006 06:14:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/12/24/16795.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/16795.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/12/24/16795.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/16795.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/16795.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 昨天提到的我想到了个优化渲染的新方法。。今天花了一个早上终于实现了。5555其实不需要这么久，偏偏是一个小小的BUG花了我两个小时。马上进入正题吧。原来的GUI渲染系统是每个Window都继承于RenderCache，每个RenderCache中保存着需要渲染的矩形信息，然后每帧渲染的时候一个个矩形添加到渲染器中再动态修改顶点坐标（一个矩形对应6个顶点）。慢就慢在动态修改顶点！今天实现的新方法，就...&nbsp;&nbsp;<a href='http://www.cppblog.com/mybios/archive/2006/12/24/16795.html'>阅读全文</a><img src ="http://www.cppblog.com/mybios/aggbug/16795.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-12-24 14:14 <a href="http://www.cppblog.com/mybios/archive/2006/12/24/16795.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>3D 引擎中 GUI 渲染的优化</title><link>http://www.cppblog.com/mybios/archive/2006/12/23/16778.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sat, 23 Dec 2006 14:32:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/12/23/16778.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/16778.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/12/23/16778.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/16778.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/16778.html</trackback:ping><description><![CDATA[前几天的BLOG中说了一些我的3D引擎GUI的渲染部分原理，这几天做到ListCtrl控件的时候，当我添加很多Item进去的时候（几乎满屏的12Px汉字，一个汉字两个三角形，相当于上万个三角形了），FPS降得吓人，Debug版只有18FPS，Release版也只有60FPS。。优化、优化、还是优化！优化之后，FPS终于达到了令人满意的500FPS左右了。且听我慢慢说来。<br /><br />首先是用我的引擎内部剖析分析了代码的瓶颈（Profile这东西真的有用啊，让我很容易就找到了慢的原因，参见GPG3 1.17《实时的层次化性能评测》），发现处理时间主要被Cache算法和渲染两部份占了，于是，我在想，渲染慢是正常的（当时的想法比较弱智，后文有术），所以，我打算从Cache算法着手。首先是优化了ListCtrl的Cache算法，把那些在屏幕外的Item的Visible属性设置成false（我的算法中Visible为false，Cache部分算法就直接跳过），于是速度一下子就上来了，Release版本达到了130FPS。但是，还是慢啊。怎么办？剖析之后，发现大部分的处理时间都集中在渲染部分，我之前的想法是渲染慢是正常的，所以暂时无法解决。。。<br /><br />下班的时候，出去遛了一圈，路上突然想到了我渲染算法中另外一个跟渲染速度有关的东西，动态修改顶点数据！难道是这里的原因？回来后马上测试，把动态修改的代码屏蔽，直接每帧渲染10000三角形，妈呀，1000＋的FPS！完全否定了我之前的想法（渲染慢是正常的），唉，想想也是，每秒千万、上亿个三角形生成速度的显卡，对于区区一万个三角形怎么会慢呢...既然找到原因，就要优化啊，现在找到原因是因为动态修改顶点导致，想到了以前看过一篇文章说顶点数据存储的位置（即CreateVertexBuffer的D3DPool参数），说到做到，把原来的D3DPOOL_MANAGED改成D3DPOOL_SYSMEMORY，哇，速度一下子提升到360FPS左右！想起来原因也是简单的，既然要每帧Lock这么多数据，那么顶点数据需要从显存-&gt;CPU处理，然后CPU提交回显存，总线交换也太频繁了，如果改成SYSMEMORY的话，就只需要从CPU-&gt;显存就可以了。<br /><br />然后我又想，有没有更好的优化方法？答案是有的。。最快的修改内存数据的方法是什么？当然是直接读写内存啊！那么我想到了DrawPrimitiveUP！把顶点数据直接new出来，然后DrawPrimitiveUP提交！改成这样后，速度再度提升！达到惊人的500FPS！<br /><br />最后，我把DrawPrimitiveUP改成DrawIndexedPrimitiveUP，那么顶点数量也减少了。但是奇怪的是速度缺没有更快，反而慢了一点点（慢了5～10FPS左右），但是，我用了DrawIndexedPrimitiveUP，我之后还有更好的优化算法准备实现。通过DrawIndexedPrimitiveUP，但是还没做好。。所以先卖个关子了。明天搞好的话再写Blog。<br /><br />唉，回头看了下自己写的东西，乱七八糟。都不知道有没有人看得懂啊。不管了。知之为知之，不知为不知吧。呵呵，看不懂的请评论一下。<br /><br />写代码去了～～<img src ="http://www.cppblog.com/mybios/aggbug/16778.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-12-23 22:32 <a href="http://www.cppblog.com/mybios/archive/2006/12/23/16778.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>今天碰到了LINK2005的问题</title><link>http://www.cppblog.com/mybios/archive/2006/12/22/16719.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Fri, 22 Dec 2006 03:14:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/12/22/16719.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/16719.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/12/22/16719.html#Feedback</comments><slash:comments>14</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/16719.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/16719.html</trackback:ping><description><![CDATA[烦人的错误。。搞了一个多小时才解决，写下来记录一下。<br /><br />解决办法：保证需要链接的几个项目的运行时库使用同一个类型就OK了！例如我的工程中有GameCore、Plugin_D3D9RenderSystem、Plugin_Win32Platform三个工程，那么就去设置每个工程的C/C++ -&gt;代码生成-&gt;运行时库，统一设置成“多线程 DLL(/MD)”，就可以了。如果其中一个不是MD，就会出现以下的错误。很烦人。希望同样遇到这个问题的朋友能少走弯路<br /><br />以下是链接错误信息：<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: int __thiscall std::ios_base::width(int)" (<a href="mailto:?width@ios_base@std@@QAEHH@Z">?width@ios_base@std@@QAEHH@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: int __thiscall std::ios_base::width(void)const " (<a href="mailto:?width@ios_base@std@@QBEHXZ">?width@ios_base@std@@QBEHXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: int __thiscall std::ios_base::flags(void)const " (<a href="mailto:?flags@ios_base@std@@QBEHXZ">?flags@ios_base@std@@QBEHXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: bool __thiscall std::ios_base::good(void)const " (<a href="mailto:?good@ios_base@std@@QBE_NXZ">?good@ios_base@std@@QBE_NXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: int __thiscall std::ios_base::rdstate(void)const " (<a href="mailto:?rdstate@ios_base@std@@QBEHXZ">?rdstate@ios_base@std@@QBEHXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: static unsigned int __cdecl std::char_traits&lt;char&gt;::length(char const *)" (<a href="mailto:?length@?$char_traits@D@std@@SAIPBD@Z">?length@?$char_traits@D@std@@SAIPBD@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "class std::basic_ostream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt; &amp; __cdecl std::operator&lt;&lt;&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;(class std::basic_ostream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt; &amp;,class std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt; const &amp;)" (<a href="mailto:??$?6_WU?$char_traits@_W@std@@V?$allocator@_W@1@@std@@YAAAV?$basic_ostream@_WU?$char_traits@_W@std@@@0@AAV10@ABV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@0@@Z">??$?6_WU?$char_traits@_W@std@@V?$allocator@_W@1@@std@@YAAAV?$basic_ostream@_WU?$char_traits@_W@std@@@0@AAV10@ABV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@0@@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: wchar_t __thiscall std::basic_ios&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::fill(void)const " (<a href="mailto:?fill@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QBE_WXZ">?fill@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QBE_WXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt; __thiscall std::basic_ostringstream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::str(void)const " (<a href="mailto:?str@?$basic_ostringstream@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBE?AV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@2@XZ">?str@?$basic_ostringstream@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBE?AV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@2@XZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::basic_ostringstream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::basic_ostringstream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;(int)" (<a href="mailto:??0?$basic_ostringstream@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@H@Z">??0?$basic_ostringstream@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@H@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::basic_ostream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt; &amp; __thiscall std::basic_ostream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::operator&lt;&lt;(int)" (<a href="mailto:??6?$basic_ostream@_WU?$char_traits@_W@std@@@std@@QAEAAV01@H@Z">??6?$basic_ostream@_WU?$char_traits@_W@std@@@std@@QAEAAV01@H@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;(class std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt; const &amp;)" (<a href="mailto:??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@ABV01@@Z">??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@ABV01@@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: void __thiscall std::basic_ostream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::_Osfx(void)" (<a href="mailto:?_Osfx@?$basic_ostream@_WU?$char_traits@_W@std@@@std@@QAEXXZ">?_Osfx@?$basic_ostream@_WU?$char_traits@_W@std@@@std@@QAEXXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::basic_ostream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt; * __thiscall std::basic_ios&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::tie(void)const " (<a href="mailto:?tie@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QBEPAV?$basic_ostream@_WU?$char_traits@_W@std@@@2@XZ">?tie@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QBEPAV?$basic_ostream@_WU?$char_traits@_W@std@@@2@XZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: void __thiscall std::basic_streambuf&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::_Lock(void)" (<a href="mailto:?_Lock@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QAEXXZ">?_Lock@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QAEXXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: void __thiscall std::basic_streambuf&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::_Unlock(void)" (<a href="mailto:?_Unlock@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QAEXXZ">?_Unlock@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QAEXXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: unsigned short __thiscall std::basic_streambuf&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::sputc(wchar_t)" (<a href="mailto:?sputc@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QAEG_W@Z">?sputc@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QAEG_W@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::~basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;(void)" (<a href="mailto:??1?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@XZ">??1?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@XZ</a>) 已经在 Plugin_Win32Platform.lib(Plugin_Win32Platform.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;(wchar_t const *)" (<a href="mailto:??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@PB_W@Z">??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@PB_W@Z</a>) 已经在 Plugin_Win32Platform.lib(Plugin_Win32Platform.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;(void)" (<a href="mailto:??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@XZ">??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAE@XZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: void __thiscall std::basic_ostringstream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::`vbase destructor'(void)" (<a href="mailto:??_D?$basic_ostringstream@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEXXZ">??_D?$basic_ostringstream@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEXXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::basic_ostream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt; &amp; __thiscall std::basic_ostream&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::flush(void)" (<a href="mailto:?flush@?$basic_ostream@_WU?$char_traits@_W@std@@@std@@QAEAAV12@XZ">?flush@?$basic_ostream@_WU?$char_traits@_W@std@@@std@@QAEAAV12@XZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::basic_streambuf&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt; * __thiscall std::basic_ios&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::rdbuf(void)const " (<a href="mailto:?rdbuf@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QBEPAV?$basic_streambuf@_WU?$char_traits@_W@std@@@2@XZ">?rdbuf@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QBEPAV?$basic_streambuf@_WU?$char_traits@_W@std@@@2@XZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: void __thiscall std::basic_ios&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::setstate(int,bool)" (<a href="mailto:?setstate@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QAEXH_N@Z">?setstate@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QAEXH_N@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::locale __thiscall std::ios_base::getloc(void)const " (<a href="mailto:?getloc@ios_base@std@@QBE?AVlocale@2@XZ">?getloc@ios_base@std@@QBE?AVlocale@2@XZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: static unsigned int __cdecl std::ctype&lt;wchar_t&gt;::_Getcat(class std::locale::facet const * *)" (<a href="mailto:?_Getcat@?$ctype@_W@std@@SAIPAPBVfacet@locale@2@@Z">?_Getcat@?$ctype@_W@std@@SAIPAPBVfacet@locale@2@@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: wchar_t __thiscall std::ctype&lt;wchar_t&gt;::widen(char)const " (<a href="mailto:?widen@?$ctype@_W@std@@QBE_WD@Z">?widen@?$ctype@_W@std@@QBE_WD@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::locale::facet const * __thiscall std::locale::_Getfacet(unsigned int)const " (<a href="mailto:?_Getfacet@locale@std@@QBEPBVfacet@12@I@Z">?_Getfacet@locale@std@@QBEPBVfacet@12@I@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::locale::~locale(void)" (<a href="mailto:??1locale@std@@QAE@XZ">??1locale@std@@QAE@XZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: void __thiscall std::locale::facet::_Register(void)" (<a href="mailto:?_Register@facet@locale@std@@QAEXXZ">?_Register@facet@locale@std@@QAEXXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: void __thiscall std::locale::facet::_Incref(void)" (<a href="mailto:?_Incref@facet@locale@std@@QAEXXZ">?_Incref@facet@locale@std@@QAEXXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::locale::id::operator unsigned int(void)" (<a href="mailto:??Bid@locale@std@@QAEIXZ">??Bid@locale@std@@QAEIXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: static unsigned short __cdecl std::char_traits&lt;wchar_t&gt;::eof(void)" (<a href="mailto:?eof@?$char_traits@_W@std@@SAGXZ">?eof@?$char_traits@_W@std@@SAGXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: static bool __cdecl std::char_traits&lt;wchar_t&gt;::eq_int_type(unsigned short const &amp;,unsigned short const &amp;)" (<a href="mailto:?eq_int_type@?$char_traits@_W@std@@SA_NABG0@Z">?eq_int_type@?$char_traits@_W@std@@SA_NABG0@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "bool __cdecl std::operator&lt;&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;(class std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt; const &amp;,class std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt; const &amp;)" (<a href="mailto:??$?M_WU?$char_traits@_W@std@@V?$allocator@_W@1@@std@@YA_NABV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@0@0@Z">??$?M_WU?$char_traits@_W@std@@V?$allocator@_W@1@@std@@YA_NABV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@0@0@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32RenderWindow.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "protected: wchar_t const * __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::_Myptr(void)const " (<a href="mailto:?_Myptr@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IBEPB_WXZ">?_Myptr@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IBEPB_WXZ</a>) 已经在 Plugin_Win32Platform.lib(Plugin_Win32Platform.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: wchar_t const * __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::c_str(void)const " (<a href="mailto:?c_str@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBEPB_WXZ">?c_str@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBEPB_WXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32LogSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "protected: char const * __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::_Myptr(void)const " (<a href="mailto:?_Myptr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IBEPBDXZ">?_Myptr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IBEPBDXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: unsigned int __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::size(void)const " (<a href="mailto:?size@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ">?size@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: char const * __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::c_str(void)const " (<a href="mailto:?c_str@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEPBDXZ">?c_str@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEPBDXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::~basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;(void)" (<a href="mailto:??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ">??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;(char const *)" (<a href="mailto:??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z">??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;(class std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt; const &amp;)" (<a href="mailto:??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ABV01@@Z">??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ABV01@@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: bool __thiscall std::ios_base::fail(void)const " (<a href="mailto:?fail@ios_base@std@@QBE_NXZ">?fail@ios_base@std@@QBE_NXZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt; &amp; __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::erase(unsigned int,unsigned int)" (<a href="mailto:?erase@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEAAV12@II@Z">?erase@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEAAV12@II@Z</a>) 已经在 Plugin_Win32Platform.lib(Plugin_Win32Platform.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: void __thiscall std::basic_ios&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::clear(int,bool)" (<a href="mailto:?clear@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QAEXH_N@Z">?clear@?$basic_ios@_WU?$char_traits@_W@std@@@std@@QAEXH_N@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: unsigned int __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::size(void)const " (<a href="mailto:?size@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBEIXZ">?size@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QBEIXZ</a>) 已经在 Plugin_Win32Platform.lib(Plugin_Win32Platform.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "protected: wchar_t * __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::_Myptr(void)" (<a href="mailto:?_Myptr@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IAEPA_WXZ">?_Myptr@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@IAEPA_WXZ</a>) 已经在 Plugin_Win32Platform.lib(Plugin_Win32Platform.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;(void)" (<a href="mailto:??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ">??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: int __thiscall std::basic_streambuf&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt; &gt;::sputn(wchar_t const *,int)" (<a href="mailto:?sputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QAEHPB_WH@Z">?sputn@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QAEHPB_WH@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: static unsigned int __cdecl std::char_traits&lt;wchar_t&gt;::length(wchar_t const *)" (<a href="mailto:?length@?$char_traits@_W@std@@SAIPB_W@Z">?length@?$char_traits@_W@std@@SAIPB_W@Z</a>) 已经在 Plugin_Win32Platform.lib(Plugin_Win32Platform.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt; &amp; __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::assign(char const *,unsigned int)" (<a href="mailto:?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@PBDI@Z">?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@PBDI@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt; &amp; __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::append(char const *,unsigned int)" (<a href="mailto:?append@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@PBDI@Z">?append@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@PBDI@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />libcpmt.lib(ios.obj) : error LNK2005: "public: static void __cdecl std::ios_base::_Addstd(class std::ios_base *)" (<a href="mailto:?_Addstd@ios_base@std@@SAXPAV12@@Z">?_Addstd@ios_base@std@@SAXPAV12@@Z</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />libcpmt.lib(ios.obj) : error LNK2005: "private: static void __cdecl std::ios_base::_Ios_base_dtor(class std::ios_base *)" (<a href="mailto:?_Ios_base_dtor@ios_base@std@@CAXPAV12@@Z">?_Ios_base_dtor@ios_base@std@@CAXPAV12@@Z</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />libcpmt.lib(locale0.obj) : error LNK2005: "private: static class std::locale::_Locimp * __cdecl std::locale::_Getgloballocale(void)" (<a href="mailto:?_Getgloballocale@locale@std@@CAPAV_Locimp@12@XZ">?_Getgloballocale@locale@std@@CAPAV_Locimp@12@XZ</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />libcpmt.lib(locale0.obj) : error LNK2005: "private: static void __cdecl std::locale::facet::facet_Register(class std::locale::facet *)" (<a href="mailto:?facet_Register@facet@locale@std@@CAXPAV123@@Z">?facet_Register@facet@locale@std@@CAXPAV123@@Z</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />libcpmt.lib(locale0.obj) : error LNK2005: "public: static void __cdecl std::_Locinfo::_Locinfo_dtor(class std::_Locinfo *)" (<a href="mailto:?_Locinfo_dtor@_Locinfo@std@@SAXPAV12@@Z">?_Locinfo_dtor@_Locinfo@std@@SAXPAV12@@Z</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />libcpmt.lib(locale0.obj) : error LNK2005: "public: class std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt; &amp; __thiscall std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;::operator=(char const *)" (<a href="mailto:??4?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV01@PBD@Z">??4?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV01@PBD@Z</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />libcpmt.lib(locale0.obj) : error LNK2005: "private: static class std::locale::_Locimp * __cdecl std::locale::_Init(void)" (<a href="mailto:?_Init@locale@std@@CAPAV_Locimp@12@XZ">?_Init@locale@std@@CAPAV_Locimp@12@XZ</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />libcpmt.lib(locale0.obj) : error LNK2005: "public: static void __cdecl std::_Locinfo::_Locinfo_ctor(class std::_Locinfo *,char const *)" (<a href="mailto:?_Locinfo_ctor@_Locinfo@std@@SAXPAV12@PBD@Z">?_Locinfo_ctor@_Locinfo@std@@SAXPAV12@PBD@Z</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />libcpmt.lib(xlock.obj) : error LNK2005: "public: __thiscall std::_Lockit::_Lockit(int)" (<a href="mailto:??0_Lockit@std@@QAE@H@Z">??0_Lockit@std@@QAE@H@Z</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />libcpmt.lib(xlock.obj) : error LNK2005: "public: __thiscall std::_Lockit::~_Lockit(void)" (<a href="mailto:??1_Lockit@std@@QAE@XZ">??1_Lockit@std@@QAE@XZ</a>) 已经在 msvcprt.lib(MSVCP80.dll) 中定义<br />msvcprt.lib(MSVCP80.dll) : error LNK2005: "public: class std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt; &amp; __thiscall std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt;::assign(class std::basic_string&lt;wchar_t,struct std::char_traits&lt;wchar_t&gt;,class std::allocator&lt;wchar_t&gt; &gt; const &amp;)" (<a href="mailto:?assign@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEAAV12@ABV12@@Z">?assign@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEAAV12@ABV12@@Z</a>) 已经在 Plugin_Win32Platform.lib(Win32InputSystem.obj) 中定义<br />   正在创建库 ../Lib/GameCore.lib 和对象 ../Lib/GameCore.exp<br />../Bin/GameCore.dll : fatal error LNK1169: 找到一个或多个多重定义的符号<img src ="http://www.cppblog.com/mybios/aggbug/16719.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-12-22 11:14 <a href="http://www.cppblog.com/mybios/archive/2006/12/22/16719.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>这段时间开发3D引擎啊，正在做GUI部分</title><link>http://www.cppblog.com/mybios/archive/2006/12/19/16630.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Tue, 19 Dec 2006 13:30:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/12/19/16630.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/16630.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/12/19/16630.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/16630.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/16630.html</trackback:ping><description><![CDATA[前段时间看了很多很多的3D相关的基础书，感觉上学到了很多东西，但是不知道做什么好。后来，用DXUT做了两个小游戏，连连看和纸牌，虽然都是2D的，但是感觉上还是觉得自己进步了。<br /><br />接下来的一段日子里，是时候继续学3D的东西了，于是萌生了个做游戏引擎的想法。我是个想做就做的人，虽然我也知道自己是不自量力，但是，只要我肯去做，即使做不好，也起码能学到东西啊，把学过的东西拿来用一番，就能有感觉了。<br /><br />说说引擎部分的构建，引擎部分的FrameWork主要参考了GPG3的1.2那个框架模式，采用Unicode编译，感觉上那个模式比较好用，但是太复杂了点，于是我简化了他，基本上只保留了任务系统。使用平台无关的插件方式把Win32和Direct3D9的模块做了出来（当然只封装了一小部分函数），把Ogre的基础库全部拿来主义（哈哈，主要就是数学库、工具库等等）。而声音引擎也留了接口，很好扩展了。<br /><br />然后，现在正在做GUI部分，主要还是说说GUI的渲染部分吧。GUI其中有两个我认为比较关键的地方，其一是渲染文字部分，其二是渲染窗口部分。下面说说我的做法<br />文字渲染部分：<br />我的做法是使用FreeType2读取TTF文件，然后当要渲染文字的时候，看哪个用到的文字就load哪个文字，先获得这个文字的大小，然后在贴图中找到一个空闲的区域（我的贴图大小是512×512，也可以设置），然后blt到贴图中，真正渲染的时候就把这个贴图纹理坐标贴到两个三角形上就完成了一个文字的渲染了。<br />在贴图中找空闲区域我有个比较特别的做法，就是每个需要渲染的文字维护一个RefCount引用计数，例如一个屏幕里10个“我”字，那么“我”的引用计数就是10，当“我”字不需要再渲染的时候（引用计数为0），此文字的贴图区域就可以被其他文字所覆盖。<br />窗口渲染部分：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> GAMECORE_EXPORT GUIRenderCache<br /><img id="Codehighlighter1_38_831_Open_Image" onclick="this.style.display='none'; Codehighlighter1_38_831_Open_Text.style.display='none'; Codehighlighter1_38_831_Closed_Image.style.display='inline'; Codehighlighter1_38_831_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_38_831_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_38_831_Closed_Text.style.display='none'; Codehighlighter1_38_831_Open_Image.style.display='inline'; Codehighlighter1_38_831_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_38_831_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_38_831_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 不允许显式创建，只可以继承</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    GUIRenderCache(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">GUIRenderCache(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 添加到渲染队列</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> AddCache(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> GUIRenderQuad</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> quad)<br /><img id="Codehighlighter1_188_262_Open_Image" onclick="this.style.display='none'; Codehighlighter1_188_262_Open_Text.style.display='none'; Codehighlighter1_188_262_Closed_Image.style.display='inline'; Codehighlighter1_188_262_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_188_262_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_188_262_Closed_Text.style.display='none'; Codehighlighter1_188_262_Open_Image.style.display='inline'; Codehighlighter1_188_262_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_188_262_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_188_262_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        m_vtGUIRenderQuad.insert(GUIRenderQuadPtr(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> GUIRenderQuad(quad)));<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 渲染需要Cache队列</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> RenderCache(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_307_612_Open_Image" onclick="this.style.display='none'; Codehighlighter1_307_612_Open_Text.style.display='none'; Codehighlighter1_307_612_Closed_Image.style.display='inline'; Codehighlighter1_307_612_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_307_612_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_307_612_Closed_Text.style.display='none'; Codehighlighter1_307_612_Open_Image.style.display='inline'; Codehighlighter1_307_612_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_307_612_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_307_612_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 从新Cache队列</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(m_bDirty)<br /><img id="Codehighlighter1_341_401_Open_Image" onclick="this.style.display='none'; Codehighlighter1_341_401_Open_Text.style.display='none'; Codehighlighter1_341_401_Closed_Image.style.display='inline'; Codehighlighter1_341_401_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_341_401_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_341_401_Closed_Text.style.display='none'; Codehighlighter1_341_401_Open_Image.style.display='inline'; Codehighlighter1_341_401_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_341_401_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_341_401_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            ClearCacheList();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            DoCache();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            m_bDirty </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 添加到渲染器</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(VectorGUIRenderQuad::const_iterator iter </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> m_vtGUIRenderQuad.begin() ; iter </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> m_vtGUIRenderQuad.end() ; iter </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_537_609_Open_Image" onclick="this.style.display='none'; Codehighlighter1_537_609_Open_Text.style.display='none'; Codehighlighter1_537_609_Closed_Image.style.display='inline'; Codehighlighter1_537_609_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_537_609_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_537_609_Closed_Text.style.display='none'; Codehighlighter1_537_609_Open_Image.style.display='inline'; Codehighlighter1_537_609_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_537_609_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_537_609_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            Systems::GetSingleton().GetGUIRendererSystem()</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">AddCache(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">iter);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 清空cache队列</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> ClearCacheList(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_656_688_Open_Image" onclick="this.style.display='none'; Codehighlighter1_656_688_Open_Text.style.display='none'; Codehighlighter1_656_688_Closed_Image.style.display='inline'; Codehighlighter1_656_688_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_656_688_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_656_688_Closed_Text.style.display='none'; Codehighlighter1_656_688_Open_Image.style.display='inline'; Codehighlighter1_656_688_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_656_688_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_656_688_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        m_vtGUIRenderQuad.clear();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Cache需要渲染的项目</span><span style="COLOR: #008000"><br /><img id="Codehighlighter1_742_743_Open_Image" onclick="this.style.display='none'; Codehighlighter1_742_743_Open_Text.style.display='none'; Codehighlighter1_742_743_Closed_Image.style.display='inline'; Codehighlighter1_742_743_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_742_743_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_742_743_Closed_Text.style.display='none'; Codehighlighter1_742_743_Open_Image.style.display='inline'; Codehighlighter1_742_743_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" /></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> DoCache()</span><span id="Codehighlighter1_742_743_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_742_743_Open_Text"><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    VectorGUIRenderQuad m_vtGUIRenderQuad;    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 渲染队列</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000"> m_bDirty; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 需要重新Cache需要渲染的项目</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" /></span><span style="COLOR: #000000">}</span></span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><br /><br /><br />每个Window（一个Window是一个抽象类，Static/Button/Dialog等等所有窗口都是继承于Window）都继承于GUIRenderCache对象，当窗口的某个属性（如WindowText）改变时，就会把m_bDirty标记设置成true。每帧渲染的时候调用RenderCache。那么如果窗口的属性没有改变，就只需要把m_vtGUIRenderQuad的东西渲染出来；如果属性改变了（即m_bDirty为true），则调用DoCache，由继承类（如Static/Button等）改写这个函数，计算贴图坐标、三角形坐标等等东西都放在这个函数里。总的来说，Cache之后速度会比Cache之前快起码一半以上。<br /><br />好了，睡觉去了。<img src ="http://www.cppblog.com/mybios/aggbug/16630.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-12-19 21:30 <a href="http://www.cppblog.com/mybios/archive/2006/12/19/16630.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>顶点声明</title><link>http://www.cppblog.com/mybios/archive/2006/12/02/15891.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sat, 02 Dec 2006 08:42:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/12/02/15891.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15891.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/12/02/15891.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15891.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15891.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 顶点声明																																																																从概念上讲，顶点声明是对顶点直接内存访问（DMA）以及图形流水线的														tessellator												引擎进行编程的一种方法。顶点声明简要地表示了数据的布局及...&nbsp;&nbsp;<a href='http://www.cppblog.com/mybios/archive/2006/12/02/15891.html'>阅读全文</a><img src ="http://www.cppblog.com/mybios/aggbug/15891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-12-02 16:42 <a href="http://www.cppblog.com/mybios/archive/2006/12/02/15891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VS2003下编译Windows计算器</title><link>http://www.cppblog.com/mybios/archive/2006/12/02/15889.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sat, 02 Dec 2006 08:10:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/12/02/15889.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15889.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/12/02/15889.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15889.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15889.html</trackback:ping><description><![CDATA[工程已经放上，<a href="http://www.cppblog.com/Files/mybios/calc.rar">下载回去编译就行</a>，放个贴图：<br /><br /><img height="309" alt="Calc.JPG" src="http://www.cppblog.com/images/cppblog_com/mybios/ArticlePics/Calc.JPG" width="480" border="0" /><img src ="http://www.cppblog.com/mybios/aggbug/15889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-12-02 16:10 <a href="http://www.cppblog.com/mybios/archive/2006/12/02/15889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>今天遇到了郁闷的C函数，幸好遇到高手帮忙解决了</title><link>http://www.cppblog.com/mybios/archive/2006/11/30/15817.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Thu, 30 Nov 2006 08:30:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/30/15817.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15817.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/30/15817.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15817.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15817.html</trackback:ping><description><![CDATA[用C函数来转换Unicode和ANSI文字<br /><br />char sChar[MAX_PATH];<br />const WCHAR wChar[] = L"我的朋友";<br />// 把wChar这个Unicode字符串转换成ANSI字符串，保存到sChar，并且返回ANSI的字符串大小，如果失败，则返回-1<br />  wcstombs(sChar, wChar, MAX_PATH);<br /><br />这样是运行不过不去的，总是返回-1。<br /><br />后来经人提醒，需要在调用wcstombs之前要先设置代码页：<br /><br />char sChar[MAX_PATH];<br />const WCHAR wChar[] = L"我的朋友";<br /><br />// 设置代码页为默认代码页<br />  _tsetlocale(LC_ALL,_T(""));<br />// 把wChar这个Unicode字符串转换成ANSI字符串，保存到sChar，并且返回ANSI的字符串大小，如果失败，则返回-1<br />  wcstombs(sChar, wChar, MAX_PATH);<br /><br /><br />这样就可以了！不用调用烦人的WideCharToMultiByte！多好啊！<br />相反的函数：<strong>mbstowcs，可以从ANSI转换到Unicode</strong><img src ="http://www.cppblog.com/mybios/aggbug/15817.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-30 16:30 <a href="http://www.cppblog.com/mybios/archive/2006/11/30/15817.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】DXUT编程指南(四):通过DXUT使用设备</title><link>http://www.cppblog.com/mybios/archive/2006/11/22/15531.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Wed, 22 Nov 2006 03:35:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/22/15531.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15531.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/22/15531.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15531.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15531.html</trackback:ping><description><![CDATA[
		<p>
				<font size="5">通过DXUT使用设备</font>
				<br />DirectX设备的创建在DXUT中得到了改进。你可以让你的应用程序直接创建设备而其它有框架提供的特征仍然可用。<br /><a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/1009763.aspx#创建设备">创建设备</a><br /><a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/1009763.aspx#使用你自己的设备">选择最佳的设备设置<br />修改可用的设备设置<br />降为软件顶点处理<br />使用你自己的设备</a></p>
		<p>
				<font size="4">
						<a name="创建设备">
						</a>创建设备</font>
				<br />典型地，你将通过标准的Direct3D方法创建设备<br />HRESULT CreateDevice(<br />    UINT                  Adapter,<br />    D3DDEVTYPE            DeviceType,<br />    HWND                  hFocusWindow,<br />    DWORD                 BehaviorFlags,<br />    D3DPRESENT_PARAMETERS *pPresentationParameters,<br />    IDirect3DDevice9      **ppReturnedDeviceInterface<br />);<br />这个方法需要有效的适配器，设备类型(HAL or REF),窗口句柄，行为标志(software/hardware vertex processing 和其它驱动标志)，以及呈现参数(presentation parameters).此外，D3DPRESENT_PARAMETER结构体还拥有大量的成员指定后备缓冲区，多重采样设定，交换效果，窗口模式，深度模版缓冲，刷新率，呈现间隔，以及呈现标志。<br />为所有这些参数选择有效的设定是具有挑战性的。框架通过DXUTCreateDevice函数简化了这一选择过程。<br />HRESULT DXUTCreateDevice(<br />    UINT AdapterOrdinal  = D3DADAPTER_DEFAULT,<br />    BOOL bWindowed       = TRUE,<br />    INT nSuggestedWidth  = 640,<br />    INT nSuggestedHeight = 480,<br />    LPDXUTCALLBACKISDEVICEACCEPTABLE pCallbackIsDeviceAcceptable     = NULL,<br />    LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings = NULL<br />);<br />最基本的用法是全部使用缺省参数调用：<br />DXUTCreateDevice();<br />通过这样的调用框架使用缺省设置创建一个在大多数情况下可用的设备。缺省的设置如下：<br /></p>
		<table>
				<tbody>
						<tr>
								<th>Direct3D Creation Flag</th>
								<th>Description</th>
								<th>Default Value from <strong>DXUTCreateDevice</strong></th>
						</tr>
						<tr>
								<td>AdapterFormat parameter of <a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/IDirect3D9__CheckDeviceFormat.htm">CheckDeviceFormat</a></td>
								<td>Adapter surface format.</td>
								<td>Desktop display mode, or <a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/D3DFORMAT.htm">D3DFMT_X8R8G8B8</a> if the desktop display mode is less than 32 bits.</td>
						</tr>
						<tr>
								<td>Adapter parameter of <strong>IDirect3D9::CreateDevice</strong></td>
								<td>Display adapter ordinal.</td>
								<td>
										<a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/D3DADAPTER_DEFAULT.htm">D3DADAPTER_DEFAULT</a>
								</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. BackBufferCount</td>
								<td>Number of back buffers.</td>
								<td>2, indicating triple buffering.</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. BackBufferFormat</td>
								<td>Back buffer format.</td>
								<td>Desktop display mode, or <strong>D3DFMT_X8R8G8B8</strong> if the desktop display mode is less than 32 bits.</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. AutoDepthStencilFormat</td>
								<td>Depth format of the automatic depth-stencil surface that the device will create.</td>
								<td>
										<strong>D3DFMT_D16</strong> if the backbuffer format is 16 bits or less, or <strong>D3DFMT_D32</strong> otherwise.</td>
						</tr>
						<tr>
								<td>The DeviceType parameter of <strong>IDirect3D9::CreateDevice</strong></td>
								<td>Enumerated type of the device.</td>
								<td>D3DDEVTYPE_HAL if available, otherwise D3DDEVTYPE_REF or failure code if neither is available.</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. MultiSampleQuality</td>
								<td>Quality level.</td>
								<td>MultiSampleQuality = 0, indicating multisampling is disabled.</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. Flags</td>
								<td>Presentation parameters flags.</td>
								<td>
										<a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/D3DPRESENTFLAG.htm">D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL</a>
								</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. PresentationInterval</td>
								<td>Presentation interval.</td>
								<td>
										<a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/D3DPRESENT.htm">D3DPRESENT_INTERVAL_IMMEDIATE</a> for windowed mode, or <strong>D3DPRESENT_INTERVAL_DEFAULT</strong> for full-screen mode.</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. FullScreen_RefreshRateInHz</td>
								<td>Rate at which the display adapter refreshes the screen.</td>
								<td>0, indicating windowed mode.</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. BackBufferWidth and .BackBufferHeight</td>
								<td>Display mode resolution.</td>
								<td>640 x 480 pixels for windowed mode, or the desktop resolution for full-screen mode.</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. AutoDepthStencilFormat</td>
								<td>Stencil format of the automatic depth-stencil surface that the device will create.</td>
								<td>
										<strong>D3DFMT_D16</strong> if the backbuffer format is 16 bits or less, or <strong>D3DFMT_D32</strong> otherwise.</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. SwapEffect</td>
								<td>Swap effect.</td>
								<td>D3DSWAPEFFECT_DISCARD</td>
						</tr>
						<tr>
								<td>BehaviorFlags parameter of <strong>IDirect3D9::CreateDevice</strong></td>
								<td>Vertex processing flags.</td>
								<td>
										<a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/D3DCREATE.htm">D3DCREATE_HARDWARE_VERTEXPROCESSING</a> if supported, otherwise <strong>D3DCREATE_SOFTWARE_VERTEXPROCESSING</strong>.</td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. Windowed</td>
								<td>Windowed or full-screen mode.</td>
								<td>true, indicating windowed mode.</td>
						</tr>
						<tr>
								<td>hFocusWindow parameter of <strong>CreateDevice</strong></td>
								<td>Handle to the created window (see <a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/Using_Application_Windows_with_DXUT.htm">Using Application Windows with DXUT</a>).</td>
								<td>hWndFocus parameter of <a href="http://blog.csdn.net/ntwilford/archive/2006/08/02/DXUTSetWindow.htm">DXUTSetWindow</a></td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. hDeviceWindow</td>
								<td>Handle to the device window.</td>
								<td>hWndDeviceFullScreen or hWndDeviceWindowed parameters of <strong>DXUTSetWindow</strong></td>
						</tr>
						<tr>
								<td>
										<strong>D3DPRESENT_PARAMETERS</strong>. EnableAutoDepthStencil</td>
								<td>Depth-stencil buffer creation flag.</td>
								<td>true.</td>
						</tr>
				</tbody>
		</table>
		<br />应用程序可以通过参数传递给CreateDevice来更多的控制设备的创建，这将比使用缺省的方式更好。例如，你可以通过nSuggestedWidth and nSuggestedHeight参数改变窗口的尺寸。<br />DXUTCreateDevice(<br />    D3DADAPTER_DEFAULT,<br />    false,<br />    1024,<br />    786,<br />    NULL,<br />    NULL,<br />    NULL<br />);<br />要得到更多的控制权，应用程序可以使用这两个可选的回调函数，LPDXUTCALLBACKISDEVICEACCEPTABLE and LPDXUTCALLBACKMODIFYDEVICESETTINGS.<p><font size="4"><a name="选择最佳的设备设置"></a>选择最佳的设备设置</font><br />你可以使用IsDeviceAcceptable回调函数帮助框架为你的应用程序选择最佳的设备设置，就像下面的代码：<br />bool CALLBACK IsDeviceAcceptable(<br />D3DCAPS9*     pCaps,<br />D3DFORMAT     AdapterFormat,<br />D3DFORMAT     BackBufferFormat,<br />bool          bWindowed,<br />void*         pUserContext )<br />{<br />    // TODO: return true for acceptable settings and false otherwise.<br />    return true;<br />}<br />这个回调函数的模型基于LPDXUTCALLBACKISDEVICEACCEPTABLE原型(This callback function is modeled on the prototype LPDXUTCALLBACKISDEVICEACCEPTABLE)，框架为每个唯一的以下5个设置的有效组合调用这个函数一次：<br />D3DDEVTYPE DeviceType;<br />UINT       AdapterOrdinal;<br />D3DFORMAT  AdapterFormat;<br />D3DFORMAT  BackBufferFormat;<br />bool       Windowed;<br />注意适配器序号和设备类型没有直接的传入回调函数，而是分别作为D3DCAPS9结构体的成员。<br />通过这个回调函数，应用程序可以拒绝任何它不支持的或不想要的组合。例如，应用程序可以使用下面的代码拒绝16bits的后备缓冲区格式和所有至少不能支持像素着色器PS_2_0的设备： <br />bool CALLBACK IsDeviceAcceptable(<br />    D3DCAPS9*     pCaps,<br />    D3DFORMAT     AdapterFormat,<br />    D3DFORMAT     BackBufferFormat,<br />    bool          bWindowed )<br />{<br />    if( pCaps-&gt;PixelShaderVersion &lt; D3DPS_VERSION(2,0) )<br />     return false;<br />    if( BackBufferFormat == D3DFMT_X1R5G5B5 || BackBufferFormat == D3DFMT_R5G6B5 )<br />        return false;<br />    return true;<br />}</p><p>为每个唯一的组合调用回调函数后，框架排列剩下的可用组合，并选择它们当中最好的。排名较高的如下：<br />D3DDEVTYPE_HAL，获取硬件加速<br />如果应用程序以全屏模式显示，框架更趋向于使用匹配桌面格式的适配器格式，这样可以在全屏与窗口之间快速切换。例外的是，如果桌面显示模式小于32位，框架更趋向于D3DFMT_X8R8G8B8.<br />匹配适配器格式的后备缓冲区格式<br />在选择了这些排名高的组合后，要创建设备，行为标志和呈现参数仍然是需要的。对于这些设置,Direct3D使用上面表中的缺省值。</p><p><font size="4"><a name="修改可用的设备设置"></a>修改可用的设备设置</font><br />应用程序可以通过使用第二个可选的回调函数修改对框架可用的设置，这个函数是ModifyDeviceSettings:<br />bool CALLBACK ModifyDeviceSettings(<br />    DXUTDeviceSettings* pDeviceSettings,<br />    const D3DCAPS9*     pCaps )<br />{<br />    // TODO: Include device creation requirements here.  <br />    // 返回真创建设备返回False保持当前设置<br />    return true;<br />}<br />这个函数是基于原型LPDXUTCALLBACKMODIFYDEVICESETTINGS的。DXUTDeviceSettings结构体被框架定义为：<br />struct DXUTDeviceSettings<br />{<br />    UINT       AdapterOrdinal;<br />    D3DDEVTYPE DeviceType;<br />    D3DFORMAT  AdapterFormat;<br />    DWORD      BehaviorFlags;<br />    D3DPRESENT_PARAMETERS pp;<br />};</p><p>这个结构体包含了创建设备所需要的所有东西，除了窗口句柄,它被假定为先前创建的窗口的句柄。框架用有效的数据填充这个结构体，然后允许应用程序通过ModifyDeviceSettings回调函数改变设备创建的选择。<br />在这个回调函数中，应用程序可以在DXUTDeviceSettings结构体中改变行为标志以及呈现参数,乃至结构体中任何其它的东西。如果应用程序在回调函数中什么都不改变，设备会成功的创建。然而，对设备创建设置的任何改变都需要被设备支持，否则可能会导致设备创建失败。<br />比如，如果应用程序需要一个D3DFMT_D24S8的深度模板缓冲区格式，就必须验证设备是否支持，就像下面的代码：<br />bool CALLBACK ModifyDeviceSettings(<br />    DXUTDeviceSettings* pDeviceSettings,<br />    const D3DCAPS9*     pCaps )<br />{<br />    IDirect3D9* pD3D = DXUTGetD3DObject();<br />    if( SUCCEEDED( pD3D-&gt;CheckDeviceFormat(<br />         pDeviceSettings-&gt;AdapterOrdinal,<br />         pDeviceSettings-&gt;DeviceType,<br />         pDeviceSettings-&gt;AdapterFormat,<br />         D3DUSAGE_DEPTHSTENCIL,<br />         D3DRTYPE_SURFACE,<br />         D3DFMT_D24S8 ) ) )<br />    {<br />     if( SUCCEEDED( pD3D-&gt;CheckDepthStencilMatch(<br />             pDeviceSettings-&gt;AdapterOrdinal,<br />             pDeviceSettings-&gt;DeviceType,<br />             pDeviceSettings-&gt;AdapterFormat,<br />             pDeviceSettings-&gt;pp.BackBufferFormat,<br />             D3DFMT_D24S8 ) ) )<br />     {<br />         pDeviceSettings-&gt;pp.AutoDepthStencilFormat = D3DFMT_D24S8;<br />     }<br />    }<br />    <br />    return true;<br />}</p><p>候选的方案是，回调函数可以使用框架的CD3DEnumeration 对象验证D3DFMT_D24S8是否被支持：<br /> bool CALLBACK ModifyDeviceSettings(<br />    DXUTDeviceSettings* pDeviceSettings,<br />    const D3DCAPS9*     pCaps )<br />{<br />    CD3DEnumeration *pEnum = DXUTGetEnumeration();<br />    CD3DEnumDeviceSettingsCombo *pCombo;<br /> <br />    pCombo = pEnum-&gt;GetDeviceSettingsCombo( pDeviceSettings );<br /> <br />    if( pCombo-&gt;depthStencilFormatList.Contains( D3DFMT_D24S8 ) )<br />        pDeviceSettings-&gt;pp.AutoDepthStencilFormat = D3DFMT_D24S8;<br />        <br />    return true;<br />}</p><p>应用程序修改了设备的设置后，框架就会用新的设置创建设备。<br />DirectX April 2005 SDK Update中的更新，ModifyDeviceSettings 回调函数返回了一个bool值。如果应用程序返回true框架继续正常的创建设备。如果返回false框架不改变设备并且保持当前的设备，如果已经有一个存在的话。这允许应用程序能够拒绝框架将设备改变到程序不能使用的请求。例如，在多监视器的缺省配置下，在监视器之间拖动窗口会导致框架改变设备。然而，如果应用程序不能使用其它的设备的话，它应当可以拒绝改变，并继续使用当前的设备。</p><p><font size="4"><a name="回降到软件顶点处理"></a>回降到软件顶点处理</font><br />如果你设置一个Direct3D设备到支持像素处理却不支持顶点处理的硬件，你会因此需要改变行为标志。为了确保正确地降到软件顶点处理，谨防你不能拒绝一个基于IsDeviceAcceptable回调函数中顶点着色器版本的设备，并确保行为标志在ModifyDeviceSettings 回调函数中被正确调整。这儿有一个例子演示怎样做这些事情。<br />bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, <br />                                    const D3DCAPS9* pCaps )<br />{<br />    // If device doesn't support HW T&amp;L or doesn't support 1.1 vertex <br />    // shaders in HW, then switch to SWVP.<br />    if( (pCaps-&gt;DevCaps &amp; D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||<br />         pCaps-&gt;VertexShaderVersion &lt; D3DVS_VERSION(1,1) )<br />    {<br />        pDeviceSettings-&gt;BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;<br />    }</p><p>    else<br />    {<br />        pDeviceSettings-&gt;BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;<br />    }<br />    <br />    return true; <br />}</p><p><font size="4"><a name="使用你自己的设备"></a>使用你自己的设备</font><br />你没有必要依赖于框架来创建Direct3D设备。应用程序自己可以创建设备并将他传递给框架使用。就像应用程序可以覆盖框架的window creation 设置。简单的使用你想要的设置创建一个设备，然后调用 DXUTSetDevice函数让框架在你的设备上渲染。<br />注意：如果应用程序创建了不依赖于框架的设备，那么应用程序也必须在主循环执行完以后亲自的通过cleanup 释放设备接口。<br />另请参阅<br />通过DXUT作更高级的设备选择</p><img src ="http://www.cppblog.com/mybios/aggbug/15531.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-22 11:35 <a href="http://www.cppblog.com/mybios/archive/2006/11/22/15531.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】C语言高效编程的几招</title><link>http://www.cppblog.com/mybios/archive/2006/11/21/15514.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Tue, 21 Nov 2006 09:26:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/21/15514.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15514.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/21/15514.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15514.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15514.html</trackback:ping><description><![CDATA[引言：<br />　　编写高效简洁的C语言代码，是许多软件工程师追求的目标。本文就工作中的一些体会和经验做相关的阐述，不对的地方请各位指教。<br /><br />第1招：以空间换时间<br /><br />　　计算机程序中最大的矛盾是空间和时间的矛盾，那么，从这个角度出发逆向思维来考虑程序的效率问题，我们就有了解决问题的第1招——以空间换时间。<br />例如：字符串的赋值。<br />方法A，通常的办法：<br />#define LEN 32<br />char string1 [LEN];<br />memset (string1,0,LEN);<br />strcpy (string1,“This is a example!!”）;<br />方法B：<br />const char string2[LEN] =“This is a example!”;<br />char * cp;<br />cp = string2 ;<br />(使用的时候可以直接用指针来操作。)<br /><br />　　从上面的例子可以看出，A和B的效率是不能比的。在同样的存储空间下，B直接使用指针就可以操作了，而A需要调用两个字符函数才能完成。B的缺点在于灵活性没有A好。在需要频繁更改一个字符串内容的时候，A具有更好的灵活性；如果采用方法B，则需要预存许多字符串，虽然占用了大量的内存，但是获得了程序执行的高效率。<br /><br />　　如果系统的实时性要求很高，内存还有一些，那我推荐你使用该招数。<br /><br />　　该招数的变招——使用宏函数而不是函数。举例如下：<br />方法C：<br />#define bwMCDR2_ADDRESS 4<br />#define bsMCDR2_ADDRESS 17<br />int BIT_MASK(int __bf)<br />{<br />return ((1U &lt;&lt; (bw ## __bf)) - 1) &lt;&lt; (bs ## __bf);<br />}<br />void SET_BITS(int __dst, int __bf, int __val)<br />{<br />__dst = ((__dst) &amp; ~(BIT_MASK(__bf))) | \<br />(((__val) &lt;&lt; (bs ## __bf)) &amp; (BIT_MASK(__bf))))<br />}<br /><br />SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);<br />方法D：<br />#define bwMCDR2_ADDRESS 4<br />#define bsMCDR2_ADDRESS 17<br />#define bmMCDR2_ADDRESS BIT_MASK(MCDR2_ADDRESS)<br />#define BIT_MASK(__bf) (((1U &lt;&lt; (bw ## __bf)) - 1) &lt;&lt; (bs ## __bf))<br />#define SET_BITS(__dst, __bf, __val) \<br />((__dst) = ((__dst) &amp; ~(BIT_MASK(__bf))) | \<br />(((__val) &lt;&lt; (bs ## __bf)) &amp; (BIT_MASK(__bf))))<br /><br />SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);<br /><br />　　函数和宏函数的区别就在于，宏函数占用了大量的空间，而函数占用了时间。大家要知道的是，函数调用是要使用系统的栈来保存数据的，如果编译器里有栈检查选项，一般在函数的头会嵌入一些汇编语句对当前栈进行检查；同时，CPU也要在函数调用时保存和恢复当前的现场，进行压栈和弹栈操作，所以，函数调用需要一些CPU时间。而宏函数不存在这个问题。宏函数仅仅作为预先写好的代码嵌入到当前程序，不会产生函数调用，所以仅仅是占用了空间，在频繁调用同一个宏函数的时候，该现象尤其突出。<br /><br />　　D方法是我看到的最好的置位操作函数，是ARM公司源码的一部分，在短短的三行内实现了很多功能，几乎涵盖了所有的位操作功能。C方法是其变体，其中滋味还需大家仔细体会。<br /><br />第2招：数学方法解决问题<br /><br />　　现在我们演绎高效C语言编写的第二招——采用数学方法来解决问题。<br /><br />　　数学是计算机之母，没有数学的依据和基础，就没有计算机的发展，所以在编写程序的时候，采用一些数学方法会对程序的执行效率有数量级的提高。<br />举例如下，求 1~100的和。<br />方法E<br />int I , j;<br />for (I = 1 ;I&lt;=100; I ++）{<br />j += I;<br />}<br />方法F<br />int I;<br />I = (100 * (1+100)) / 2<br /><br />　　这个例子是我印象最深的一个数学用例，是我的计算机启蒙老师考我的。当时我只有小学三年级，可惜我当时不知道用公式 N×（N+1）/ 2 来解决这个问题。方法E循环了100次才解决问题，也就是说最少用了100个赋值，100个判断，200个加法（I和j）；而方法F仅仅用了1个加法，1 次乘法，1次除法。效果自然不言而喻。所以，现在我在编程序的时候，更多的是动脑筋找规律，最大限度地发挥数学的威力来提高程序运行的效率。<br /><br />第3招：使用位操作<br /><br />　　实现高效的C语言编写的第三招——使用位操作，减少除法和取模的运算。<br /><br />　　在计算机程序中，数据的位是可以操作的最小数据单位，理论上可以用“位运算”来完成所有的运算和操作。一般的位操作是用来控制硬件的，或者做数据变换使用，但是，灵活的位操作可以有效地提高程序运行的效率。举例如下：<br />方法G<br />int I,J;<br />I = 257 /8;<br />J = 456 % 32;<br />方法H<br />int I,J;<br />I = 257 &gt;&gt;3;<br />J = 456 - (456 &gt;&gt; 4 &lt;&lt; 4);<br /><br />　　在字面上好像H比G麻烦了好多，但是，仔细查看产生的汇编代码就会明白，方法G调用了基本的取模函数和除法函数，既有函数调用，还有很多汇编代码和寄存器参与运算；而方法H则仅仅是几句相关的汇编，代码更简洁，效率更高。当然，由于编译器的不同，可能效率的差距不大，但是，以我目前遇到的MS C ,ARM C 来看，效率的差距还是不小。相关汇编代码就不在这里列举了。<br />运用这招需要注意的是，因为CPU的不同而产生的问题。比如说，在PC上用这招编写的程序，并在PC上调试通过，在移植到一个16位机平台上的时候，可能会产生代码隐患。所以只有在一定技术进阶的基础下才可以使用这招。<br /><br />第4招：汇编嵌入<br /><br />　　高效C语言编程的必杀技，第四招——嵌入汇编。<br /><br />　　“在熟悉汇编语言的人眼里，C语言编写的程序都是垃圾”。这种说法虽然偏激了一些，但是却有它的道理。汇编语言是效率最高的计算机语言，但是，不可能靠着它来写一个操作系统吧?所以，为了获得程序的高效率，我们只好采用变通的方法 ——嵌入汇编，混合编程。<br /><br />　　举例如下，将数组一赋值给数组二,要求每一字节都相符。<br />char string1[1024],string2[1024];<br />方法I<br />int I;<br />for (I =0 ;I&lt;1024;I++)<br />*(string2 + I) = *(string1 + I)<br />方法J<br />#ifdef _PC_<br />int I;<br />for (I =0 ;I&lt;1024;I++)<br />*(string2 + I) = *(string1 + I);<br />#else<br />#ifdef _ARM_<br />__asm<br />{<br />MOV R0,string1<br />MOV R1,string2<br />MOV R2,#0<br />loop:<br />LDMIA R0!, [R3-R11]<br />STMIA R1!, [R3-R11]<br />ADD R2,R2,#8<br />CMP R2, #400<br />BNE loop<br />}<br />#endif<br /><br />　　方法I是最常见的方法，使用了1024次循环；方法J则根据平台不同做了区分，在ARM平台下，用嵌入汇编仅用128次循环就完成了同样的操作。这里有朋友会说，为什么不用标准的内存拷贝函数呢?这是因为在源数据里可能含有数据为0的字节，这样的话，标准库函数会提前结束而不会完成我们要求的操作。这个例程典型应用于LCD数据的拷贝过程。根据不同的CPU，熟练使用相应的嵌入汇编，可以大大提高程序执行的效率。<br /><br />　　虽然是必杀技，但是如果轻易使用会付出惨重的代价。这是因为，使用了嵌入汇编，便限制了程序的可移植性，使程序在不同平台移植的过程中，卧虎藏龙，险象环生！同时该招数也与现代软件工程的思想相违背，只有在迫不得已的情况下才可以采用。切记，切记。 <br /><br /><img src ="http://www.cppblog.com/mybios/aggbug/15514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-21 17:26 <a href="http://www.cppblog.com/mybios/archive/2006/11/21/15514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】直接载入内存中的DLL</title><link>http://www.cppblog.com/mybios/archive/2006/11/21/15483.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Mon, 20 Nov 2006 16:45:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/21/15483.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15483.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/21/15483.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15483.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15483.html</trackback:ping><description><![CDATA[作者：<a href="mailto:njjane@21cn.com">任明汉</a><p><a href="http://www.vckbase.com/code/downcode.asp?id=2358">下载源代码</a><br /><br /><img src="http://www.vckbase.com/document/image/paragraph.gif" /><b>前言</b></p><p>　　你可能不希望在发布程序时附带上一个外部的 DLL，因为可能会有些用户在无意中把 DLL 删除了而造成 EXE 不能正确运行，也有可能该 DLL 会被别人拿去使用，也有可能，此 DLL 会成为破解者破解你的程序的突破口。无论出于何种原因，如果你想把一个 DLL 合并到一个 EXE 中的话，本文向你介绍这种方法。 <br /></p><hr /><img src="http://www.vckbase.com/document/image/paragraph.gif" /><b>Win32 程序调用 DLL 的机制</b><br /><br />　　 Win32 EXE 在调用一个外部 DLL 中的函数时，首先要调用 LoadLibary 函数来载入此 DLL 到程序的进程地址空间。 如果 LoadLibary 载入此 DLL 成功，将返回一个该 DLL 的句柄。 这个句柄实际上就是该 DLL 在内存中的起始地址。 在载入 DLL 成功后，还必须调用 GetProcAddress 函数来获取要调用的函数的地址。然后再根据该地址来调用这个函数。<br />根据上述原理，我们可以把一个 DLL 作为资源文件放到 EXE 文件中，在程序运行时，分配一块内存，然后将此资源复制到该分配的内存中，并根据该内存地址计算得到相关的导出函数地址，然后，当我们需要调用某一函数时，可以用该函数在内存中的地址来调用它。 <br />程序实现。<br />　　首先，把要合并的 DLL 作为资源加入到项目的资源文件中，然后在程序运行时，从资源中载入该资源，以得到该 DLL 在内存中的位置： <br /><pre>LPVOID sRawDll; // 资源文件在内存中的地址 
HRSRC hRes; 
HMODULE hLibrary; 
HGLOBAL hResourceLoaded; 
char lib_name[MAX_PATH]; 
GetModuleFileName(hInstance, lib_name, MAX_PATH ); // 得到运行程序的名字 
hLibrary = LoadLibrary(lib_name);                  // 就象载入一个 DLL 一样载入运行程序到内存中 

if (NULL != hLibrary) 
{
	// 得到指定的资源文件在内存中的位置 
	hRes = FindResource(hLibrary, MAKEINTRESOURCE(IDR_DATA1), RT_RCDATA); 
	if (NULL != hRes) 
	{
		// 将资源文件载入内存 
		hResourceLoaded = LoadResource(hLibrary, hRes); 
		if (NULL != hResourceLoaded) 
		{
			// 得到资源文件大小 
			SizeofResource(hLibrary, hRes); 

			// 锁定资源以得到它在内存中的地址 
			sRawDll = (LPVOID)LockResource(hResourceLoaded); 
		}
	}
	else return 1; 
	FreeLibrary(hLibrary);
}
else return 1; 
</pre>然后，从资源中载入 DLL 到内存函数 LoadPbDllFromMemory 将载入 DLL 到内存中， 该函数有两个参数，第一个参数是指向 DLL 资源在内存中的地址的指针，也就是前面代码中的 LockResource 函数的返回值。第二个参数是一个空的指针，如果函数 LoadPbDllFromMemory 运行成功，该指针将指向重新组合后的内存中的 DLL 的起始地址。该函数还有一个功能就是如果运行成功，它将手动地用 DLL_PROCESS_ATTACH 参数调用 DLL 的入口函数 DllMain 来初始化该 DLL。除此之外，它还会手动地载入合并的 DLL 的入口表中导入的 DLL 并调整它们在内存中的相对地址。以下是该函数代码:<pre>DWORD LoadPbDllFromMemory(LPVOID lpRawDll, LPVOID lpImageDll) 
{
	SYSTEM_INFO sSysInfo; 
	PIMAGE_DOS_HEADER dosHeader; 
	PIMAGE_NT_HEADERS pNTHeader; 
	PIMAGE_SECTION_HEADER section; 
	PIMAGE_IMPORT_DESCRIPTOR pImportDesc; 
	PIMAGE_IMPORT_BY_NAME pOrdinalName; 
	PIMAGE_BASE_RELOCATION baseReloc; 
	PDWORD lpLink; 
	unsigned char Protection[4096]; 
	HINSTANCE hDll; 
	WORD i; 
	DWORD ImagePages,fOldProtect,j,MaxLen,HdrLen,Addr1,Addr2,Pg,Pg1,Pg2; 
	char * sDllName; 

	if(NULL == lpRawDll) return 1 ; 

	dosHeader = (PIMAGE_DOS_HEADER)lpRawDll; 

	// Is this the MZ header? 
	if ((TRUE == IsBadReadPtr(dosHeader,sizeof (IMAGE_DOS_HEADER))) ||
				 (IMAGE_DOS_SIGNATURE != dosHeader-&gt;e_magic)) 
		return 2; 

	// Get the PE header. 
	pNTHeader = MakePtr(PIMAGE_NT_HEADERS,dosHeader,dosHeader-&gt;e_lfanew); 

	// Is this a real PE image? 
	if((TRUE == IsBadReadPtr(pNTHeader,sizeof ( IMAGE_NT_HEADERS))) || 
				( IMAGE_NT_SIGNATURE != pNTHeader-&gt;Signature)) 
		return 3 ; 

	if(( pNTHeader-&gt;FileHeader.SizeOfOptionalHeader != 
			sizeof(pNTHeader-&gt;OptionalHeader)) || 
		(pNTHeader-&gt;OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)) 
		return 4; 

	if (pNTHeader-&gt;FileHeader.NumberOfSections &lt; 1) return 5; 

	section = IMAGE_FIRST_SECTION( pNTHeader ); 
	int HeaderSize = sizeof(IMAGE_SECTION_HEADER); 

	// 节头长度 
	HdrLen = (DWORD)section - (DWORD)dosHeader + 
			HeaderSize * pNTHeader-&gt;FileHeader.NumberOfSections; 

	// 找出最大的节的长度,此节一般是代码所在的节(.text 节) 
	MaxLen = HdrLen; 
	int ii=0; 

	for (i = 0;i&lt;(DWORD)pNTHeader-&gt;FileHeader.NumberOfSections;i++)// find MaxLen 
	{
		if(MaxLen &lt; section[i].VirtualAddress + section[i].SizeOfRawData) 
		{
			MaxLen = section[i].VirtualAddress + section[i].SizeOfRawData; 
		}
		if(strcmp((const char *)section[i].Name,".rsrc") == 0) ii=i; 
	}

	GetSystemInfo(&amp;sSysInfo);
	ImagePages = MaxLen / sSysInfo.dwPageSize; 
	if (MaxLen % sSysInfo.dwPageSize) ImagePages++; 

	// 分配所需的内存 
	DWORD NeededMemory = ImagePages * sSysInfo.dwPageSize; 
	lpImageDll = VirtualAlloc(NULL, NeededMemory, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 

	if (lpImageDll == NULL) return 6; // 分配内存失败 

	MoveMemory( lpImageDll, lpRawDll, HdrLen ); // 复制节头 

	DWORD OrgAddr = 0; 
	DWORD NewAddr = 0; 
	DWORD Size = 0; 

	// 复制 .text 节数据 
	for (i = 0;i&lt;pNTHeader-&gt;FileHeader.NumberOfSections;i++) 
	{
		OrgAddr = (DWORD)lpImageDll + (DWORD)section[i].VirtualAddress; 
		NewAddr = (DWORD)lpRawDll + (DWORD)section[i].PointerToRawData; 
		Size = (DWORD)section[i].SizeOfRawData; 
		MoveMemory((void *)OrgAddr, (void *)NewAddr, Size ); 
	}

	// 把指针指向新的 DLL 映像 
	dosHeader = (PIMAGE_DOS_HEADER) lpImageDll; // Switch to new image 
	pNTHeader = (PIMAGE_NT_HEADERS) ((DWORD)dosHeader + dosHeader-&gt;e_lfanew); 
	section = (PIMAGE_SECTION_HEADER) ((DWORD)pNTHeader + sizeof(IMAGE_NT_HEADERS)); 
	pImageBase = (PBYTE)dosHeader; 

	if((ii!=0) &amp;&amp; (IsNT()==TRUE)) 
	{
		section[ii].VirtualAddress = section[ii].VirtualAddress + (DWORD)lpRawDll; 
		section[ii].PointerToRawData = section[ii].PointerToRawData + (DWORD)lpRawDll; 
	}

	DWORD importsStartRVA; 

	// Look up where the imports section is (normally in the .idata section) 
	// but not necessarily so. Therefore, grab the RVA from the data dir. 
	importsStartRVA = GetImgDirEntryRVA(pNTHeader,IMAGE_DIRECTORY_ENTRY_IMPORT); 
	if ( !importsStartRVA ) 
	{
		VirtualFree(dosHeader,0, MEM_RELEASE); 
		return 7; 
	}

	pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) pNTHeader-&gt;
		OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; 

	if(pImportDesc!= 0) 
		pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ((DWORD)pImportDesc + (DWORD)dosHeader); 
	else 
	{
		VirtualFree(dosHeader,0, MEM_RELEASE); 
		return 8; 
	}

	while (1) // 处理各入口表中的 DLL 
	{
		// 检查是否遇到了空的 IMAGE_IMPORT_DESCRIPTOR 
		if ((pImportDesc-&gt;TimeDateStamp==0 ) &amp;&amp; (pImportDesc-&gt;Name==0)) break; 

		// 从磁盘载入必须的 Dll, 
		// 注意,载入的 DLL 是合并的 DLL 的入口表中的 DLL, 
		// 不是合并到 EXE 中的 DLL 
		sDllName = (char *) (pImportDesc-&gt;Name + (DWORD)pImageBase); 
		hDll = GetModuleHandle(sDllName); 

		if (hDll == 0 ) hDll = LoadLibrary(sDllName); 

		if (hDll == 0 ) 
		{
			MessageBox(NULL, "Can''t find required Dll",
					"Error in LoadPbDllFromMemory()",0); 
			VirtualFree(dosHeader,0, MEM_RELEASE); 
			return 9; 
		}

		DWORD *lpFuncNameRef = (DWORD *) (pImportDesc-&gt;OriginalFirstThunk +
								 (DWORD)dosHeader); 
		DWORD *lpFuncAddr = (DWORD *) (pImportDesc-&gt;FirstThunk +
								 (DWORD)dosHeader); 

		while( *lpFuncNameRef != 0) 
		{
			pOrdinalName = (PIMAGE_IMPORT_BY_NAME) (*lpFuncNameRef +
						 (DWORD)dosHeader); 
			DWORD pIMAGE_ORDINAL_FLAG = 0x80000000; 

			if (*lpFuncNameRef &amp; pIMAGE_ORDINAL_FLAG) 
				*lpFuncAddr = (DWORD) GetProcAddress(hDll,
					 (const char *)(*lpFuncNameRef &amp; 0xFFFF)); 
			else
				*lpFuncAddr = (DWORD) GetProcAddress(hDll,
						 (const char *)pOrdinalName-&gt;Name); 

			if (lpFuncAddr == 0) 
			{
				VirtualFree(dosHeader,0, MEM_RELEASE); 
				return 10;// Can''t GetProcAddress 
			}

			lpFuncAddr++;
			lpFuncNameRef++;
		}
		pImportDesc++;
	}

	DWORD TpOffset; 
	baseReloc = (PIMAGE_BASE_RELOCATION)((DWORD)pNTHeader-&gt;
　　　　 OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); 

	if (baseReloc !=0) 
	{
		baseReloc = (PIMAGE_BASE_RELOCATION) ((DWORD)baseReloc + (DWORD)dosHeader); 
		while(baseReloc-&gt;VirtualAddress != 0) 
		{
			PWORD lpTypeOffset = (PWORD) ((DWORD)baseReloc +
					 sizeof(IMAGE_BASE_RELOCATION)); 
			while (lpTypeOffset &lt; (PWORD)((DWORD)baseReloc +
						 (DWORD)baseReloc-&gt;SizeOfBlock)) 
			{
				TpOffset = *lpTypeOffset &amp; 0xF000; 
				if(TpOffset == 0x3000) 
				{
					lpLink = (PDWORD) ((DWORD)dosHeader +
　　　　　　　　　　　　　　　　　　　　　　             baseReloc-&gt;VirtualAddress +
                                                      (*lpTypeOffset &amp; 0xFFF)); 
					*lpLink = (DWORD)dosHeader + 
                                            (*lpLink) - pNTHeader-&gt;OptionalHeader.ImageBase; 
				}
				else
				{
					if (TpOffset != 0) 
					{
						VirtualFree(dosHeader,0, MEM_RELEASE); 
						return 10; 
					}
				}
				lpTypeOffset++;
			}
			baseReloc = (PIMAGE_BASE_RELOCATION)((DWORD)baseReloc + 
				(DWORD)baseReloc-&gt;SizeOfBlock); 
		}
	}

	// 取得原始的内存状态 
	memset(Protection,0,4096);
	for (i = 0;i&lt;=pNTHeader-&gt;FileHeader.NumberOfSections;i++) 
	{
		if (i == pNTHeader-&gt;FileHeader.NumberOfSections) 
		{
			Addr1 = 0; 
			Addr2 = HdrLen; 
			j = 0x60000000; 
		}
		else
		{
			Addr1 = section[i].VirtualAddress; 
			Addr2 = section[i].SizeOfRawData; 
			j = section[i].Characteristics; 
		}
		Addr2 += Addr1 - 1; 

		Pg1 = Addr1 / sSysInfo.dwPageSize; 
		Pg2 = Addr2 / sSysInfo.dwPageSize; 
		for(Pg = Pg1 ;Pg&lt;=Pg2;Pg++) 
		{
			if (j &amp; 0x20000000) Protection[Pg] |= 1; // Execute 
			if (j &amp; 0x40000000) Protection[Pg] |= 2; // Read 
			if (j &amp; 0x80000000) Protection[Pg] |= 4; // Write 
		}
	}

	// 恢复原始的内存状态 
	Addr1 = (DWORD)dosHeader; 
	for (Pg = 0 ;Pg&lt;= ImagePages;Pg++) 
	{
		switch(Protection[Pg])
		{
		case 2: 
			fOldProtect = PAGE_READONLY; 
			break;
		case 3: 
			fOldProtect = PAGE_EXECUTE_READ; 
			break;
		case 6: 
			fOldProtect = PAGE_READWRITE; 
			break;
		default: 
			// Ignore strange combinations
			fOldProtect = PAGE_EXECUTE_READWRITE;  
			break;
		}

		if (fOldProtect !=PAGE_EXECUTE_READWRITE) 
		{
			if (VirtualProtect((void *)Addr1, 
				sSysInfo.dwPageSize, 
				fOldProtect,
				&amp;fOldProtect) == 0) 
			{
				VirtualFree(dosHeader,0, MEM_RELEASE); 
				return 11; 
			}
		}
		Addr1 += sSysInfo.dwPageSize; 
	}

	EntryPoint = (LPENTRYPOINT) ((DWORD)pNTHeader-&gt;OptionalHeader.AddressOfEntryPoint +
				 (DWORD)dosHeader); 
	LPVOID lpReserved = 0; 
	EntryPoint((HINSTANCE)dosHeader, DLL_PROCESS_ATTACH, lpReserved); 
	lpImageDll2=lpImageDll;
	return 0; 
}
</pre>　　一但 DLL 被正确地载入到内存中，我们就可以通过自定义函数 GetProcAddressDirectly 来获取某函数在内存中的地址，并根据该地址来调用该函数，该函数也有两个参数，第一个参数是指向载入到内存中的 DLL 的起始地址的指针，第二个是要调用的函数的函数名。以下是 GetProcAddressDirectly 函数代码: <pre>DWORD GetProcAddressDirectly(PIMAGE_DOS_HEADER dosHeader, char * FuncName)  
{ 
	PIMAGE_NT_HEADERS pNTHeader;  
	PIMAGE_EXPORT_DIRECTORY pExportDir;  
	PWORD lpNameOrdinals;  
	LPDWORD lpFunctions;  
	DWORD * lpName;  
	char * lpExpFuncName;  
	DWORD i;  
	DWORD j;  
	char * lpFuncName;  

	if(dosHeader-&gt;e_magic != IMAGE_DOS_SIGNATURE) return 0;  

	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + dosHeader-&gt;e_lfanew);  

	if (pNTHeader-&gt;Signature != IMAGE_NT_SIGNATURE) return 0;  

	if ((pNTHeader-&gt;FileHeader.SizeOfOptionalHeader != sizeof(pNTHeader-&gt;OptionalHeader)) ||  
		(pNTHeader-&gt;OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC))  
		return 0;  

	DWORD exportsStartRVA, exportsEndRVA;  
	pImageBase = (PBYTE)dosHeader;  

	// Make pointers to 32 and 64 bit versions of the header.  
	pNTHeader = MakePtr( PIMAGE_NT_HEADERS, dosHeader,dosHeader-&gt;e_lfanew );  

	exportsStartRVA = GetImgDirEntryRVA(pNTHeader,IMAGE_DIRECTORY_ENTRY_EXPORT);  
	exportsEndRVA = exportsStartRVA +  
		GetImgDirEntrySize(pNTHeader, IMAGE_DIRECTORY_ENTRY_EXPORT);  

	// Get the IMAGE_SECTION_HEADER that contains the exports. This is  
	// usually the .edata section, but doesn''t have to be.  
	PIMAGE_SECTION_HEADER header;  
	header = GetEnclosingSectionHeader( exportsStartRVA, pNTHeader );  
	if ( !header ) return 0;  

	INT delta;  
	delta = (INT)(header-&gt;VirtualAddress - header-&gt;PointerToRawData);  
	pExportDir = (PIMAGE_EXPORT_DIRECTORY)GetPtrFromRVA(exportsStartRVA, 
				pNTHeader, pImageBase);  


	pExportDir =(PIMAGE_EXPORT_DIRECTORY) (pNTHeader-&gt;
	OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);  

	if (pExportDir == 0)  
	{ 
		MessageBox(NULL,"Error in GetProcAddressDirectly()",0,0);  
		return 0;  
	} 

	pExportDir =(PIMAGE_EXPORT_DIRECTORY) ((DWORD)pExportDir + (DWORD)dosHeader);  
	lpNameOrdinals =(PWORD)((DWORD)pExportDir-&gt;AddressOfNameOrdinals + (DWORD)dosHeader);  
	lpName =(LPDWORD) (pExportDir-&gt;AddressOfNames + (DWORD)dosHeader);  
	lpFunctions =(LPDWORD) (pExportDir-&gt;AddressOfFunctions + (DWORD)dosHeader);  
	lpFuncName = FuncName;  

	if(HIWORD(lpFuncName)!=0 )  
	{ 
		for( i = 0;i&lt;=pExportDir-&gt;NumberOfFunctions - 1;i++)  
		{ 
			DWORD entryPointRVA = *lpFunctions;  

			// Skip over gaps in exported function  
			if ( entryPointRVA == 0 ) continue; 
			for( j = 0;j&lt;=pExportDir-&gt;NumberOfNames-1;j++)  
			{ 
				if( lpNameOrdinals[j] == i)  
				{ 
					lpExpFuncName = (char *) (lpName[j] + 
							(DWORD)dosHeader);  
					if(strcmp((char *)lpExpFuncName,(char *)FuncName)==0)  
						return (DWORD) (lpFunctions[i] + 
								(DWORD)dosHeader);  
				} 
			} 
		} 
	} 
	else 
	{ 
		for (i = 0 ;i&lt;=pExportDir-&gt;NumberOfFunctions - 1;i++)  
		{ 
			if (lpFuncName == (char *)(pExportDir-&gt;Base + i))  
			{ 
				if (lpFunctions[i]) return (unsigned long) (lpFunctions[i] + 
							dosHeader);  
			} 
		} 
	} 
	return 0;  
}


</pre>在调用完函数后，不要忘记用 UnloadPbDllFromMemory 来从内存中移去 DLL 以释放分配的内存，该函数还会用 DLL_PROCESS_DETACH 参数调用 DLL 的入口函数 DllMain 来从调用进程的地址空间卸载该 DLL。 以下是 UnloadPbDllFromMemory 函数代码:<pre>DWORD UnloadPbDllFromMemory(PIMAGE_DOS_HEADER dosHeader) 
{
	PIMAGE_NT_HEADERS pNTHeader; 
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + (DWORD)dosHeader-&gt;e_lfanew); 
	EntryPoint = (LPENTRYPOINT)(pNTHeader-&gt;OptionalHeader.AddressOfEntryPoint +
					 (DWORD)dosHeader); 
	EntryPoint((HINSTANCE)dosHeader, DLL_PROCESS_DETACH, 0); 
	return VirtualFree(dosHeader, 0, MEM_RELEASE); 
}
</pre><hr /><b><br /></b><img src="http://www.vckbase.com/document/image/paragraph.gif" /><b>关于示例代码的说明</b><p>　　在本文附带的示例代码中，合并了一个名为 hardware.dll 的动态连接库，该动态连接库是一个获取系统硬件信息的库文件，其中包括了以下函数:</p><pre>   getmac 		取得网卡 MAC 
   VolumeNumber 	取得硬盘卷标 
   changeres            改变屏幕分辩率 
   IsDiskInDrive        检查软驱中是否插有盘 
   DPGetDefaultPrinter  取得默认的打印机名 
   DPSetDefaultPrinter  设置默认的打印机 
   getserial            取得硬盘的出厂序列号 
   getmetric            取得显示分辩率 
   PrintStringDirect    直接向打印机发送一个串 
   vfpbeep              让 PC 喇叭发声 
   getcpuid             取得 CPU ID 
   getbios              取得主板 BIOS ID 
</pre>　　在示例代码中，只调用了其中一个函数 getbios 来获取主板 BIOS ID， 这里说明一下，该函数实际上好象只能检测 AWARD 主板的 BIOS， 也就是说它是读取的是系统内存 0x000fex71 处的值。因为其它牌子的主板 BIOS 的位置稍有不同，但在程序中没有进行这方面的处理，所以在读其它牌子的主板 BIOS 时可能会有些问题(读出的内容可能不正确)。关于此 DLL 的内容和实现，也许我会在另一篇文章中论及。 <br />　 
<hr /><br /><img src="http://www.vckbase.com/document/image/paragraph.gif" /><b>局限<br />　　</b>在我进行测试时，发现对于有些含有资源的 DLL，在 9x 平台下可能会有问题。<br /><p><img src="http://www.vckbase.com/document/image/paragraph.gif" /><b>题外话<br />　　</b>另外，其它一些本文未提及的非主要的函数，请自行参见源代码中的注释。<br />再，本文涉及 PE 文件格式方面的知识，它们已经超出了本文的范围，具体信息可参见 MSDM 中的:</p><dir><li><i>Peering Inside the PE: A Tour of the Win32 Portable Executable File Format 一</i>文和 
</li><li><i>Microsoft Portable Executable and Common Object File Format Specification </i>一文 </li></dir><p><b>特别感谢卢春明（Aming）在我编写本文时所作的一些技术方面的建议和指导</b></p><img src ="http://www.cppblog.com/mybios/aggbug/15483.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-21 00:45 <a href="http://www.cppblog.com/mybios/archive/2006/11/21/15483.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】EffectFramework</title><link>http://www.cppblog.com/mybios/archive/2006/11/20/15464.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Mon, 20 Nov 2006 08:54:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/20/15464.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15464.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/20/15464.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15464.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15464.html</trackback:ping><description><![CDATA[
		<p>
				<font face="宋体">
						<strong>Effect Framework</strong>
				</font>
		</p>
		<p>
				<strong>
						<font face="宋体">摘要</font>
				</strong>
		</p>
		<p>
				<font face="宋体">本文简要介绍了在DirectX 9 SDK中提供的Effect Framework支持，以及DirectX FX文件结构和Microsoft Hight Level Shading Language的基本知识。本文假定读者对DirectX Graphics有一定了解，并正在学习DirectX Effect Framework。希望能够与各位读者共同探讨、切磋。 </font>
		</p>
		<p>
				<font face="宋体">
						<strong>简介 </strong>
				</font>
		</p>
		<p>
				<font face="宋体">Effect的起源 </font>
		</p>
		<p>
				<font face="宋体">在计算机3维场景中，物体表面的材质代表了其光学特性。最简单的材质可以表现为Diffuse颜色，Specular颜色，Emissive颜色等信息的集合；而为了表现物体表面的细节，可以 在材质中加入一张纹理——这些就构成了最基本的材质信息。在以前的Direct3D程序中，这些信息可以直接传送给设备，由设备自动根据它们来计算物体表面的光学效果。但是， 仅仅有这些基本的材质信息，已经不足以满足游戏制作者的要求和游戏玩家的要求了——他们希望场景中的材质更加复杂，具有更多的细节，更加逼真。 </font>
		</p>
		<p>
				<font face="宋体">在Direct3D中，除了材质的概念，还存在一个渲染状态（Render State）的概念。在Direct3D Device中存在很多的渲染状态，它们可以在Direct3D进行渲染时控制渲染的流程和效 果，从而实现某些带有特效的材质。程序员可以通过IDirect3DDevice*::SetRenderState()方法来设置这些状态。所有的渲染状态都是一些特定的数值。对状态的设置可以通过硬 编码完成，即在程序中调用SetRenderState()方法，将设置什么样的状态“写死”在程序里，但是这样做的缺点就是太不灵活了——如果想要实现一种新的渲染状态，就需要修改 程序代码。所以更好的一种方法是将为了实现某一种特效材质的一些渲染状态值记录到一个“效果文件”中，通过在程序运行时读取该文件，从中分析出这些值，并将它们作为参 数调用SetRenderState()。这样，要想实现一种新的特效，只需修改“效果文件”而不用更改代码。 </font>
		</p>
		<p>
				<font face="宋体">Direct3D SDK是通过Effect Framework来支持这种机制的。而前面所述的“效果文件”在Direct3D中是以*.fx文件存在的。在fx文件中保存了为实现某一特效的渲染状态，包括状态名 称和它们的对应值。所以在9.0以前版本的DirectX中就已经有Effect Framework和FX文件了，早期的Effect Framework仅仅是为了实现对渲染状态进行控制。 但是随着计算机显示硬件技术的发展，图形处理单元（GPU）正在重复CPU所走过的路——新一代的GPU已经具有了可编程特性，程序员可以通过对GPU编写一段程序来控制其渲染的 输出效果。这种程序一般称为Shader程序。目前的Shader程序分成两种，Vertex Shader和Pixel Shader。Vertex Shader主要用于对3维网格模型的每一个顶点进行处理，而Pixel Shader主要用于对要绘制到屏幕上的每一个象素进行处理。通过Shader，程序员可以制作出相当丰富的实时渲染效果。</font>
		</p>
		<p>
				<font face="宋体">同CPU一样，对GPU编程也是借助一定的编程语言来进行的。 </font>
				<font face="宋体">在DirectX 8中，对GPU的编程是通过一种类似于汇编的语言进行的。而在DirectX 9中，使用了一种类似于C语言的高级语言——Microsoft High Level Shading Language (HLSL) 。</font>
		</p>
		<p>
				<font face="宋体">无论使用什么语言对GPU编程，都需要把编译好的Shader程序输送到显卡去。Direct3D Device可以通过SetVertexShader()和SetPixelShader()来向显卡输送Shader程序。然而，由 于Shader和材质具有十分紧密的关系——一般来说，一个Shader就是为了实现一种特殊的材质——最好是能够将Shader程序与材质进行整合。 所以，在DirectX 8和DirectX 9中，原来的Effect Framework发生了扩充——在原来的基础上加入了对Shader程序的支持。程序员可以把Vertex Shader和Pixel Shader程序以函数 的方式直接书写在FX文件中。</font>
		</p>
		<p>
				<font face="宋体"> .FX文件</font>
		</p>
		<p>
				<font face="宋体">FX文件中的内容大致可以分成几部分： </font>
		</p>
		<ul>
				<li>
						<font face="宋体">预编译标志 </font>
				</li>
				<li>
						<font face="宋体">变量表 </font>
				</li>
				<li>
						<font face="宋体">结构定义 </font>
				</li>
				<li>
						<font face="宋体">函数 </font>
				</li>
				<li>
						<font face="宋体">Technique </font>
				</li>
		</ul>
		<p>
				<font face="宋体">预编译标志：预编译标志包括 </font>
		</p>
		<ul>
				<li>
						<font face="宋体">#define </font>
				</li>
				<li>
						<font face="宋体">#elif </font>
				</li>
				<li>
						<font face="宋体">#else </font>
				</li>
				<li>
						<font face="宋体">#endif </font>
				</li>
				<li>
						<font face="宋体">#error </font>
				</li>
				<li>
						<font face="宋体">#if </font>
				</li>
				<li>
						<font face="宋体">#ifdef </font>
				</li>
				<li>
						<font face="宋体">#ifndef </font>
				</li>
				<li>
						<font face="宋体">#include </font>
				</li>
				<li>
						<font face="宋体">#line </font>
				</li>
				<li>
						<font face="宋体">#pragma </font>
				</li>
				<li>
						<font face="宋体">#undef </font>
				</li>
		</ul>
		<p>
				<font face="宋体">其中最常用到的是#include和#define，同C语言中的意义很相似：用#include可以在一个FX文件中引入另外一个或多个文件。#define可以定义FX文件中的宏替换。例如： </font>
		</p>
		<table cellspacing="5" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<p>
												<span class="unnamed2">
														<font face="宋体">#include "helper_Funcs.fx"</font>
												</span>
												<font face="宋体">     <span class="unnamed1">//引入一个名为helper_funcs.fx的fx文件</span><br /><span class="unnamed2">#include "public_variables.fh</span>" <span class="unnamed1">//引入一个名为public_variables.fh的文件</span><br /><span class="unnamed2">#define MATRICES_COUNT 25</span>      <span class="unnamed1">//定义宏MATRICES_COUNT为25</span><br /><span class="unnamed2">#define VSHADER VShader_2_0</span>    <span class="unnamed1">//定义宏VSHADER为VShader_2_0</span></font>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<font face="宋体">#include带来的好处和C中也是一样的－您可以在一个头文件中定义一些公有变量、函数等，在其他文件中引用它们－就不用写很多遍了。例如： </font>
		</p>
		<p>
				<font face="宋体">文件public.fh: </font>
		</p>
		<table cellspacing="5" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<p>
												<span class="unnamed2">
														<font face="宋体">mat4x4</font>
												</span>
												<font face="宋体"> matWorldViewProj; <span class="unnamed1">// 4x4世界－视－投影变换矩阵</span><br /></font>
												<span class="unnamed2">
														<font face="宋体">float3</font>
												</span>
												<font face="宋体"> lightPosisiton;   <span class="unnamed1">// 三维光源位置向量</span><br /><span class="unnamed2">float4</span> lightColor;     <span class="unnamed1">  // 光源的颜色</span><br /><span class="unnamed2">float</span> time;              <span class="unnamed1">// 当前时间</span></font>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<font face="宋体">//定义一个名为VS_OUTPUT的结构。关于结构体定义，下文中会有介绍 <br /></font>
		</p>
		<table width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">struct</font>
										</span>
										<font face="宋体"> VS_INPUT <br />{<br />    <span class="unnamed2">float4</span> LocalPos : POSITION; <br />    <span class="unnamed2">float3</span> Normal : NORMAL; <br />    <span class="unnamed2">float4</span> Color : COLOR; <br />    <span class="unnamed2">float2</span> Texcoord : TEXCOORD0; <br />};</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
		</p>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">struct VS_OUTPUT</font>
										</span>
										<font face="宋体">
												<br />{<br />   <span class="unnamed2"> float4</span> WorldPos : POSITION;<br />    <span class="unnamed2">float4</span> Color : COLOR; <br />    <span class="unnamed2">float2</span> Texcoord : TEXCOORD0; <br />}; </font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
		</p>
		<p>
				<font face="宋体">//定义一个名为CaculateWorldPosition的函数。关于函数定义，下文中会有介绍 <br /></font>
		</p>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">float3</font>
										</span>
										<font face="宋体"> CaculateWorldPosition( <span class="unnamed2">float4</span> LocalPos ) <br />{<br />    <span class="unnamed2">return</span> mul( LocalPos, matWorldViewProj); <br />}</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
		</p>
		<p>
				<font face="宋体">这样，当我们在另外一个文件中include这个头文件时，上面所有的定义都可以直接使用了。 </font>
		</p>
		<p>
				<font face="宋体">文件client.fx: </font>
		</p>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<p class="unnamed2">
												<font face="宋体">#include "public.fh" </font>
										</p>
										<p>
												<font face="宋体">
														<br />
														<span class="unnamed2">VS_OUTPUT</span> VS_main( VS_INPUT In ) <span class="unnamed1">// 可以直接使用结构体定义VS_OUTPUT和VS_INPUT </span><br />{ <br />    VS_OUTPUT Out = 0; <br />    Out.WorldPos = CaculateWorldPosition( In.LocalPos ); <span class="unnamed1">// 可以直接使用函数</span><br />    Out.Color = In.Color; <br />    Out.Texcoord = In.Texcoord; <br />} </font>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p> </p>
		<font face="宋体">
				<p>这样不仅可以复用代码，还可以使变量名、结构体、函数名的定义统一。 </p>
				<p>而#define不仅仅可以使某些常量具有比较有意义的名称，通过与#ifdef，#ifndef, #else, #endif等结合使用，还可以用来根据一些配置控制编译过程。 </p>
				<p>变量表</p>
				<p>每个FX文件都可以有若干参数变量，通过Effect Framework可以在程序中识别出这些参数的类型、名称和用途，这样就可以将程序中的一些参数输送到Effect中去，从而更加灵活 的控制效果。参数的类型很多，可以是int, float, matrix, texture等等。例如： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">matrix</font>
										</span>
										<font face="宋体"> matWorld;    <span class="unnamed1">//定义一个名为matWorld的矩阵类型参数变量</span><br /><span class="unnamed2">float</span> time;         <span class="unnamed1">//定义一个名为time的浮点类型参数变量 </span><br /><span class="unnamed2">texture</span> texDiffuse; <span class="unnamed1">//定义一个名为texDiffuse的纹理类型参数变量</span></font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>另外，每个变量还有前缀修饰符、Semantic、Annotation等，限于篇幅，在这里不再赘述，具体的介绍请参考DirectX C++帮助文档的DirectX Graphics &gt; Reference &gt; HLSL Shader Reference &gt; Variable Declaration Syntax条目。 </p>
				<p>结构定义</p>
				<p>在FX文件中可以定义结构体，这些结构体一般用于Shader函数的参数和返回值。结构体的定义与C语言方式及其类似，例如： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">struct</font>
										</span>
										<font face="宋体"> VS_OUTPUT <span class="unnamed1">//结构名称 </span><br />{ <br />    <span class="unnamed2">float4</span> Pos : POSITION; <span class="unnamed1">//成员变量。</span><br />    <span class="unnamed2">float4</span> Color : COLOR; <br />   <span class="unnamed2"> float2</span> Texcoord : TEXCOORD0; <br />}; </font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>上面每个成员变量后面的标识符是该变量的semantic，HLSL编译器根据这个标识符来确定该变量的用处。不一定非得是结构体成员变量才有semantic，一般来说Shader的输入输出参数变量都可以有semantic。</p>
				<p>函数</p>
				<p>函数部分是在Effect Framework加入了对Vertex Shader和Pixel Shader的扩充后才加入到FX文件中的。FX文件中的函数的内容可以用汇编形式书写，也可以用HLSL编写。目前一般 都是使用HLSL。用这种语言书写的函数与C语言函数十分类似，可以说，只要学过C语言，书写Shader函数就绰绰有余了。在同一个fx文件中可以定义很多函数，在函数中也可以互 相调用，但是最终Shader程序的入口将在fx文件的Technique部分中指定。对于哪个函数是Vertex shader函数，哪个是Pixel shader函数，也是在Technique中指定的。关于Technique，将在下文中介绍。 例子： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<p>
												<span class="unnamed2">
														<font face="宋体">float4</font>
												</span>
												<font face="宋体"> CalcDiffuseColor( float3 Normal ) <br />{ <br />    <span class="unnamed2">float4</span> Color; ...<span class="unnamed1">//用于实现该函数功能的多条语句 </span><br />    <span class="unnamed2">return</span> Color; <br />} </font>
										</p>
										<p>
												<span class="unnamed2">
														<font face="宋体">VS_OUTPUT</font>
												</span>
												<font face="宋体"> Vertex_Shader( <span class="unnamed2">float4</span> InPos : POSITION, <br />                         <span class="unnamed2">float3</span> InNor : NORMAL, <br />                         <span class="unnamed2">float3</span> InTexcoord : TEXCOORD ) <br />{ <br />    <span class="unnamed2">VS_OUTPUT</span> Out; ...<span class="unnamed1">//用于实现该函数功能的多条语句 </span><br />    Out.Color = CalcDiffuseColor(InNor);<span class="unnamed1"> //函数调用 </span><br />    <span class="unnamed2">return</span> Out; <br />}</font>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>正如上文中所说，Shader程序分为两种：Vertex shader和Pixel shader。在fx函数中就有两种相应的函数：Vertex shader函数和Pixel Shader函数。Vertex shader函数的输入参数是网格模型中的每一个顶点数据，其输出是经过该函数特殊处理的顶点数据；而Pixel Shader函数的输入，则是经过硬件光栅化过程后经过插值的Vertex shader输出结果。至于Pixel shader的输出，一般就是经过该函数计算得到的一个颜色值，即要画到后备缓冲中一个象素上的颜色值。但是这个“颜色值”有时并不一定代表颜色。而且对于支持多RenderTarget的硬件，Pixel shader还可以有多个输出，分别对应不同的RenderTarget。</p>
				<p>technique </p>
				<p>technique是FX文件的主体，是真正设置各种渲染状态的地方，也是指定所使用的Shader程序入口的地方。在理解Technique前首先要理解Pass的概念。Pass是Technique的组成部分 ，一个Pass就代表了绘制时的一遍。通常为了达到一种效果，仅仅绘制一遍网格模型是不够的，需要向framebuffer中多次绘制，并利用设置渲染状态中的BlendState进行Alpha混合。这就是经常提到的“Muli-pass Rendering”。但是随着硬件越来越强大，Shader程序的功能越来越强，目前的趋势是所有的特效材质都将可以用越来越少个Pass来完成。 一个technique中，可以存在一个或多个Pass，但是至少要有一个Pass时该technique才会起实际作用。当存在多个pass时，默认情况下在渲染时将会按照pass在文件中的前后顺序 作为渲染时的前后顺序。technique和Pass中的内容都是以大括号括起来。 </p>
				<p>technique的例子： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">technique</font>
										</span>
										<font face="宋体"> Tec_Shader_1_X <span class="unnamed1">//定义一个名为Tec_Shader_1_X的technique </span><br />{ <br />    pass P0 <span class="unnamed1">//一个名为P0的pass</span><br />    { <br />        VertexShader = compile vs_1_1 Vertex_Shader();<span class="unnamed1"> //设置Vertex Shader程序入口函数 </span><br />        PixelShader = compile ps_1_1 Pixel_Shader();   <span class="unnamed1">//设置Pixel Shader程序入口函数 </span><br />        AlphaBlendEnable= true;                       <span class="unnamed1"> //设置渲染状态        </span><br />        SrcBlend = SrcAlpha;  <br />        DestBlend = InvSrcAlpha; <br />        ... <span class="unnamed1">//其他设置</span><br />    } <br />    pass P1<span class="unnamed1"> //一个名为P1的pass</span><br />    { <br />        ... <br />    } <br />} </font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>
						<strong>ID3DXEffect接口</strong>
				</p>
				<p>上面介绍了很多fx文件相关内容，但是在程序中如何读取和分析这些fx文件呢？在程序中对于读取fx文件，控制渲染状态、设置Shader程序等工作都是通过D3DX库中的ID3DXEffect接口来实现的。ID3DXEffect接口提供了大量的方法，基本上分为几个方面： </p>
				<ul>
						<li>获得Effect参数变量信息 
</li>
						<li>设置Effect参数变量 
</li>
						<li>获得technique信息 
</li>
						<li>设置当前使用的technique 
</li>
						<li>开始和结束使用当前的technique 
</li>
						<li>执行一个pass（渲染绘制遍） </li>
				</ul>
				<p>ID3DXEffect接口的创建： 通过D3DX库中的D3DXCreateEffectFromFile()函数，可以根据一个指定的文件的内容来创建一个ID3DXEffect接口。在该函数执行成功后，所创建的接口中就包含了文件里所对应的 所有内容，包括参数变量表、Shader程序、technique和pass等。 </p>
				<p>ID3DXEffect接口的使用： 通过该接口的方法可以获得FX文件中的所有信息，并设置参数变量和当前的technique。所有的参数变量、technique、pass、shader等等都有自己的名称，根据这些名称，通过调用ID3DXEffect::GetParameterByName()、ID3DXEffect::GetTechniqueByName()和ID3DXEffect::GetPassByName()等方法就可以获得这些对象的句柄，从而在调用 ID3DXEFFECT::Set***()进行设置时使用句柄而不是字符串进行索引来提高效率。</p>
				<p>通过ID3DXEffect::GetParameterDesc()、ID3DXEffect::GetTechniqueDesc()和GetPassDecs等方 法可以获得关于指定对象的所有细节描述信息。 D3DX库中定义了一个D3DXPARAMETER_DESC结构来专门表示参数的类型。通过ID3DXEffect::GetParameterDesc()方法，可以为一个参数获得这样一个结构的数据。 </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">typedef struct</font>
										</span>
										<font face="宋体"> _D3DXPARAMETER_DESC <br />{ <br />    LPCSTR Name;               //参数变量名 <br />    LPCSTR Semantic;           //参数变量的Semantic <br />    D3DXPARAMETER_CLASS Class; //参数变量的类别，可以是标量、矢量、矩阵、对象和结构 <br />    D3DXPARAMETER_TYPE Type;   //参数变量的类型 <br />    UINT Rows;                 //数组型参数的行数 <br />    UINT Columns;              //数组型参数的列数 <br />    UINT Elements;             //数组中的元素个数 <br />    UINT Annotations;          //参数变量的Annotation个数 <br />    UINT StructMembers;        //结构型参数变量成员的个数 <br />    DWORD Flags;               //参数属性 <br />    UINT Bytes;                //参数大小，以字节记 <br />} D3DXPARAMETER_DESC; </font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>其中的参数类型可以有下列几种： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">typedef</font>
										</span>
										<font face="宋体"> enum _D3DXPARAMETER_TYPE <br />{ <br />    D3DXPT_VOID, //Void型指针 <br />    D3DXPT_BOOL, //Bool型 <br />    D3DXPT_INT, //整型 <br />    D3DXPT_FLOAT, //浮点型 <br />    D3DXPT_STRING, //字符串 <br />    D3DXPT_TEXTURE, //纹理 <br />    D3DXPT_TEXTURE1D, //一维纹理 <br />    D3DXPT_TEXTURE2D, //二维纹理 <br />    D3DXPT_TEXTURE3D, //三维纹理 <br />    D3DXPT_TEXTURECUBE, //立方体环境纹理 <br />    D3DXPT_SAMPLER, //纹理取样器 <br />    D3DXPT_SAMPLER1D, //一维纹理取样器 <br />    D3DXPT_SAMPLER2D, //二维纹理取样器 <br />    D3DXPT_SAMPLER3D, //三维纹理取样器 <br />    D3DXPT_SAMPLERCUBE, //立方体环境纹理取样器 <br />    D3DXPT_PIXELSHADER, //Pixel Shader程序 <br />    D3DXPT_VERTEXSHADER, //Vertex Shader程序 <br />    D3DXPT_PIXELFRAGMENT, //Pixel Shader片断 <br />    D3DXPT_VERTEXFRAGMENT, //Vertex Shader片断 <br />    D3DXPT_FORCE_DWORD = 0x7fffffff <br />} D3DXPARAMETER_TYPE;</font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>而真正要让Effect起作用，需要在绘制网格模型前后调用ID3DXEffect::BeginPass()和EndPass方法。在调用这两个函数之前和之后，还需调用ID3DXEffect::Begin()和 ID3DXEffect::End()方法来界定此次Effect设置的起止。大致的形式如下： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<p>
												<font face="宋体">LPD3DXEffect pd3dEffect；<span class="unnamed1"> //ID3DXEffect接口指针 </span><br />... <span class="unnamed1">//初始化该指针 </span><br />... <span class="unnamed1">//程序中的其他部分</span><br />... </font>
										</p>
										<p>
												<font face="宋体">UINT numPasses;<span class="unnamed1"> //用于接受当前所使用的technique中的pass个数 </span><br />pd3dEffect-&gt;Begin( &amp; numPasses, 0 ) <span class="unnamed1">//开始使用当前的technique </span><br /><span class="unnamed2">for</span>( UINT iPass = 0; iPass &lt; numPasses; iPass ++ ) <br />{ <br />    <span class="unnamed1">//遍历所有的pass </span><br />    pd3dEffect-&gt;BeginPass( iPass ); <span class="unnamed1">//调用BeginPass </span><br />    DrawMesh();                     <span class="unnamed1">//然后进行模型的绘制。 </span><br />    pd3dEffect-&gt;EndPass();         <span class="unnamed1"> //调用EndPass </span><br />} <br />pd3dEffect-&gt;End();                 <span class="unnamed1"> //不要忘记结束当前technique </span></font>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>
						<strong>3DS MAX对DirectX 9 Shader Material的支持；Effect数据获取和导出</strong>
				</p>
				<p>在FX文件中的参数，大部分都是用来调整FX文件所指定的Effect的一些细节，例如，一种带有凹凸纹理的效果，可能在FX中就有一个参数控制着凹凸不平的程度。而这些参数是需要由美工来调整的。另外，美工也需要有一个途径能够将FX文件定义的Effect赋予到一个模型或它的一部分上去。同时美工也应该能够实时的预览该Effect在模型上的实际效果。 在以前，实现这些要求只能通过自制效果预览器、模型编辑器或者为DCC软件编写插件来完成。这对于小的工作组和工期较短的项目来说是非常困难的。幸运的是，目前的DCC软件 已经开始为游戏制作提供丰富的支持功能。通过DCC软件自身就可以预览到实时Effect的效果，并调整其参数。在《龙的传说》这个项目中，我们使用3DS MAX 6.0来作为模型建立 工具和Shader预览工具。 </p>
				<p>在3DS MAX 6.0中，新加入了一种材质类型——DirectX 9 Shader材质。这种材质是基于FX文件的。一个FX文件就可以代表一种材质。它可以同MAX中的其他材质一样赋予到模型上 。在MAX的Viewport中可以实时地观察到FX文件中设计的效果。通过为FX中的参数设置特定的Semantic，可以将这些参数与MAX中的场景信息联系起来，如摄像机位置、世界变换矩 阵等。对于控制Effect效果的一些本地参数，可以通过为它们添加特定的Annotation，使MAX能够直接识别这些参数并在用户界面中显示它们的名称和调节控件。对应不同类型的参 数，MAX可以为它们生成不同的调节控件。这样，这种材质就和MAX的其他材质一样，可以更改纹理等等的参数了。 对于美工来说，通过这种用户界面就可以调整该FX材质的参数达到最好的效果。</p>
				<p>但是美工所调整的结果必须要能够保存下来才有意义。这个工作就得由程序员来完成了。要保存3DS MAX中编辑的所有内容，需要为3DS MAX编写文件导出插件，将其内部数据保存在特定格式的文件中。在《龙的传说》这个项目中，我们使用Microsoft DirectX .X 文件。如果从头开始写导出插件，工作量是相当大的；幸运的是，在Microsoft DirectX SDK Extra中提供了一个能够导出模型和3DS MAX标准材质到X文件的插件源代码。通过修改该源代码，可以使它能够导出DirectX 9 Shader材质。在3DS MAX 6 SDK中新增加了一个IDxMaterial接口，通过查询一个IMaterial接口是否为IDxMaterial接口，就可以确定该材质是否为DirectX 9 Shader材质。通过IDxMaterial接口可以获得该材质对应的FX文件的文件名，以及其参数信息。这样就可以将它们导出了。 </p>
				<p>
						<strong>.X文件中对Effect的支持；EffectInstance和EffectDefault</strong>
				</p>
				<p>Microsoft DirectX .X文件的格式是基于模板的、可扩展的文件格式。通过为其制定新的模板，就可以在其中加入新的内容。一般的.X文件中的内容有三维场景的物体层级关系、网格模型几何数据、材质信息、动画信息等。在DirectX的众多X文件模板中有一个模板是专门用来代表Effect的实例的。当一个FX文件的参数被美工加以调整从而具备一些特定的值之后，该 FX文件和这些参数值的集合就形成了一个Effect实例。该模板的定义如下： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">template</font>
												<font face="宋体">
												</font>
										</span>
										<font face="宋体"> EffectInstance <br />{ <br />    &lt; E331F7E4-0559-4cc2-8E99-1CEC1657928F &gt; <br />    STRING EffectFilename; <br />    [ ... ] <br />} </font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>其中， EffectFilename代表了该Effect实例中的FX文件名， [ ... ]代表在其中可以插入任何X文件模板对应的数据。这样就可以代表任何类型的参数值。 </p>
				<p>然而要想让Direct3D程序能够识别[ ... ]中的内容，需要使用X文件模板中的EffectParam系列模板，包括EffectParamDWord, EffectParamFlaots, EffectParamString。通过这三种模板对应的数据，所有类型的Effect参数值都可以被记录在X文件中。 </p>
				<p>最后，EffectInstance数据需要被放置在Material数据中才可以被识别。</p>
				<p>Material模板： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<span class="unnamed2">
												<font face="宋体">template</font>
										</span>
										<font face="宋体"> Material <br />{ <br />    &lt; 3D82AB4D-62DA-11CF-AB39-0020AF71E433 &gt; <br />    ColorRGBA faceColor; <br />    FLOAT power; <br />    ColorRGB specularColor; <br />    ColorRGB emissiveColor; <br />    [...] <br />} </font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>前面的一些颜色模板表明在Material数据中这些颜色信息是必须有的，而最后的[ ... ]则代表可以插入任何X文件模板对应的数据。我们的EffectInstance数据就可以放置在这里 。 </p>
				<p>举一个简单的例子： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<font face="宋体">Material { <span class="unnamed1">//材质 </span><br />    0.500000;0.500000;0.500000;1.000000;;<span class="unnamed1"> //faceColor</span><br />    0.000000;<span class="unnamed1"> //power</span><br />    0.900000;0.900000;0.900000;;<span class="unnamed1"> //specularColor</span><br />    0.000000;0.000000;0.000000;;<span class="unnamed1"> //emissiveColor</span><br />    EffectInstance <br />    {                            <span class="unnamed1">//[...]，这里是EffectInstance</span><br />        "SkyboxNew01.fx";       <span class="unnamed1"> //fx文件的文件名。通过D3DXCreateEffectFromFile()可以</span><br />                                <span class="unnamed1"> //建立该文件对应的D3DXEffect对象 <br />        //下面是EffectInstance中的[...] </span><br />        EffectParamString <br />        {                        <span class="unnamed1">//EffectParamString，即字符串型参数值</span> <br />            "TexCloudTop";      <span class="unnamed1"> //参数的名称，通过该名称调用ID3DXEffect::GetXXXByName()方法</span><br />                                 <span class="unnamed1">//可以得到与fx文件中对应的参数</span>。 <br />            "DarkClouds01.jpg"; <span class="unnamed1"> //参数的值 </span><br />        } <br />        EffectParamString <br />        {                        <span class="unnamed1">//同上 </span><br />            "TexCloudBottom"; <br />            "DarkClouds02.jpg"; <br />        } <br />        EffectParamFloats <br />        {                       <span class="unnamed1">//EffectParamFloats，即浮点数组型参数值</span><br />            "Brightness";       <span class="unnamed1">//参数名称</span><br />            1;                 <span class="unnamed1"> //浮点数组大小</span><br />            0.500000;          <span class="unnamed1"> //值 </span><br />        } <br />    } <br />} </font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>当我们在程序中调用D3DXLoadMeshFromX()或D3DXLoadMeshHierarchyFromX()时，就可以通过其LPD3DXBUFFER *ppEffectInstances参数来接收到网格所用的所有EffectInstance的信息。</p>
				<p>在程序中，对应于X文件中的EffectInstance模板和EffectParam系列模板，有两个结构体用来代表Effect数据： </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<p>
												<span class="unnamed2">
														<font face="宋体">typedef struct</font>
												</span>
												<font face="宋体"> _D3DXEFFECTINSTANCE <br />{ <span class="unnamed1">//EffectInstance</span><br />    LPSTR pEffectFilename; <span class="unnamed1">//fx文件名</span><br />    DWORD NumDefaults; <span class="unnamed1">//参数个数</span><br />    LPD3DXEFFECTDEFAULT pDefaults; <span class="unnamed1">//参数数组</span><br />} D3DXEFFECTINSTANCE, *LPD3DXEFFECTINSTANCE; </font>
										</p>
										<font face="宋体">
												<p>
														<span class="unnamed2">typedef struct </span>_D3DXEFFECTDEFAULT <br />{ <span class="unnamed1">//EffectDefault，即EffectParam </span><br />    LPSTR pParamName;           <span class="unnamed1">//参数名 </span><br />    D3DXEFFECTDEFAULTTYPE Type;<span class="unnamed1"> //参数类型 </span><br />    DWORD NumBytes;             <span class="unnamed1">//参数大小，以字节记 </span><br />    LPVOID pValue;              <span class="unnamed1">//指向参数的值的指针 </span><br />} D3DXEFFECTDEFAULT, *LPD3DXEFFECTDEFAULT; </p>
												<p>需要注意的是，从文件中得到的参数类型只有以下几种： <br /><span class="unnamed2">typedef</span> enum _D3DXEFFECTDEFAULTTYPE <br />{ <br />    D3DXEDT_STRING = 1, <span class="unnamed1">//字符串 </span><br />    D3DXEDT_FLOATS = 2, <span class="unnamed1">//浮点数组 </span><br />    D3DXEDT_DWORD = 3,  <span class="unnamed1">//长整型 </span><br />    D3DXEDT_FORCE_DWORD = 0x7fffffff <span class="unnamed1">//此值不使用 </span><br />} D3DXEFFECTDEFAULTTYPE; </p>
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>在调用了D3DXLoadMeshFromX()和D3DXLoadMeshHierarchyFromX()之后，X文件中的所有Effect数据信息就以上述结构体的形式放置在ppEffectInstances中了。 另外，在从3DS MAX导出参数到X文件时，对于整型和浮点数组型的变量，它们的值将直接导出到X文件中去；而对于所有的纹理贴图文件参数，导出的仅仅是该文件的文件名。所以 在程序中需要再根据这些文件名来建立纹理对象。 在《龙的传说》中，我们使用一个自定义的CEffectInstance类来处理将文件名转换为纹理对象的过程。 一般来说，建立一个完整的CEffectInstance的过程如下： </p>
				<p>根据D3DXEFFECTINSTANCE结构中的pEffectFilename字符串寻找对应的FX文件; <br />根据该FX文件建立ID3DXEffect，并将指针保存在CEffectInstance中; <br />根据D3DXEFFECTINSTANCE结构中的pDefaults设置CEffectInstance中的参数信息： </p>
				<blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
						<p>
								<br />对于长整型和浮点数组，直接拷贝； <br />对于字符串，首先调用ID3DXEffect接口中的GetParameterByName()和GetParameterDesc()方法，得到该参数的类型； 然后进一步判断： </p>
						<blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
								<p>
										<br />如果确实是字符串参数，则直接拷贝 <br />如果是纹理参数，则将该字符串作为纹理文件名建立纹理对象，并将指针保存在CEffectInstance中。 </p>
						</blockquote>
				</blockquote>
				<p>而在最新推出的DirectX 9 SDK Summer 2004中，通过ID3DXEffect::BeginParameterBlock()和ID3DXEffect::EndParameterBlock()方法，我们可以将Effect参数设置过程统一绑定到一个ParamBlock句柄上。这样，在调用ID3DXEffect::Begin()之前就可以直接使用ID3DXEffect::ApplyParameterBlock()方法来设置所有被绑定的参数值。例如： </p>
				<p>[<strong>以前的做法</strong>]： </p>
				<p>在读取参数时：获得每一个参数的句柄 </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<font face="宋体">
												<p>hParam1 = pEffect-&gt;GetParameterByName( NULL, "LightPos" ); <br />hParam2 = pEffect-&gt;GetParameterByName( NULL, "LightColor" ); <br />...</p>
												<p class="unnamed1">在实时绘制时：分别设置每一个参数 </p>
												<p>pEffect-&gt;SetValue( hParam1, value1 ); <br />pEffect-&gt;SetValue( hParam2, value2 ); <br />... <br />pEffect-&gt;Begin(); <br /><span class="unnamed1">// 绘制</span><br />... </p>
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>[<strong>在DirectX 9 SDK Summer 2004中的做法</strong>]： </p>
				<p>在读取参数时：绑定所有参数设置到同一句柄 </p>
		</font>
		<table cellspacing="0" cellpadding="0" width="500" bgcolor="#e0e0e0" border="0">
				<tbody>
						<tr>
								<td>
										<p>
												<font face="宋体">hParam1 = pEffect-&gt;GetParameterByName( NULL, "LightPos" ); <br />hParam2 = pEffect-&gt;GetParameterByName( NULL, "LightColor" ); <br />...<br />pEffect-&gt;BeginParameterBlock();<span class="unnamed1"> // 开始绑定</span><br />pEffect-&gt;SetValue( hParam, value1 ); <br />pEffect-&gt;SetValue( hParam, value2 ); <br />... <br />hParamBlock = pEffect-&gt;EndParameterBlock(); <span class="unnamed1">// 结束绑定，返回句柄 </span></font>
										</p>
										<p class="unnamed1">
												<font face="宋体">在实时绘制时：统一设置绑定值 </font>
										</p>
										<font face="宋体">
												<p>pEffect-&gt;ApplyParameterBlock( hParamBlock ); <br />pEffect-&gt;Begin; <br /><span class="unnamed1">// 绘制 </span><br />... </p>
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<font face="宋体">
				<p> </p>
				<p>这样不仅简化了在读取时对参数的分析过程，而且提高了实际绘制时参数设置过程的效率。 </p>
				<p>
						<strong>总结</strong>
				</p>
				<p>以上就是一些对于在DirectX 9.0中对Effect Framework的使用的简要介绍。总之，使用Effect来替代以前的标准材质是目前实时图形领域的发展趋势。通过Effect Framework，程序员和美工可以为实时三维程序实现多种多样的材质效果和视觉效果。 由于内容实在太多，限于篇幅，本文只是对Effect Framework中相关概念的一个总体概括和简要介绍，所以显得有些晦涩。在以后的文章中，将分批对这个Framework以及在其之上进行工作的流程进行比较详细的介绍。</p>
		</font>
<img src ="http://www.cppblog.com/mybios/aggbug/15464.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-20 16:54 <a href="http://www.cppblog.com/mybios/archive/2006/11/20/15464.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】直接运行内存中的程序</title><link>http://www.cppblog.com/mybios/archive/2006/11/20/15452.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Mon, 20 Nov 2006 03:54:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/20/15452.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15452.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/20/15452.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15452.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15452.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 哈哈，想不到有人居然把这种代码也搞出来了。    Windows的PE加载器在启动程序的时候，会将磁盘上的文件加载到内存，然后做很多操作，如函数导入表重定位，变量预处理之类的。这位仁兄等于是自己写了一个PE加载器。直接将内存中的程序启动。记得以前的“红色代码”病毒也有相同的特性。    直接启动内存中的程序相当于加了一个壳，可以把程序加密保存，运行时解密到内存，然后启动，不过对于增加破解难度还要稍...&nbsp;&nbsp;<a href='http://www.cppblog.com/mybios/archive/2006/11/20/15452.html'>阅读全文</a><img src ="http://www.cppblog.com/mybios/aggbug/15452.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-20 11:54 <a href="http://www.cppblog.com/mybios/archive/2006/11/20/15452.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我到了游戏开发学习迷惘期，该如何是好？</title><link>http://www.cppblog.com/mybios/archive/2006/11/20/15447.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Mon, 20 Nov 2006 01:46:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/20/15447.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15447.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/20/15447.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15447.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15447.html</trackback:ping><description><![CDATA[        学游戏开发前前后后也有两个星期了。<br />        在这两个星期里，收获甚多，从最几本的经典几何知识到高等数学、线性代数都看了一遍，从Direct3D入门到Shader的编写也看了，甚至还学习了LUA脚本的编写和游戏引擎的架构，BSP、八叉树等等算法也看过了解了一下。<br />        学的东西这么多，但是真正能掌握的又有多少？自己无法掂量啊，那么接下去应该做什么好？很多人说应该做一个DEMO，甚至有人说试着自己做一个游戏引擎，还有人说要我试着做一个网游。<br />        确实，现在应该从实际出发了，要做点东西出来才能把学过的知识牢固掌握。但是，我现在觉得很迷惘，不知道做什么好，我打算春节过后去搞游戏开发，请大虾小虾们都给点意见如何？<img src ="http://www.cppblog.com/mybios/aggbug/15447.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-20 09:46 <a href="http://www.cppblog.com/mybios/archive/2006/11/20/15447.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】Ogre的官僚主义批判</title><link>http://www.cppblog.com/mybios/archive/2006/11/19/15418.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 19 Nov 2006 00:40:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/19/15418.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15418.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/19/15418.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15418.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15418.html</trackback:ping><description><![CDATA[
		<div class="postbody">
				<p>Ogre的Manager真是多啊,就象个官僚公司,干事的没几个,一堆的Manager,个个丫还都是Singleton.说自己是Singleton却又public构造函数,让人来new它.在第1次被new的时候,偷偷地将this赋给静态成员ms_Singleton,第2次new它就要assert喊冤了,当然这都是叫Singleton的模板基类的那个构造函数干的(典型的小人行径,见不得光).Manager一多,本来不复杂的事,也变得复杂了.</p>
				<p>1.LogManager<br />a.全局单体LogManager组合Log指针Map集合,控制有多个Log对象,1个Log对象表达对一个Log文件的输入(老一套).<br />b.同时LogManager维护1个当前默认主事的Log对象mDefaultLog,以展现Log对象功能而隐藏自己实际是个Manager的身份(邀功自赏,其心可诛).<br />c.维护一个监控者接口LogListener列表,以履行作为一个Manager受外部监督的职责(实为推清责任).</p>
				<p>2.DynLibManager<br />a.全局单体DynLibManager组合DynLib*指针Map集合,控制多个DynLib对象,1个Dynlib表达对动态库的装载和卸载(典型的官僚主义,人浮于事,这点屁事都要有Manager).</p>
				<p>3.ResourceGroupManager<br />  a.全局单体ResourceGroupManager组合ResourceManager指针Map?Manager的Manager,靠,好大的官)<br />  b.一上任就安插了个亲信Manager,建立个叫General的ResourceManager.</p>
				<p>4.SceneManagerEnumerator<br />  a.连它都是系统单体,一个迭代器,小人得志啊,不说了,它可管着一堆SceneManager,惹不起.<br />  b.一开始就安排了什么事都作不了的SceneManager(基类)作默认SceneManager,大事小事都是它,室内室外一手包.</p>
				<p>5.一堆中层干部,一堆的MaterialManager,MeshManager,ParticleSystemManager,SkeletonManager......,都是Singleton,有的还是ResourceManager的门生,一开始都干了2件事.<br />a.定名分:向ResourceGroupManager注册说自己是某方面的Manager,_registerResourceManager.<br />b.要资源:向ResourceGroupManager要求控制对某种脚本的解析_registerScriptLoader(就是瓜分资源).<br />c.有个OverlayManager,ArchiveManager最牛,手下还有几个工厂给它干活,无非是自己作不了,又推给下级.</p>
				<p>6.一堆插件外劳,开始加载,这些外劳到系统中来当然要注册.</p>
				<p>7.透明实体mTransparentObjects按z序排序,不透明实体按material分组.</p>
				<p>8.我一开始认为Materail是个很聪明的概念,后来才发现上当受骗了,它管理了mTechniques数组,而Techniche管理了mPasses数组(Multipass render),最后实质的内容在Pass类中,Pass类表达了一个渲染的环境.由于这个官僚系统实在太官僚,所以按对象每次渲染是不可接受的(跨部门合作太多,相互扯皮),渲染状态切换频繁,效率极低,透明渲染z序混乱.所以需要按Materail分组和z轴分序,而RenderSystem的最重要方法接受RenderOperation参数.</p>
				<p>9.Pass和RenderOperation是两位最能干的劳动人民,都是受人管制的对象,整个系统的灵魂和核心,Pass封装了最重要的渲染状态(即进行glDrawXXX时管线所处的状态,着色系统),RenderOperation封装了带纹理几何渲染操作(glDrawElements几何系统),两者构成一个完整的渲染.即,先,调用SceneManager的setPass(在其中其仍将调用RenderSystem以设置管线状态),再,调用RenderSystem的_render.</p>
				<p>10.SceneManager的虚方法_findVisibleObjects是场景管理的核心,由它将Renderable分组,分透明和不透明分送入不同的渲染队列,Renderable组合RenderOperation和Pass(但出头的都是Materail),然后SceneManager对之排序,整理,送入RenderSystem渲染.</p>
				<p>11.SceneManager的_renderScene是基本渲染核心,它完成若干任务<br />   a.帧动画驱动_applySceneAnimations <br />   b.场景图更新_updateSceneGraph<br />   c.渲染队列更新,_findVisibleObjects更新主场景,_queueOverlaysForRendering更新上层主界面,_queueSkiesForRendering更新天空盒,最后_renderVisibleObjects.</p>
				<p>12.渲染队列RenderQueue,维护std::map&lt;RenderQueueGroupID, RenderQueueGroup*&gt;对象,以表达其内部的多个方面(世界,前景,背景)的渲染分队列.RenderQueueGroup再往下分std::map&lt;ushort, RenderPriorityGroup*, std::less&lt;ushort&gt; &gt;,以表达其(如前景)内部按ushort优先级维护渲染分队列.RenderPriorityGroup维护一个mTransparentPasses,若干个SolidRenderablePassMap.</p>
		</div>
<img src ="http://www.cppblog.com/mybios/aggbug/15418.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-19 08:40 <a href="http://www.cppblog.com/mybios/archive/2006/11/19/15418.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】使用非2次方幂的图像纹理的问题</title><link>http://www.cppblog.com/mybios/archive/2006/11/19/15417.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 19 Nov 2006 00:26:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/19/15417.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15417.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/19/15417.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15417.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15417.html</trackback:ping><description><![CDATA[
		<div class="postbody">
				<p>图像使用2次方是很讨厌的问题,不在技术难度上,而在技术妥协上.实际上要求美工作出2次方纹理,并且整张图的空间利用率要高,是很难的.<br />当有些策划丢过来奇奇怪怪的尺寸的图像,我都要吐血,当知道2n次方限制后,他们把图像尺寸扩大一下,再丢给我空余大量空白的2n次方纹理,再吐血.</p>
				<p>玻璃渣资源里标准的2n次方人物纹理,图像挤的满满的,每个身体部位纹理还是一个矩形,利用率之高不得不令人佩服,然而这对美工要求是极高的.<br />1024*768的图像是要拆成4*3的256*256图像的,而不是一整大张纹理,因为768不是2的n次方,更不要扩大为1024*1024,加大25%的内存.<br />还有Wow里Loading界面的图像都压成512*512,因为Loading图像模糊一点不要紧,很简单却都是很重要的细节.<br />所以当Wow运行在我Geforce2的显卡上时,我觉的很cool.</p>
				<p>Nvidia的驱动程序也很讨厌,实际Geforce6显卡才支持non power of two texture,Geforce 5200级的显卡,在硬件能力上不足以支持NPOT,但是最新的驱动程序使用了软件模式进行模拟支持,而软件模拟根本毫无实用价值,渲染变得超级缓慢,因为驱动程序每次纹理渲染都会很聪明地把非2次方尺寸图像自动Scale到2次方尺寸,对于一个800*600的图像,驱动程序在这个步骤就吃光了CPU.<br />所以总有些人喊着为什么OpenGL没有软件渲染支持,DX很体贴都有(实际上DX也没有,比如那个所谓的8层纹理),而我认为如果软件渲染能解决问题,那要硬件作什么!不能解决问题的方案我们支持它作什么!</p>
				<p>// OpenGL动态执行2n次方图像限制<br />inline int next_p2(int a)<br />{<br /> int rval=1;<br /> while(rval&lt;a) rval&lt;&lt;=1;<br /> return rval;<br />}</p>
				<p>int nWidthPowerOfTwo = next_p2(tex.nWidth);<br />int nHeightPowerOfTwo = next_p2(tex.nHeight);</p>
				<p>if(tex.nWidth == nWidthPowerOfTwo  &amp;&amp;  tex.nHeight == nHeightPowerOfTwo)<br />{ <br /> glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nWidthPowerOfTwo, nHeightPowerOfTwo, 0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());<br /> tex.fScaleX = tex.fScaleY = 1.0f;<br />} <br />else<br />{ <br /> glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nWidthPowerOfTwo, nHeightPowerOfTwo, 0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, NULL);<br /> glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex.nWidth, tex.nHeight, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());<br /> tex.fScaleX = (float)tex.nWidth / (float)nWidthPowerOfTwo;<br /> tex.fScaleY = (float)tex.nHeight/ (float)nHeightPowerOfTwo;<br />}<br /><br />然而对这个问题,正确的解决方案是事先规划,强制执行,be clever.</p>
		</div>
<img src ="http://www.cppblog.com/mybios/aggbug/15417.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-19 08:26 <a href="http://www.cppblog.com/mybios/archive/2006/11/19/15417.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】数据打包格式</title><link>http://www.cppblog.com/mybios/archive/2006/11/19/15416.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 19 Nov 2006 00:17:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/19/15416.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15416.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/19/15416.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15416.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15416.html</trackback:ping><description><![CDATA[
		<div align="left">　　游戏运行和显示的速度固然重要，不过我认为，在游戏中另外一个速度：游戏装入的速度也同样不可轻视。试想一个游戏，动不动就要装入数据，而且每次装入的时间都令人等到“心越来越慌”的地步，我想恐怕也没有什么人愿意玩下去的。<br /><br />　　选择一个好的打包数据格式，对于编程人员来说，是一件很重要的事情。一般来说，一个游戏的文件个数太多，并不是一件好事情，不光占用的硬盘空间大，而且严重的影响装入速度。不过这样做的优点也很明显：可以很详细的分类，可以大大的减小编程人员的工作量。另外一种做法是，把所有的数据全部放在一个文件里面，这样的做法和上面一种做法的优缺点正好相反，装入速度比较快（因为只要做一次文件打开的操作），但是由于所有数据都放在一起，文件数据的组织比较复杂，要求编程人员花费大量的精力去定位数据的格式和存放位置。因此，选择一个合适的数据打包格式，实际上就是在这两种情况之间选择一个平衡点，使它既不会对游戏的装入速度造成明显的影响，也不会给编程人员带来额外的负担。<br /><br />　　那么，对于一个游戏来说，数据应该怎么组织呢？其实现在有很多好的游戏，参考一下他们的数据文件就会发现这个平衡点其实很好找。现在大多数的游戏，基本上把游戏需要用到的数据分门别类的存放，每一类数据放在一个文件里面。比如说音乐放在一个文件里面，地形图素放在一个文件里面，精灵造型、动画放在一个文件里面，游戏需要用到的图片放在一个文件里面，人物的对话、事件说明放在一个文件里面……那么这些数据在文件里面怎么组织呢？<br /><br />　　还是一句话：分门别类。下面以游戏最基本的地形图素为例，说明数据的组织形式。一般说来，游戏的地图由很多大大小小的“图素”组成的，这些图素分为几层，每一层的图素基本上可以算作一类：比如说地面层可以算作一类，地上层可以算作一类，然后天空层（背景层）可以算作一类，部队、物品可以算作一类。而在地面层里面，又可以进一步的分类，比如说地形有山地，沙漠，草原，森林，河流，海洋……在游戏中，是可以分为场景的，一般的情况下，每个场景所涉及到的地形不会很多，总是以某一类典型地行为主，然后加入少量其他的地形作为点缀。针对这种情况，我们可以把同一类的地形连续的放在文件的某一个位置，这样我们在装入场景的时候，只要在这个位置一次读取这种地形的数据就可以了。一般游戏在制作的过程中都有一个场景生成器，或者叫作拚图器，它的作用就是生成地图——或者说生成场景。这个拚图器在初期的时候读人的数据肯定不是已经打包了的，因为美术还要对地形的基本图素进行某些修改。<br /><br />　　所以我认为，好的数据打包格式应该是基于拚图器的，他把每一种数据分门别类的连续存放在某一个文件之中或者文件的某一个位置，这样能够大大的加快程序读取数据的速度。这样几能够使游戏文件看起来很简洁，也会大大的有利于程序的开发。<br /></div>
<img src ="http://www.cppblog.com/mybios/aggbug/15416.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-19 08:17 <a href="http://www.cppblog.com/mybios/archive/2006/11/19/15416.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】游戏中如何读取压缩包文件</title><link>http://www.cppblog.com/mybios/archive/2006/11/19/15414.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 19 Nov 2006 00:16:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/19/15414.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15414.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/19/15414.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15414.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15414.html</trackback:ping><description><![CDATA[
		<font size="2">　　我们在市场上买了一个游戏，很少会轻易的看到游戏目录里一堆的BMP，PCX资源图片。难道他们不使用BMP之类的文件作为图片资源吗？非也，其实他们把这些资源图片进行了打包、压缩。<br /><br />　　举几个游戏的例子吧，大名鼎鼎westernwood的《红色警戒》的.mix文件就是一种压缩包，里面包含了一堆堆的游戏图片，声音等资源。还有blizzard的《星际争霸》、《暗黑破坏神》、《魔兽系列》的.mpq文件也是一种压缩包，里面包含了各种游戏使用的资源。几乎所有的游戏都用到了压缩包。<br /><br />　　那么为什么要使用这种压缩包呢？原因很多，首先就是压缩，游戏中使用的图片等资源都是极其适合压缩的，这样就减小了游戏的体积。如果把《红色警戒2》的资源全部解开相信会超过3G。其次压缩后文件体积的减小会带来读盘速度的显著提高。通常一个2M的BMP文件可以被压缩到700K以内，读取一个2M的文件和读取一个700K的文件然后再内存中解压的速度对比是可想而知的。最后，将大量的资源文件打包能使得游戏目录清晰，而不是一堆堆的文件夹和文件，这样能减少磁盘空间的浪费，也减少了磁盘碎片。<br /><br />说了那么多压缩包的好处，我们在游戏中到底怎么使用压缩包呢？<br />　　1．我们需要定义我们自己的压缩包文件存储格式。<br />　　2．根据1我们写一个压缩工具来对游戏中的资源进行压缩存储。<br />　　3．根据1我们写一个解压缩的库以便我们游戏中使用。<br />　　4．在游戏的代码中，我们调用这个库，来读取我们包中的文件。<br /><br />　　看到这儿，似乎我们需要做的工作还是很多、很复杂的。要定义一个文件结构，又要写压缩工具、还要写解压库。而我们真正使用确实在最后一步，而且是简单的调用一个库而已。似乎有点得不偿失了。好了，我们现在要找一条捷径来完成我们游戏使用压缩包的问题，对于1和2来说其实很好办，现成的就有很多压缩软件可以生成压缩包，winzip,winrar,winace ……都是非常好的压缩工具，这样我们不用定义压缩包的存储格式，也不用编写压缩工具。不费任何力气就完成了1和2两步。那么第3步又如何呢？文件存储格式不是我们设计的，我们无法知道文件是如何组织、如何压缩的，跟不用说知道如何压缩了。不过上网搜索一下，我们还是能得到一些winzip，winrar格式的解压缩源代码的。不过研究起这些代码来又是件痛苦的事情，更何况还要用在自己的游戏里。<br /><br />　　到这里，我们又遇到了严峻的考验，现在我向大家隆重介绍我们的压轴法宝：</font>
		<a href="http://www.gameres.com/Articles/Program/Other/MDFile.zip">
				<font size="2">MDFile文件系统</font>
		</a>
		<font size="2">。那么，MDFile是个什么东东呢？MDFile是一个可扩展的文件操作库，可以用最最简单的方法实现对任意压缩包格式内文件的读取。那么到此，我们的3和4也都可以实现了。下面我们就以MDFile为例来说以下怎么使用它来读取我们包中的文件。<br /><br />　　首先我们先获取我们需要的</font>
		<a href="http://www.gameres.com/Articles/Program/Other/MDFile.zip">
				<font size="2">MDFile</font>
		</a>
		<font size="2">库，到中国游戏开发技术咨询网上下载</font>
		<a href="http://www.gameres.com/Articles/Program/Other/MDFile.zip">
				<font size="2">MDFile库</font>
		</a>
		<font size="2">，点击本站原创，找到</font>
		<a href="http://www.gameres.com/Articles/Program/Other/MDFile.zip">
				<font size="2">MDFile</font>
		</a>
		<font size="2">并下载下来。<br /><br />　　将库放到你的工程中，并设置好，这里我就不详细说如何设置一个外部的库了，如果不会的话你可以参考相关的书。好了，下面我们就开始我们的代码了，这里以读取test.zip中的一个test.txt文件为例：<br /><br />我们在程序中添加一个LoadFile的函数来载入一个包里的文件。<br /></font>
		<font face="宋体" size="2">bool LoadFile(char* filename,char* packfile)<br />{<br />    BYTE* buf=NULL; // 用来存放读取出的文件的内容<br />    </font>
		<font face="宋体" size="2">CMD_File cmdfile(“ZipExt.dll”); // 我们先生成一个实例<br />    </font>
		<font face="宋体" size="2">cmdfile.Open(“test.zip”,true,true); // 打开test.zip这个压缩包<br />    </font>
		<font face="宋体" size="2">cmdfile.Locate(“test.txt”); // 定位到test.txt文件<br />    </font>
		<font face="宋体" size="2">buf=new BYTE[cmdfile.GetLength()];// 根据test.txt的大小分配内存<br />    </font>
		<font face="宋体" size="2">cmdfile.Read(buf); // 读取文件到我们的内存中<br />    </font>
		<font face="宋体" size="2">// 至此，buf中已经存储了我们需要的test.zip中的test.txt文件的内容了<br />    </font>
		<font face="宋体" size="2">// 是不是很简单呢？<br />}</font>
		<font face="Arial">
				<br />
				<br />
				<font size="2">细心的朋友可能已经注意到了，</font>
		</font>
		<font face="宋体" size="2">CMD_File cmdfile(“ZipExt.dll”);</font>
		<font face="Arial">
				<br />
				<br />
				<font size="2">　　这个初始化是什么意思呢？就是用ZipExt.dll这个扩展库来打开我们的test.zip文件，因为MDFile本身并不支持Zip格式，他支持内部的一种叫epk的压缩包格式，为了让他支持Zip你必须获得ZipExt.dll这个扩展库，同样的如果你需要Rar支持你需要获得RarExt.dll这个扩展库。好在我们刚下载的MDFile包中已经包括了一个ZipExt.dll（在Sample\Sample4\Release中），也好在@J--S Studio在不停的开发MDFile的扩展库，以便我们能够使用更多的压缩包格式。<br /><br />　　需要一提的是：使用这些现成的压缩软件制作文件包虽然简单，但是也有很多问题，例如安全性，有时候我们不想被其他人看到游戏中用到的资源，这时如果我们用的是Zip格式，那就可能轻易的被别人解开并修改了。这时，其实使用MDFile内部的epk格式就比较好，他使用动态加密技术，同时epk格式不被其他压缩软件支持，另外他的其他一些特性都是非常不错的。同时为了支持epk格式，他还提供了一个JSFilePacker程序用来打包需要的文件并存成epk格式。所有的这些都可以在我们下载的MDFile中得到。  (JSFilePacker在tools下)</font>
		</font>
		<font face="Arial">
				<br />
				<font size="2">
						<br />　　<a href="http://www.gameres.com/Articles/Program/Other/MDFile.zip">立即下载MDFile库</a></font>
		</font>
<img src ="http://www.cppblog.com/mybios/aggbug/15414.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-19 08:16 <a href="http://www.cppblog.com/mybios/archive/2006/11/19/15414.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】游戏中的资源打包技术</title><link>http://www.cppblog.com/mybios/archive/2006/11/19/15413.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 19 Nov 2006 00:14:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/19/15413.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15413.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/19/15413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15413.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15413.html</trackback:ping><description><![CDATA[
		<div align="left">打包，很形象的，就是把零散的东西转换为单一的东西。常用的压缩软件就可以说是给文件打包。</div>
		<div align="left">那么，在游戏中为什么要打包？有什么意义么？个人认为，有以下几个意义：</div>
		<div align="left"> 　　1.安全性。</div>
		<div align="left"> 　　如果你的游戏重要数据以文本文件的形式保存在某些文件中，然而你又不希望玩家随意修改这些数据。（比如某些ini文件之类的）把他们和其他2进制文件全部打包在一起的话，这个问题就可以避免了。</div>
		<div align="left"> 　　2.节约磁盘空间。</div>
		<div align="left"> 　　文件太多的话，很容易产生“碎片”。比如一个1个字节的文件，占用空间就高达8Kb。（这个是由windows文件管理系统决定的），如果是很多这样的文件，就可能会发生这种情况：xxxxx个文件，实际大小1xxMb,占用空间3xxMB，（这里只是打一个比方，实际相差不会那么多）。这也许会让人感觉不舒服。</div>
		<div align="left"> 　　3.美观</div>
		<div align="left"> 　　简单的少量文件总比一大堆乱七八糟的东西更让人觉得舒服。</div>
		<div align="left"> 　　4.还没想到...... </div>
		<div align="left">　　下面说说我的设计思路。</div>
		<div align="left"> 　　打包后的文件该是怎样一种结构呢?</div>
		<div align="left"> 　　我想到的有以下几种结构:</div>
		<div align="left"> 　　1. 　　{ 文件标示信息 //判断是否是正确的打包文件 文件的个数,文件索引表大小 各个文件的一个索引表.里面包含每个文件的偏移,大小.类似这种结构:文件名 偏移 大小. 各个文件内容 　　} </div>
		<div align="left">　　2. 　　{ 文件标示信息 第一个文件信息: 文件名长度,文件名,文件长度 第二个文件信息: 文件名长度,文件名,文件长度 ...... 第n个文件信息: 文件名长度,文件名,文件长度 (文件计数) 　　}</div>
		<div align="left"> 　　3. 　　{ 打包成两个文件,一个负责方式1的索引表.另外一个只负责文件内容 　　} 　　这里第1种和第三种方式必须要得到索引表信息后才能填充文件,不如方式2直截了当.所以我在程序设计的时候采用的是方式2.当然方式1,3也有他们的好处,比如查找文件比2要方便一点. </div>
		<div align="left">　　需要压缩么?</div>
		<div align="left"> 　　解压缩是要花费时间的.你可以从速度和容量方面做一个折中.我在设计的时候,没有考虑压缩. 　　怎样在游戏中从已经打包了的文件读取需要的文件?</div>
		<div align="left"> 　　最简单的方法,得到需要的文件信息,从打包文件中读取出来,放到一个临时文件中.读取这个临时文件即可, </div>
		<div align="left">　　游戏结束之前,从程序中删除这个临时文件即可.这里就带来了一个问题:性能.每次都要进行I/O操作.如果每个文件都不是非常大的文件的话,这个办法还是可以的.或则你需要高性能的东西,那就只有一个办法:把你的程序中所有对文件操作都改到对内存进行操作.这样只要把需要的文件从打包文件中读取到内存中即可.或者还有另外的方法,直接在打包文件中读取(这个我还不知道怎么实现,盼望高手赐教之) 　　在制作游戏过程中,当然不用打包,只是在正式版发布后,把所有已经做好了的资源(比如图片,一些数据文件,脚本文件等)打包再一起就可以了.类似如下结构</div>
		<div align="left"> 　　//假设这个是一个打包类的一个成员函数, </div>
		<div align="left">BOOL CPackFile::GetPackFileFromPacker(char*szFindFile,char*szTempFile) { #ifndef PACKER strcpy(y,x); return true; #else </div>
		<div align="left">　　在打包文件中查找szFindFile,如果找到,创建文件名为szTempFile的文件,返回true </div>
		<div align="left">　　否则,返回false #endif } </div>
		<div align="left">　　程序中应该有如下片断 char szFile[256]; CPackFile packer; packer.OpenPackFile("somefile.pak"); ................ if(packer.GetPackFileFromPacker("resource.bmp",szFile)) do something.... 　　</div>
		<div align="left">下面看看我的具体程序吧!</div>
		<div align="left"> 　　<a href="http://www.gamego.cn/download/kaifajishu/packer.rar">程序下载</a> 　　</div>
		<div align="left">欢迎和我交流 　　E-mail:game-diy@163.com 　　OICQ:30784290(难得糊涂) 　　<a href="http://gameplusplus.yeah.net/" target="_blank">http://GamePlusPlus.yeah.net</a></div>
		<br />
		<br />
<img src ="http://www.cppblog.com/mybios/aggbug/15413.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-19 08:14 <a href="http://www.cppblog.com/mybios/archive/2006/11/19/15413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】PNG文件结构分析</title><link>http://www.cppblog.com/mybios/archive/2006/11/19/15411.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 19 Nov 2006 00:11:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/19/15411.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15411.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/19/15411.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15411.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15411.html</trackback:ping><description><![CDATA[
		<span class="content">
				<strong>前言</strong>
				<p>PNG是20世纪90年代中期开始开发的图像文件存储格式，其目的是企图替代GIF和TIFF文件格式，同时增加一些GIF文件格式所不具备的特性。流式网络图形格式(Portable Network Graphic Format，PNG)名称来源于非官方的“PNG's Not GIF”，是一种位图文件(bitmap file)存储格式，读成“ping”。PNG用来存储灰度图像时，灰度图像的深度可多到16位，存储彩色图像时，彩色图像的深度可多到48位，并且还可存储多到16位的α通道数据。PNG使用从LZ77派生的无损数据压缩算法。</p>
				<p>
						<strong>PNG数据块（Chunk）</strong>
				</p>
				<p>PNG定义了两种类型的数据块，一种是称为关键数据块(critical chunk)，这是标准的数据块，另一种叫做辅助数据块(ancillary chunks)，这是可选的数据块。关键数据块定义了4个标准数据块，每个PNG文件都必须包含它们，PNG读写软件也都必须要支持这些数据块。虽然PNG文件规范没有要求PNG编译码器对可选数据块进行编码和译码，但规范提倡支持可选数据块。</p>
				<p>下表就是PNG中数据块的类别，其中，关键数据块部分我们使用深色背景加以区分。</p>
				<table class="text" cellspacing="1" cellpadding="3" align="center" bgcolor="#000000" border="0">
						<tbody>
								<tr bgcolor="#ffffff">
										<td colspan="5">
												<div align="center">
														<strong>PNG文件格式中的数据块</strong>
												</div>
										</td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>
												<div align="center">
														<b>数据块符号</b>
												</div>
										</td>
										<td>
												<div align="center">
														<b>数据块名称 </b>
												</div>
										</td>
										<td>
												<div align="center">
														<b>多数据块 </b>
												</div>
										</td>
										<td>
												<div align="center">
														<b>可选否 </b>
												</div>
										</td>
										<td>
												<div align="center">
														<b>位置限制 </b>
												</div>
										</td>
								</tr>
								<tr bgcolor="#cccccc">
										<td>IHDR </td>
										<td>文件头数据块 </td>
										<td>否 </td>
										<td>否 </td>
										<td>第一块 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>cHRM </td>
										<td>基色和白色点数据块 </td>
										<td>否 </td>
										<td>是</td>
										<td>在PLTE和IDAT之前</td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>gAMA </td>
										<td>图像γ数据块 </td>
										<td>否 </td>
										<td>是</td>
										<td>在PLTE和IDAT之前 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>sBIT </td>
										<td>样本有效位数据块 </td>
										<td>否 </td>
										<td>是</td>
										<td>在PLTE和IDAT之前 </td>
								</tr>
								<tr bgcolor="#cccccc">
										<td>PLTE </td>
										<td>调色板数据块 </td>
										<td>否 </td>
										<td>是</td>
										<td>在IDAT之前 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>bKGD </td>
										<td>背景颜色数据块 </td>
										<td>否 </td>
										<td>是</td>
										<td>在PLTE之后IDAT之前 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>hIST </td>
										<td>图像直方图数据块 </td>
										<td>否 </td>
										<td>是</td>
										<td>在PLTE之后IDAT之前 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>tRNS </td>
										<td>图像透明数据块 </td>
										<td>否 </td>
										<td>是</td>
										<td>在PLTE之后IDAT之前 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>oFFs </td>
										<td>(专用公共数据块) </td>
										<td>否 </td>
										<td>是</td>
										<td>在IDAT之前 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>pHYs </td>
										<td>物理像素尺寸数据块 </td>
										<td>否 </td>
										<td>是</td>
										<td>在IDAT之前 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>sCAL </td>
										<td>(专用公共数据块) </td>
										<td>否 </td>
										<td>是</td>
										<td>在IDAT之前 </td>
								</tr>
								<tr bgcolor="#cccccc">
										<td>IDAT </td>
										<td>图像数据块 </td>
										<td>是</td>
										<td>否 </td>
										<td>与其他IDAT连续</td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>tIME </td>
										<td>图像最后修改时间数据块 </td>
										<td>否 </td>
										<td>是</td>
										<td>无限制 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>tEXt </td>
										<td>文本信息数据块 </td>
										<td>是</td>
										<td>是</td>
										<td>无限制 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>zTXt </td>
										<td>压缩文本数据块 </td>
										<td>是</td>
										<td>是</td>
										<td>无限制 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>fRAc </td>
										<td>(专用公共数据块) </td>
										<td>是</td>
										<td>是</td>
										<td>无限制 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>gIFg </td>
										<td>(专用公共数据块) </td>
										<td>是</td>
										<td>是</td>
										<td>无限制 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>gIFt </td>
										<td>(专用公共数据块) </td>
										<td>是</td>
										<td>是</td>
										<td class="text">无限制 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>gIFx </td>
										<td>(专用公共数据块) </td>
										<td>是</td>
										<td>是</td>
										<td>无限制 </td>
								</tr>
								<tr bgcolor="#cccccc">
										<td>IEND </td>
										<td>图像结束数据 </td>
										<td>否 </td>
										<td>否 </td>
										<td>最后一个数据块 </td>
								</tr>
						</tbody>
				</table>
				<p>为了简单起见，我们假设在我们使用的PNG文件中，这4个数据块按以上先后顺序进行存储，并且都只出现一次。</p>
				<p>
						<strong>数据块结构</strong>
				</p>
				<p>PNG文件中，每个数据块由4个部分组成，如下：</p>
				<table class="text" cellspacing="1" cellpadding="3" align="center" bgcolor="#000000" border="0">
						<tbody>
								<tr bgcolor="#ffffff">
										<td>
												<b>名称 </b>
										</td>
										<td>
												<b>字节数 </b>
										</td>
										<td>
												<b>说明 </b>
										</td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>Length (长度) </td>
										<td>4字节 </td>
										<td>指定数据块中数据域的长度，其长度不超过(2<sup>31</sup>－1)字节 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>Chunk Type Code (数据块类型码) </td>
										<td>4字节 </td>
										<td>数据块类型码由ASCII字母(A-Z和a-z)组成 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>Chunk Data (数据块数据) </td>
										<td>可变长度 </td>
										<td>存储按照Chunk Type Code指定的数据 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>CRC (循环冗余检测) </td>
										<td>4字节 </td>
										<td>存储用来检测是否有错误的循环冗余码 </td>
								</tr>
						</tbody>
				</table>
				<p>CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。CRC具体算法定义在ISO 3309和ITU-T V.42中，其值按下面的CRC码生成多项式进行计算：</p>
				<p>x<sup>32</sup>+x<sup>26</sup>+x<sup>23</sup>+x<sup>22</sup>+x<sup>16</sup>+x<sup>12</sup>+x<sup>11</sup>+x<sup>10</sup>+x<sup>8</sup>+x<sup>7</sup>+x<sup>5</sup>+x<sup>4</sup>+x<sup>2</sup>+x+1</p>
				<p>下面，我们依次来了解一下各个关键数据块的结构吧。</p>
				<p>
						<strong>IHDR</strong>
				</p>
				<p>文件头数据块IHDR(header chunk)：它包含有PNG文件中存储的图像数据的基本信息，并要作为第一个数据块出现在PNG数据流中，而且一个PNG数据流中只能有一个文件头数据块。</p>
				<p>文件头数据块由13字节组成，它的格式如下表所示。</p>
				<table class="text" cellspacing="1" cellpadding="3" align="center" bgcolor="#000000" border="0">
						<tbody>
								<tr bgcolor="#ffffff">
										<td>
												<div align="center">
														<b>域的名称 </b>
												</div>
										</td>
										<td>
												<div align="center">
														<b>字节数 </b>
												</div>
										</td>
										<td>
												<div align="center">
														<b>说明 </b>
												</div>
										</td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>Width </td>
										<td>4 bytes </td>
										<td>图像宽度，以像素为单位 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>Height </td>
										<td>4 bytes </td>
										<td>图像高度，以像素为单位 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>Bit depth </td>
										<td>1 byte </td>
										<td>图像深度： <br />索引彩色图像：1，2，4或8 <br />灰度图像：1，2，4，8或16 <br />真彩色图像：8或16 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>ColorType </td>
										<td>1 byte </td>
										<td>颜色类型：<br />0：灰度图像, 1，2，4，8或16 <br />2：真彩色图像，8或16 <br />3：索引彩色图像，1，2，4或8 <br />4：带α通道数据的灰度图像，8或16 <br />6：带α通道数据的真彩色图像，8或16 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>Compression method </td>
										<td>1 byte </td>
										<td>压缩方法(LZ77派生算法) </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>Filter method </td>
										<td>1 byte </td>
										<td>滤波器方法 </td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>Interlace method </td>
										<td>1 byte </td>
										<td>隔行扫描方法：<br />0：非隔行扫描 <br />1： Adam7(由Adam M. Costello开发的7遍隔行扫描方法) </td>
								</tr>
						</tbody>
				</table>
				<p>由于我们研究的是手机上的PNG，因此，首先我们看看MIDP1.0对所使用PNG图片的要求吧：</p>
				<ul>
						<li>在MIDP1.0中，我们只可以使用1.0版本的PNG图片。并且，所以的PNG关键数据块都有特别要求：<br />IHDR 
</li>
						<li>文件大小：MIDP支持任意大小的PNG图片，然而，实际上，如果一个图片过大，会由于内存耗尽而无法读取。 
</li>
						<li>颜色类型：所有颜色类型都有被支持，虽然这些颜色的显示依赖于实际设备的显示能力。同时，MIDP也能支持alpha通道，但是，所有的alpha通道信息都会被忽略并且当作不透明的颜色对待。 
</li>
						<li>色深：所有的色深都能被支持。 
</li>
						<li>压缩方法：仅支持压缩方式0（deflate压缩方式），这和jar文件的压缩方式完全相同，所以，PNG图片数据的解压和jar文件的解压可以使用相同的代码。（其实这也就是为什么J2ME能很好的支持PNG图像的原因：）） 
</li>
						<li>滤波器方法：尽管在PNG的白皮书中仅定义了方法0，然而所有的5种方法都被支持！ 
</li>
						<li>隔行扫描：虽然MIDP支持0、1两种方式，然而，当使用隔行扫描时，MIDP却不会真正的使用隔行扫描方式来显示。 
</li>
						<li>PLTE chunk：支持 
</li>
						<li>IDAT chunk：图像信息必须使用5种过滤方式中的方式0 (None, Sub, Up, Average, Paeth) 
</li>
						<li>IEND chunk：当IEND数据块被找到时，这个PNG图像才认为是合法的PNG图像。 
</li>
						<li>可选数据块：MIDP可以支持下列辅助数据块，然而，这却不是必须的。 
<blockquote><p>bKGD cHRM gAMA hIST iCCP iTXt pHYs<br />sBIT sPLT sRGB tEXt tIME tRNS zTXt</p></blockquote></li>
				</ul>
				<p>关于更多的信息，可以参考<a href="http://www.w3.org/TR/REC-png.html" target="_blank"><font color="#000000"><a href="http://www.w3.org/TR/REC-png.html" target="_blank">http://www.w3.org/TR/REC-png.html</a></font></a></p>
				<p>
						<strong>PLTE</strong>
				</p>
				<p>调色板数据块PLTE(palette chunk)包含有与索引彩色图像(indexed-color image)相关的彩色变换数据，它仅与索引彩色图像有关，而且要放在图像数据块(image data chunk)之前。</p>
				<p>PLTE数据块是定义图像的调色板信息，PLTE可以包含1~256个调色板信息，每一个调色板信息由3个字节组成：</p>
				<table class="text" cellspacing="1" cellpadding="3" align="center" bgcolor="#000000" border="0">
						<tbody>
								<tr bgcolor="#ffffff">
										<td>
												<p align="center">
														<strong>颜色</strong>
												</p>
										</td>
										<td>
												<p align="center">
														<strong>字节</strong>
												</p>
										</td>
										<td>
												<p align="center">
														<strong>意义</strong>
												</p>
										</td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>
												<p>Red</p>
										</td>
										<td>
												<p>1 byte</p>
										</td>
										<td>
												<p>0 = 黑色, 255 = 红</p>
										</td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>
												<p>Green</p>
										</td>
										<td>
												<p>1 byte</p>
										</td>
										<td>
												<p>0 = 黑色, 255 = 绿色</p>
										</td>
								</tr>
								<tr bgcolor="#ffffff">
										<td>
												<p>Blue</p>
										</td>
										<td>
												<p>1 byte</p>
										</td>
										<td>
												<p>0 = 黑色, 255 = 蓝色 </p>
										</td>
								</tr>
						</tbody>
				</table>
				<p>因此，调色板的长度应该是3的倍数，否则，这将是一个非法的调色板。</p>
				<p>对于索引图像，调色板信息是必须的，调色板的颜色索引从0开始编号，然后是1、2……，调色板的颜色数不能超过色深中规定的颜色数（如图像色深为4的时候，调色板中的颜色数不可以超过2^4=16），否则，这将导致PNG图像不合法。</p>
				<p>真彩色图像和带α通道数据的真彩色图像也可以有调色板数据块，目的是便于非真彩色显示程序用它来量化图像数据，从而显示该图像。</p>
				<p>
						<strong>IDAT</strong>
				</p>
				<p>图像数据块IDAT(image data chunk)：它存储实际的数据，在数据流中可包含多个连续顺序的图像数据块。</p>
				<p>IDAT存放着图像真正的数据信息，因此，如果能够了解IDAT的结构，我们就可以很方便的生成PNG图像。</p>
				<p>
						<strong>IEND</strong>
				</p>
				<p>图像结束数据IEND(image trailer chunk)：它用来标记PNG文件或者数据流已经结束，并且必须要放在文件的尾部。</p>
				<p>如果我们仔细观察PNG文件，我们会发现，文件的结尾12个字符看起来总应该是这样的：</p>
				<p>00 00 00 00 49 45 4E 44 AE 42 60 82</p>
				<p>不难明白，由于数据块结构的定义，IEND数据块的长度总是0（00 00 00 00，除非人为加入信息），数据标识总是IEND（49 45 4E 44），因此，CRC码也总是AE 42 60 82。</p>
				<p>
						<strong>实例研究PNG</strong>
				</p>
				<p>以下是由Fireworks生成的一幅图像，图像大小为8*8，为了方便大家观看，我们将图像放大：</p>
				<p>
						<img hspace="0" src="http://svcdn.blogbus.com/files/1114048547.jpg" align="baseline" border="0" />
				</p>
				<p>使用UltraEdit32打开该文件，如下：<br /><strong>00000000~00000007：</strong></p>
				<p>
						<strong>
						</strong>
				</p>
				<p>
						<img hspace="0" src="http://svcdn.blogbus.com/files/1114048623.jpg" align="baseline" border="0" />
				</p>
				<p>可以看到，选中的头8个字节即为PNG文件的标识。</p>
				<p>接下来的地方就是IHDR数据块了：</p>
				<p>
						<strong>00000008~00000020：</strong>
				</p>
				<p>
						<img hspace="0" src="http://svcdn.blogbus.com/files/1114048677.jpg" align="baseline" border="0" />
				</p>
				<ul>
						<li>00 00 00 0D 说明IHDR头块长为13 
</li>
						<li>49 48 44 52 IHDR标识 
</li>
						<li>00 00 00 08 图像的宽，8像素 
</li>
						<li>00 00 00 08 图像的高，8像素 
</li>
						<li>04 色深，2^4=16，即这是一个16色的图像（也有可能颜色数不超过16，当然，如果颜色数不超过8，用03表示更合适） 
</li>
						<li>03 颜色类型，索引图像 
</li>
						<li>00 PNG Spec规定此处总为0（非0值为将来使用更好的压缩方法预留），表示使压缩方法(LZ77派生算法) 
</li>
						<li>00 同上 
</li>
						<li>00 非隔行扫描 
</li>
						<li>36 21 A3 B8 CRC校验</li>
				</ul>
				<p>
						<strong>00000021~0000002F：</strong>
				</p>
				<p>
						<img hspace="0" src="http://svcdn.blogbus.com/files/1114048728.jpg" align="baseline" border="0" />
				</p>
				<p>可选数据块sBIT，颜色采样率，RGB都是256（2^8=256）</p>
				<p>
						<strong>00000030~00000062：</strong>
				</p>
				<p>
						<img hspace="0" src="http://svcdn.blogbus.com/files/1114048773.jpg" align="baseline" border="0" />
				</p>
				<p>这里是调色板信息</p>
				<ul>
						<li>00 00 00 27 说明调色板数据长为39字节，既13个颜色数 
</li>
						<li>50 4C 54 45 PLTE标识 
</li>
						<li>FF FF 00 颜色0 
</li>
						<li>FF ED 00 颜色1 
</li>
						<li>…… …… 
</li>
						<li>09 00 B2 最后一个颜色，12 
</li>
						<li>5F F5 BB DD CRC校验</li>
				</ul>
				<p>
						<strong>00000063~000000C5：</strong>
				</p>
				<p>
						<img hspace="0" src="http://svcdn.blogbus.com/files/1114048823.jpg" align="baseline" border="0" />
				</p>
				<p>这部分包含了pHYs、tExt两种类型的数据块共3块，由于并不太重要，因此也不再详细描述了。<br /><br /><strong>000000C0~000000F8：</strong></p>
				<p>
						<img hspace="0" src="http://svcdn.blogbus.com/files/1114048862.jpg" align="baseline" border="0" />
				</p>
				<p>以上选中部分是IDAT数据块</p>
				<ul>
						<li>00 00 00 27 数据长为39字节 
</li>
						<li>49 44 41 54 IDAT标识 
</li>
						<li>78 9C…… 压缩的数据，LZ77派生压缩方法 
</li>
						<li>DA 12 06 A5 CRC校验</li>
				</ul>
				<p>IDAT中压缩数据部分在后面会有详细的介绍。</p>
				<p>
						<strong>000000F9~00000104：</strong>
				</p>
				<p>
						<img hspace="0" src="http://svcdn.blogbus.com/files/1114048896.jpg" align="baseline" border="0" />
				</p>
				<p>IEND数据块，这部分正如上所说，通常都应该是</p>
				<p>00 00 00 00 49 45 4E 44 AE 42 60 82</p>
				<p>至此，我们已经能够从一个PNG文件中识别出各个数据块了。由于PNG中规定除关键数据块外，其它的辅助数据块都为可选部分，因此，有了这个标准后，我们可以通过删除所有的辅助数据块来减少PNG文件的大小。（当然，需要注意的是，PNG格式可以保存图像中的层、文字等信息，一旦删除了这些辅助数据块后，图像将失去原来的可编辑性。）</p>
				<p>
						<img hspace="0" src="http://svcdn.blogbus.com/files/1114048924.jpg" align="baseline" border="0" />
				</p>
				<p>删除了辅助数据块后的PNG文件，现在文件大小为147字节，原文件大小为261字节，文件大小减少后，并不影响图像的内容。</p>
				<p>如上说过，IDAT数据块是使用了LZ77压缩算法生成的，由于受限于手机处理器的能力，因此，如果我们在生成IDAT数据块时仍然使用LZ77压缩算法，将会使效率大打折扣，因此，为了效率，只能使用无压缩的LZ77算法，关于LZ77算法的具体实现，此文不打算深究，如果你对LZ77算法的JAVA实现有兴趣，可以参考以下两个站点：</p>
				<ul>
						<li>
								<a href="http://jazzlib.sourceforge.net/" target="_blank">
										<font color="#000000">
												<a href="http://jazzlib.sourceforge.net/" target="_blank">http://jazzlib.sourceforge.net/</a>
										</font>
								</a>
						</li>
						<li>
								<a href="http://www.jcraft.com/jzlib/index.html" target="_blank">
										<font color="#000000">
												<a href="http://www.jcraft.com/jzlib/index.html" target="_blank">http://www.jcraft.com/jzlib/index.html</a>
										</font>
								</a>
						</li>
				</ul>
				<p>
						<strong>参考资料：</strong>
				</p>
				<p>PNG文件格式白皮书：<a href="http://www.w3.org/TR/REC-png.html" target="_blank"><font color="#000000"><a href="http://www.w3.org/TR/REC-png.html" target="_blank">http://www.w3.org/TR/REC-png.html</a></font></a><br />为数不多的中文PNG格式说明：<a href="http://dev.gameres.com/Program/Visual/Other/PNGFormat.htm" target="_blank"><font color="#000000"><a href="http://dev.gameres.com/Program/Visual/Other/PNGFormat.htm" target="_blank">http://dev.gameres.com/Program/Visual/Other/PNGFormat.htm</a></font></a><br />RFC-1950(ZLIB Compressed Data Format Specification)：<a href="ftp://ds.internic.net/rfc/rfc1950.txt" target="_blank"><font color="#000000"><a href="ftp://ds.internic.net/rfc/rfc1950.txt" target="_blank">ftp://ds.internic.net/rfc/rfc1950.txt</a></font></a><br />RFC-1950(DEFLATE Compressed Data Format Specification)：<a href="ftp://ds.internic.net/rfc/rfc1951.txt" target="_blank"><font color="#000000"><a href="ftp://ds.internic.net/rfc/rfc1951.txt" target="_blank">ftp://ds.internic.net/rfc/rfc1951.txt</a></font></a><br />LZ77算法的JAVA实现：<a href="http://jazzlib.sourceforge.net/" target="_blank"><font color="#000000"><a href="http://jazzlib.sourceforge.net/" target="_blank">http://jazzlib.sourceforge.net/</a></font></a><br />LZ77算法的JAVA实现，包括J2ME版本：<a href="http://www.jcraft.com/jzlib/index.html" target="_blank"><font color="#000000"><a href="http://www.jcraft.com/jzlib/index.html" target="_blank">http://www.jcraft.com/jzlib/index.html</a></font></a></p>
		</span>
<img src ="http://www.cppblog.com/mybios/aggbug/15411.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-19 08:11 <a href="http://www.cppblog.com/mybios/archive/2006/11/19/15411.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】游戏中的资源打包</title><link>http://www.cppblog.com/mybios/archive/2006/11/19/15412.html</link><dc:creator>李锦俊</dc:creator><author>李锦俊</author><pubDate>Sun, 19 Nov 2006 00:11:00 GMT</pubDate><guid>http://www.cppblog.com/mybios/archive/2006/11/19/15412.html</guid><wfw:comment>http://www.cppblog.com/mybios/comments/15412.html</wfw:comment><comments>http://www.cppblog.com/mybios/archive/2006/11/19/15412.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mybios/comments/commentRss/15412.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mybios/services/trackbacks/15412.html</trackback:ping><description><![CDATA[
		<span class="content">　　本人正在准备做一个游戏引擎（你就当我准备产生垃圾好了~呵呵！），准备写文档，就顺便把这篇文章写出来了，初次发稿，写得可能不是很好，请多多包涵~谢谢！~~<br /><br />　　资源打包就是将一些零碎资源（如图片，音乐文件）。打包的好处有哪些呢？<br /><br />　　1、减少碎片。因为WINDOWS的文件管理系统的原因，将这些资源按原样放在硬盘里，会产生“碎片”。比如1个字节的文件，占用的空间就高达8KB。这样，资源可以说“膨胀”了。<br /><br />　　2、安全。将这些数据集合起来打包的话，就可以隐藏这些文件，让用户不能修改（如果某位高手破解了文件结构并提取出来了的话你当我没说~）<br /><br />　　我想到的只有这些，如果哪位大虾认为还可以补充的，请联系我：）<br /><br />　　好了！我们现在来构造一个结构来储存这些文件吧！在这里因为我准备写的是只储存图形的游戏引擎，所以我想到的只是图片的储存，其他文件的储存，这里没有涉及。<br />　　<br />　　我们先构造一个文件头，这个文件头描述了一些基本的信息，有长度，文件版本，压缩类型，还有储存的图片总数。现在详细的说一下，长度就不用说了吧，文件头的大小。文件版本是给打包工具看的东东，游戏引擎里也可以使用，根据版本来用不同的方法打开文件（不同的结构，或者其他的）。压缩类型是一个以备扩展用的东东，根据标识来使用不同的压缩方法解压缩，在这里可以选一个速度和容量折中的压缩方法。图片总数说的不是单个图片的总数，而是静态图片和动态图片的总数，静态图片可以理解成一个图片，动态图片就是一系列静态图片的集合，这个在后面会说到。讲一个文件头就说了这么多话。我讲得是太详细了还是太水了？<br /><br />　　struct FileHeader<br /><br />　　{<br /><br />　　unsigned long headsize; //文件头长度<br /><br />　　int Version; //文件版本<br /><br />　　int Compress; //压缩类型<br /><br />　　int AllNumber; //图片总数<br /><br />　　}<br /><br />　　然后紧跟一个结构数组，这个结构描述了每个图片的起始偏移量，这个偏移量是以文件头的长度+索引结构数组的长度+1为基址的，还描述了图片的帧数，为1则表示为静态图片，大于1则表示动态图片（动态图片很有用处，比如海面，被风吹动的树，这些就可以很容易的表示出来）<br /><br />　　struct PicIndex<br /><br />　　{<br /><br />　　int offset; //图片偏移量<br /><br />　　unsigned long PicSize //图片长度（如果是多帧的则代表这个图片集的总共长度）<br /><br />　　int nFrameNumber; //图片帧数<br /><br />　　unsigned long nFrameSize[nFrameNumber]; //每一帧的偏移量，这里的偏移量就是基址+offset+这一个偏移量。。#··%…！天书？<br /><br />　　//当然上面这个数组定义编译时不能这样写<br /><br />　　}<br /><br />　　PicIndex结构是一个数组，它的下标为AllNumber个。例如：<br /><br />　　PicIndex Index[AllNumber];<br /><br />　　然后剩下的就是一些数据了，这些数据已经被压缩了，压缩方式通过文件头的AllNumber变量来获得。<br /><br />　　<br /><br />　　下标n其实就是AllNumber，这里为了省空间：）<br /><br />　　值得注意的是后面的压缩数据不是整块压缩的，而是单个图片的压缩，然后放在一起而已，我这样做是为了读取方便，就不用读取一个数据还要把整个文件再解压缩一道了，这样压缩率可能也会降低，不知道是否还有更好的办法，如果有，请联系我~谢谢！<br /><br />　　除了我写的这种结构方式来储存文件以外，还有其他的实现方案，但是我觉得这个好一点。<br /><br />　　代码我刚写一半，还不完全，所以这里就不放上来了。<br /><br />　　我的QQ：393277421<br /><br />　　我再说一句最重要的话：有空常联系~~~~~~~~<br /></span>
<img src ="http://www.cppblog.com/mybios/aggbug/15412.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mybios/" target="_blank">李锦俊</a> 2006-11-19 08:11 <a href="http://www.cppblog.com/mybios/archive/2006/11/19/15412.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>