﻿<?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++博客-Heath's Blog</title><link>http://www.cppblog.com/heath/</link><description>There is no end, it is just the beginning! - A Game Developer's Notes</description><language>zh-cn</language><lastBuildDate>Wed, 22 Apr 2026 22:38:27 GMT</lastBuildDate><pubDate>Wed, 22 Apr 2026 22:38:27 GMT</pubDate><ttl>60</ttl><item><title>解决在Unity中封装Debug.Log后代码行定位问题</title><link>http://www.cppblog.com/heath/archive/2016/06/21/213777.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 21 Jun 2016 02:53:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2016/06/21/213777.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/213777.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2016/06/21/213777.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/213777.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/213777.html</trackback:ping><description><![CDATA[<p>众所周知，代码中使用Debug.Log*输出的日志在Unity的ConsoleWindow中可以双击定位到对应的代码行，然而将Debug.Log*封装到自己的日志类中后，定位就失去意义了。原因很简单，Unity只会处理StackFrame的栈顶信息，它们保存在LogEntry中，栈顶的方法对应的脚本文件会以其instanceID来保存，其他StackTrace信息则以字符串结果存储，最终在双击ConsoleWindow中的ListView条目时通过指定了OnOpenAssetAttribute的callback来打开代码编辑器。其中，OnOpenAssetAttribute参数用于处理存在多个Callback时的优先级问题。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/78e5bc01e0b8_776C/image_2.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/78e5bc01e0b8_776C/image_thumb.png" width="526" height="63"></a></p> <p>通过阅读ConsoleWindow代码，想到了一个解决思路：自己实现OnOpenAsset，通过获取ConsoleWindow中的ListView得到当前选中的row，然后在LogEntries中取得该行对应的LogEntry，其中的condition字段保存了StackTrace字符串，最后过滤掉包装的日志类后拿到脚本文件名和代码行，用OpenFileAtLineExternal直接打开。在实现过程中发现，完全没有必要拿到LogEntry，因为ConsoleWindow中的m_ActiveText就是StackTrace字符串，直接处理就好了。</p> <p>在想到该方案之前，看过两个解决方法：1）将日志类编译成DLL；2）输出日志时自己记录StackFrame，通过一系列手段在OnOpenAsset查找LogEntry中对应的StackFrame。不过这两种方案都不能满足个人的完美主义情节，方案1失去了预编译宏的灵活，一旦日志系统改动需要重编DLL和处理依赖，方案2低效且过于复杂。</p> <p>最后摘出代码供参考，实现环境为：Unity 4.7.5f1, UnityVS+Visual Studio 2015 Pro。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/78e5bc01e0b8_776C/2016-06-21_10-35-04_2.png"><img title="2016-06-21_10-35-04" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="2016-06-21_10-35-04" src="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/78e5bc01e0b8_776C/2016-06-21_10-35-04_thumb.png" width="1247" height="1307"></a></p><img src ="http://www.cppblog.com/heath/aggbug/213777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2016-06-21 10:53 <a href="http://www.cppblog.com/heath/archive/2016/06/21/213777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unity中短距离寻路方案</title><link>http://www.cppblog.com/heath/archive/2016/03/13/212997.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 13 Mar 2016 10:40:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2016/03/13/212997.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/212997.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2016/03/13/212997.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/212997.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/212997.html</trackback:ping><description><![CDATA[<blockquote> <p>从A*到Navmesh都是完备的寻路方案，能满足任意距离的路径搜索。它们都需要根据场景预先生成相关数据（A*是规整的2D格子数据，Navmesh则是mesh数据），在场景尺寸确定的情况下，Navmesh算法的网格数会随障碍的复杂程度改变，而A*是固定的。就时空复杂度而言，通常情况下Navmesh要优于A*，但一些优化的变种A*算法（如：Hierarchy A*）在长距离寻路上要优于Navmesh。然而对于动态改变的场景障碍，在使用以上两种算法时都会有性能和设计上的限制。在实际项目中，我们通常将战斗约束在一定区域内，而且这些区域有可能是诸如移动平台之类的，此时A*和Navmesh可能会面临无法使用的境地。下面这个方案是在洗澡时突然想到的，确切点应该称之为避障算法，因为它源自之前做智能避障小车时的经验。</p> <p>设，角色到目标点的方向向量为D<sub>0</sub>，投射线长度为L，探测间隙角为θ，N = 180 / θ，算法流程如下：</p> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/21828fffae4c_DA4F/image_10.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/21828fffae4c_DA4F/image_thumb_4.png" width="975" height="561"></a></p> <p>算法通过优先搜索目标方向左右无障碍空间，减少检测次数，通过设置θ和L可以控制检测精度和范围。此外，设置合适的Collision Matrix和检测频率可以约束RayCast的性能开销。</p></blockquote><img src ="http://www.cppblog.com/heath/aggbug/212997.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2016-03-13 18:40 <a href="http://www.cppblog.com/heath/archive/2016/03/13/212997.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Font Outline in Unity</title><link>http://www.cppblog.com/heath/archive/2016/02/05/212793.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Fri, 05 Feb 2016 09:36:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2016/02/05/212793.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/212793.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2016/02/05/212793.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/212793.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/212793.html</trackback:ping><description><![CDATA[<blockquote> <p>团队在使用UGUI时，发现其Outline实现是将文字的顶点在上下左右方向上做偏移生成了新的顶点，所以顶点和三角面数量都增加了4倍。受Glow中Gaussian Filter可实现边界外扩效果的启发，做了个实验，在第一个pass中使用Filter对Font Texture的Alpha进行4或者8方向采样，第二个pass正常渲染字体，然后将两者进行Alpha blend。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/Outline_A506/image_12.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/Outline_A506/image_thumb_5.png" width="677" height="223"></a></p> <p align="center">No Outline</p> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/Outline_A506/image_8.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/Outline_A506/image_thumb_3.png" width="679" height="223"></a></p></blockquote> <p align="center">Tow-Pass Outline with Four-Direction Sampling</p> <p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/Outline_A506/image_10.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/Outline_A506/image_thumb_4.png" width="679" height="218"></a></p> <p align="center">Outline in UGUI</p>     <blockquote> <p>从结果上来看，在一定范围的纹理坐标偏移下可以接受，但限制也很明显，下图是偏移过大导致失真</p> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/Outline_A506/image_14.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; border-left: 0px; display: block; padding-right: 0px; margin-right: auto" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Open-Live-Writer/Outline_A506/image_thumb_6.png" width="386" height="158"></a></p></blockquote><img src ="http://www.cppblog.com/heath/aggbug/212793.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2016-02-05 17:36 <a href="http://www.cppblog.com/heath/archive/2016/02/05/212793.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Real-time Cutscene中的摄像机插值研究</title><link>http://www.cppblog.com/heath/archive/2013/10/26/203921.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 26 Oct 2013 01:07:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/10/26/203921.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/203921.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/10/26/203921.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/203921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/203921.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 很多DCC工具都提供了Curves Editor，通过控制点来构造插值曲线，这样可以精确地插值轨迹。在我们游戏的过场编辑器中，我们并没有开发这类工具，一方面由于时间人力有限，另一方面希望能够提供一种直观简便的方式达到想要的效果。因此我们支持两种摄像机路径创建方法：1）以摄像机视角直接将摄像机摆到想要位置，保存此时摄像机的位置与旋转；2）将3DS Max中的路径导出为游戏的过场格式。前者可以满足90%的过场编辑需求，后者满足了10%的复杂路径编辑需求。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 不管使用那种方式，都需要将离散点进行插值（interpolation）以便得到平滑路径。这里就牵涉到位置插值和朝向插值。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 从插值函数上可分为三类：1）线性；2）多项式；3）样条。顾名思义，线性插值采用线性函数，多项式插值采用多项式，而样条插值则采用了一组多项式组成的分段函数。由于摄像机的关键路径点通常都会大于2个，所以插值方法上就必须选取样条方法。 <p><font size="4" face="Arial"><strong>一、位置插值</strong></font></p> <p><font size="3"><strong>1.1 样条类型选择</strong></font> <p>&nbsp;&nbsp;&nbsp;&nbsp; 在这里我们仅考虑三次样条插值，因为它们可达到C2连续。三次样条中主要以Bezier、Catmull-Rom、均匀B样条为考查对象，它们都具有计算开销小的优点。可以通过下面公式来定义它们： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(18)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(18)" border="0" alt="Image(18)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(18)_thumb.png" width="500" height="117"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 简化为： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(19)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(19)" border="0" alt="Image(19)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(19)_thumb.png" width="130" height="32"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 下面表格列出了三种插值曲线对应的G和M： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(20)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(20)" border="0" alt="Image(20)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(20)_thumb.png" width="483" height="339"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 如下图所示，对4个点进行Bezier插值得到的曲线只会有两个点被曲线穿过，而B-Spline插值得到的曲线不会经过控制点，只有Catmull-Rom Spline可以得到穿过除起点和终点之间的所有控制点。正因为Catmull-Rom具有这个特性，使得它被广泛地应用在关键帧平滑插值上，因此我们选择了Catmull-Rom样条作为摄像机位置点的插值算法。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(21)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(21)" border="0" alt="Image(21)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(21)_thumb.png" width="400" height="917"></a> <p><font size="3"><strong>1.2 实现</strong></font> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image" border="0" alt="Image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image_thumb.jpg" width="759" height="732"></a> <p><font size="3"><strong>参考：</strong></font> <p>[1] <a href="http://www.amazon.com/Mathematics-Programming-Computer-Graphics-Edition/dp/1435458869/ref=sr_1_1?ie=UTF8&amp;qid=1378171987&amp;sr=8-1&amp;keywords=Mathematics+for+3D+Game+Programming+and+Computer+Graphics">Mathematics for 3D Game Programming and Computer Graphics 3e by Eric Lengyel</a> <p>[2] <a href="http://en.wikipedia.org/wiki/Catmull-Rom_spline#Catmull.E2.80.93Rom_spline">http://en.wikipedia.org/wiki/Catmull-Rom_spline#Catmull.E2.80.93Rom_spline</a> <p>[3] <a href="http://www.codeproject.com/Articles/30838/Overhauser-Catmull-Rom-Splines-for-Camera-Animatio">http://www.codeproject.com/Articles/30838/Overhauser-Catmull-Rom-Splines-for-Camera-Animatio</a> <p><font size="4"><strong>二、朝向（旋转）插值</strong></font>&nbsp;&nbsp; <p><font size="3"><strong>2.1 Euler Angles VS Quaternion</strong></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; 三维空间中描述旋转的主要方法有Euler Angles和Quaternion。Euler Angles有三个明显的问题：1）三轴上的旋转顺序敏感；2）Gimbal Lock现象导致旋转自由度丢失；3）独立地对三个旋转分量进行插值，忽略了三轴之间的依赖关系，导致插值结果不理想。与Euler Angles不同的是，Quaternion没有将旋转分解到三个轴向上，而是用一个旋转轴和绕该轴的旋转角度来描述，所以从根本上消除了Euler Angles的三大问题。有关Quaternion的详细描述可参考[1]，在此不再累述。 <p><font size="3"><strong>2.2 LERP VS SLERP</strong></font> <p>&nbsp;&nbsp;&nbsp;&nbsp; 四元数线性插值（Linear Quaternion interpolation）的计算公式为： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(1)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(1)" border="0" alt="Image(1)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(1)_thumb.jpg" width="510" height="306"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 四元数球面线性插值（Spherical Linear Quaternion interpolation）的计算公式为： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(2)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(2)" border="0" alt="Image(2)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(2)_thumb.jpg" width="315" height="43"></a> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(3)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(3)" border="0" alt="Image(3)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(3)_thumb.jpg" width="221" height="138"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 其中，θ为两个四元数的夹角。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 为了方便展示，我们考虑在2D情况对角度V进行两次插值，两种算法在插值效果上存在的差异，如下图（b为LERP、c为SLERP）： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(4)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(4)" border="0" alt="Image(4)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(4)_thumb.jpg" width="640" height="128"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 从图中可以看出LERP其实是对两四元数在圆上的弦进行了等分，而SLERP则是对圆弧进行等分。由此得出的结论是，SLERP得到了比LERP更平滑的插值结果。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 为了保证插值曲线的C2连续性，需要使用球面四边形插值（Spherical Quadrangle interpolation）方法。例如，对q1和q2插值，首先要用q0、q1、q2、q3计算出两个控制点（Inner Quadrangle Point），公式如下： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(5)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(5)" border="0" alt="Image(5)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(5)_thumb.jpg" width="286" height="79"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 然后通过下式得到最终插值结果： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(6)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(6)" border="0" alt="Image(6)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(6)_thumb.jpg" width="760" height="41"></a> <p><font size="3"><strong>2.3 实现</strong></font> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(7)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(7)" border="0" alt="Image(7)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(7)_thumb.jpg" width="696" height="1022"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 上面代码没有考虑两个四元数之间夹角大于180°的情况。例如，考虑q1-&gt;q2的插值角度θ&gt;180°，我们可以让q1-&gt;q2反向旋转2π-θ，即旋转-(2π-θ)，根据四元数的定义[v*sin(θ/2) , cos(θ/2)]，那么对q2进行处理变为[-v*sin(θ/2) , -cos(θ/2)]。这个处理可以放在AddSplinePoint中来做： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(8)_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(8)" border="0" alt="Image(8)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/Real-time-Cutscene_7DED/Image(8)_thumb.jpg" width="527" height="234"></a> <p><font size="3"><strong>参考：</strong></font> <p>[1] <a href="http://www.itu.dk/people/erikdam/DOWNLOAD/98-5.pdf%E2%80%8E">Quaternions, Interpolation and Animation by EB Dam - 1998</a> <p>[2] <a href="http://www.amazon.com/Game-Engine-Architecture-Jason-Gregory/dp/1568814135/ref=sr_1_1?ie=UTF8&amp;qid=1378136624&amp;sr=8-1&amp;keywords=Game+Engine+Architecture+by+Jason+Gregory">Game Engine Architecture by Jason Gregory - 2009</a> <p>[3] <a href="https://theory.org/software/qfa/writeup/node12.html">https://theory.org/software/qfa/writeup/node12.html</a><img src ="http://www.cppblog.com/heath/aggbug/203921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-10-26 09:07 <a href="http://www.cppblog.com/heath/archive/2013/10/26/203921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows平台下针对C/C++项目的内存泄漏检测方法</title><link>http://www.cppblog.com/heath/archive/2013/10/26/203920.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 26 Oct 2013 00:55:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/10/26/203920.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/203920.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/10/26/203920.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/203920.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/203920.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 由于语言在自动内存管理上的欠缺，C/C++在内存管理上从来都是需要程序员小心处理的一个方面，当项目代码上了一定规模，内存消耗和泄漏就会成为程序稳定运行的第一大敌。如果不在项目之初就建立内存管理和泄漏检测机制，后面蛋疼的问题就会接踵而来。这篇文章着重讨论内存泄漏检测，而内存管理与具体项目类型关系密切，后面有时间我会着重游戏项目来讨论。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 内存泄漏检测的基本步骤是：1）包装（重载）内存分配/释放API；2）进行内存分配时记下相关信息：地址、大小、调用栈；3）释放时清除之前记录的对应信息；4）程序退出时（确保在所有内存释放操作完成之后），输出剩下的记录。其中，对进行分配操作是的调用栈回溯是个重点信息，它能够帮助我们找出内存泄漏代码。 <p>&nbsp;&nbsp;&nbsp;&nbsp; Windows中的Dbghelp库提供了丰富的调试API。StackWalk应该是进行栈回溯最直接的一种接口了，但是它不够快。如果能先记录下调用栈上的CALL指令地址，然后在输出日志时解析出符号，将会大大降低检测机制对程序本身性能的影响。Dbghelp库中提供了Sym*FromAddr系列API，可以通过指令地址获取函数符号，那么剩下的就是如何记录指令地址的问题了。从网上借了一张x86调用栈示意图，如下： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(12)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(12)" border="0" alt="Image(12)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(12)_thumb.png" width="263" height="458"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 从图中可以看出，Callee的EBP始终指向Caller的EBP，EBP下面是指向Caller下一条指令（注意x86体系下栈的增长方向是小地址），因此通过EBP就可以回溯整个调用栈了。通过下面代码可以实现此功能： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(13)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(13)" border="0" alt="Image(13)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(13)_thumb.png" width="512" height="335"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 宏参数frame是个void*指针数组，数组的大小取决于想要回溯的栈深度。内存分配和回收的包装代码如下： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(14)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(14)" border="0" alt="Image(14)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(14)_thumb.png" width="768" height="311"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 我们看到，内存管理系统内部终究还是要使用语言提供的内存分配/释放API，只要配对实现了分配与释放管理，系统内部的无泄漏是很容易保证的。在这里着重讲解原理，就不重载new/delete operator了。最后看一下调用栈函数符号的回溯代码： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(15)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(15)" border="0" alt="Image(15)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(15)_thumb.png" width="1236" height="868"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 我们用下面代码做测试用例： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(16)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(16)" border="0" alt="Image(16)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(16)_thumb.png" width="537" height="567"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 泄漏检测结果： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(17)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(17)" border="0" alt="Image(17)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/WindowsCC_7CB0/Image(17)_thumb.png" width="800" height="322"></a> <p>参考： <p>[1] <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms681412(v=vs.85).aspx">Using DbgHelp</a> <p>[2] <a href="http://www.unixwiz.net/techtips/win32-callconv-asm.html">Intel x86 Function-call Conventions - Assembly View</a><img src ="http://www.cppblog.com/heath/aggbug/203920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-10-26 08:55 <a href="http://www.cppblog.com/heath/archive/2013/10/26/203920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>3DS Max坐标系与D3D左手系的简单转换方法</title><link>http://www.cppblog.com/heath/archive/2013/06/08/200890.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 08 Jun 2013 14:31:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/06/08/200890.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/200890.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/06/08/200890.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/200890.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/200890.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2013/06/08/200890.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/200890.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-06-08 22:31 <a href="http://www.cppblog.com/heath/archive/2013/06/08/200890.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决A*寻路中边缘行走问题</title><link>http://www.cppblog.com/heath/archive/2013/05/04/199973.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 04 May 2013 15:49:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/05/04/199973.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/199973.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/05/04/199973.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/199973.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/199973.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 用碰撞体来约束世界范围已经用得很广泛了，玩家与世界边缘的交互问题也容易用碰撞面的法线和玩家朝向来解决。然而对于一个基于A* PathFinding的游戏，貌似还没有人去考虑和解决这个问题。最初考虑这个问题，是因为游戏中加入了AWSD的移动方式，当碰到阻挡就静止不动了，加上有时阻挡刷得与场景不太贴合，造成玩家在移动上的不爽快。考虑下图的情况，蓝色三角是角色，红色线段给出了前进方向和终点（游戏中配置为角色朝向上5m处）。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(9)%5B6%5D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(9)[6]" border="0" alt="Image(9)[6]" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(9)%5B6%5D_thumb.png" width="503" height="290"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 我想了两种方案，最初的方案灵感来自光线反射，如下图所示。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(10)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(10)" border="0" alt="Image(10)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(10)_thumb.png" width="516" height="282"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 因为阻挡格子是轴对齐的，通过法向量n可以得到b点的反射向量e'-o，将|e'-o|限定在一个固定值，此时如果e'不在阻挡里面，就将它作为新的终点。该方案的实验结果不太令人满意，当角色离阻挡较近时断续感太明显，因为|e' - b|的长度较短。另外它不能处理e'在阻挡里的情况，被卡住不动的概率依然较大。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 第二种方案是根据移动趋向在一个轴向找一个可达试探点，然后用限制了搜索空间（搜索节点在50以内）的A*算法找到一条到试探点的路径，如下图。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(11)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(11)" border="0" alt="Image(11)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/988bf6b67b08_14D26/Image(11)_thumb.png" width="506" height="285"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 设diff_x = 终点x - 起点x，diff_y = 终点y - 起点y，当diff_x &gt; diff_y，认定为趋向x方向上移动，在这种情况下在终点y轴向上±10个格子内去找到一个最接近终点的无阻挡点（称它为可达试探点）。由于试探点与玩家当前点极有可能是直线不连通的，而且它们不可能太远，所以使用了一个将搜索节点个数限制在50以内A*来得到一条路径。该方案大部分情况都能在边缘找到合理点，但如果玩家垂直面朝阻挡内移动且不能在限制搜索范围内找到可达点，角色就会卡住不动，这种情况就只能让玩家自己调整一下朝向了。 <img src ="http://www.cppblog.com/heath/aggbug/199973.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-05-04 23:49 <a href="http://www.cppblog.com/heath/archive/2013/05/04/199973.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>toLua++的导出函数如何访问Lua Table</title><link>http://www.cppblog.com/heath/archive/2013/02/12/197808.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 12 Feb 2013 11:30:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/02/12/197808.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/197808.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/02/12/197808.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/197808.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/197808.html</trackback:ping><description><![CDATA[<p>有些函数需要向lua返回多个结果，将这些结果存在table中是理所当然的。因为toLua++已经自动生成了函数的wrapper，所以没办法直接将栈顶table返回给Lua。好在toLua预留了lua_Object这个类型，可以代表lua中的任何类型，其实它只是int的typedef罢了，主要是在toLua解析程序时作为标记产生tolua_tovalue调用。在C/C++函数中，需要检查一下栈顶是否为table类型，进行table元素的插入操作，例子函数如下：<pre class="code"><span style="color: blue">void </span>ActorMgr::GetPlayerEntityIDs( lua_Object lua_table )
{
       TEntityListIt tIt ;
       std::list &lt;<span style="color: blue">int</span>&gt; result;

       <span style="color: blue">for</span>(<span style="color: blue">int </span>i = 0; i &lt; ACOTOR_BUCKET_LEN ; ++i)
      {
             <span style="color: blue">for</span>(tIt =mSceneEntities[i].mEntities.begin(); tIt != mSceneEntities[i].mEntities.end( ); ++tIt )
            {
                   TActorPtr tpActor  = tIt-&gt;second-&gt;mpActor ;
                   <span style="color: blue">if</span>(tpActor -&gt;GetActorType() == LOCAL_PLAYER)
                  {
                         result.push_front(tpActor-&gt;GetEntityID());
                  }
                   <span style="color: blue">else if </span>(tpActor-&gt; GetActorType() == REMOTE_PLAYER )
                  {
                         result.push_back(tpActor-&gt;GetEntityID());
                  }
            }
      }
       lua_State* L = LuaVM::GetInstPtr()-&gt;mLS ;
       assert(lua_istable (L , -1));
       std::list &lt;<span style="color: blue">int</span>&gt;:: iterator iter = result. begin();
       <span style="color: blue">for</span>(<span style="color: blue">int </span>i = 1; iter != result .end(); ++ iter , ++i )
      {
             lua_pushinteger(L , *iter);
             lua_rawseti(L , -2 , i);
      }
       lua_pop(L , 1);
}</pre>
<p>需要注意的是，如果是多个参数，Lua的压栈顺序是object pointer、参数从左到右，所以栈顶元素是函数签名最右边的参数。</p><img src ="http://www.cppblog.com/heath/aggbug/197808.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-02-12 19:30 <a href="http://www.cppblog.com/heath/archive/2013/02/12/197808.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lua和C的那些事</title><link>http://www.cppblog.com/heath/archive/2013/02/12/197807.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 12 Feb 2013 11:17:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2013/02/12/197807.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/197807.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2013/02/12/197807.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/197807.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/197807.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Lua和C是天生的好基友，语言开发者提供了一系列API，让他们通过栈进行交流。用Lua做游戏逻辑开发有些时日了，下面主要针对Lua C API的应用进行总结。</p> <p><font size="4"><strong>一、扩展Lua</strong></font></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Lua核心很小，主要包含一个解释器，其他功能可以通过动态库的形式作为插件来扩展，io、string、math、table等内置库都是通过此方式来实现，只是他们被集成到了一个lua.dll中罢了。制作一个动态库形式的module，需要在代码中通过luaL_Reg数组指定lua function到c function的映射，接着实现c function，最后在luaopen_xxx(xxx为module name)注册这个luaL_Reg。这里给出一个非常简单的例子，它使用VC++创建一个Console DLL：</p><pre class="code"><span style="color: blue">#include </span><span style="color: #a31515">"lua.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">"lualib.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">"lauxlib.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;math.h&gt;

</span><span style="color: blue">int </span>mysin (lua_State* L);

<span style="color: blue">static const struct </span>luaL_Reg mymathlib [] =
{
    { <span style="color: #a31515">"sin" </span>, mysin } ,
    { NULL , NULL }
};

<span style="color: blue">static int </span>mysin( lua_State* L )
{
    <span style="color: blue">double </span>d = luaL_checknumber( L , 1);
    lua_pushnumber(L , <span style="color: blue">sin</span>( d));
    <span style="color: blue">return </span>1;
}

<span style="color: blue">__declspec</span>(<span style="color: blue">dllexport</span>) <span style="color: blue">int </span>luaopen_mymathlib(lua_State * L)
{
    luaL_register(L , <span style="color: #a31515">"mymathlib" </span>, mymathlib);
    <span style="color: blue">return </span>1;
}</pre>
<p>编译成dll后放到lua解释器目录下。Lua test code：</p>
<p>require "mymathlib"</p>
<p>local a = mymathlib.sin(0.5)<br>print(a)</p>
<p><font size="4"><strong>二、作为脚本系统</strong></font></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Lua应用最多的领域当属游戏开发，WOW的UI和插件让它名声大噪。在这种应用中，Lua作为应用程序的一个子系统，用作配置或者业务处理。在将Lua与应用集成起来时，必须用到Lua C API，根据其规范，你需要写一系列的static函数，作为Lua与应用程序的粘合代码。如果要在Lua使用C++对象，可将其作为userdata，为它创建一个metatable，并将粘合函数放入其中，关键是要让__index指向metatable自身，这样当Lua访问userdata的field时，__index会引导它去搜索metatable自身，从而获得注册的粘合函数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有很多开源的粘合代码生成器，他们都是在precompile时做了一些工作，因而不是使用macro就是template，这两种方法的代表是toLua++和luaBind。个人更倾向使用toLua++，一方面这种方式比较直白，另一方面本人弱于使用template。在WGAME中也将原来写得不是很好的bind代码替换成了toLua++，目前UI和关卡逻辑重度使用了Lua，产生的bind代码会有几万行，由于项目采用事件驱动的方式，在profile时看到对游戏整体性能影响非常小。luaBind大概了解过，没有在实际项目中用过，在此就不做评论了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在使用toLua++时我最好奇的是它对C++关键特性是如何支持的。除了上面说的成员函数外，对于多态的支持，它是通过在static函数后加编号，调用时判断参数是否对应来遍历找到正确static函数的；对于复杂成员变量，它会自动生成get/set方法；而继承关系，则是通过子类将父类作为metatable来实现。秉着重新发明车轮的精神，我试着写了一个简化的自动生成器[<a href="https://github.com/groov0v/LuaCBind/tree/master/LuaCBind" target="_blank">我在github上</a>]。我定义了几个关键字作为类与方法的导出标识：</p>
<p>&nbsp;&nbsp;&nbsp; {module_begin = "LUACBIND_MODULE_BEGIN" , module_end = "LUACBIND_MODULE_END" , method_begin = "LUACBIND_METHOD_BEGIN" , method_end = "LUACBIND_METHOD_END"}</p>
<p>&nbsp;&nbsp;&nbsp; util.h定义了产生bind代码需要的宏，parser.lua对指定的.h文件进行扫描产生bind代码，在main函数中register后，就可以在lua中使用了。</p>
<p><font size="4"><strong>三、调试器</strong></font></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Lua的C API和Debug库提供了实现调试器的必要方法，对应了两种实现方式：一种是Remdebug所采用的，直接用lua实现；另外一种是使用C API。不管哪种方式，使用HOOK都是必须的，但使用Lua debug库会比C API更方便，因为不用考虑栈平衡问题。在用C API实现调试器时，可用lua_newthread创建一个coroutine，之后yield/resume/getstack/getlocal都作用它上面，breakpoint通常会采用在hook中yield的方式来实现，但不能等hook返回之后去进行栈回溯，因为traceexec根据hook mask调用对应hook函数后，如果state是为LUA_YIELD状态，将会调用luaD_throw，最终使用longjmp导致无法进行回溯。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 利用春节值班两天清闲时光，基于lua 5.2实现了一个命令行调试器[<a href="https://github.com/groov0v/LuaDebugger" target="_blank">我在github上</a>]，目前仅有几个简单的功能：加载/运行lua脚本、设置/清除断点、单步、查看简单类型变量值，命令格式可参考README。</p><img src ="http://www.cppblog.com/heath/aggbug/197807.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2013-02-12 19:17 <a href="http://www.cppblog.com/heath/archive/2013/02/12/197807.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单想了一下《泡泡龙》的实现</title><link>http://www.cppblog.com/heath/archive/2012/11/27/195752.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 27 Nov 2012 15:43:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/11/27/195752.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/195752.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/11/27/195752.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/195752.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/195752.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 领导最近在玩泡泡龙，我也想不通为什么突然又对这么古老的游戏感兴趣了。昨晚在地铁上，她问我这种游戏能做吗？我不加思考回答道：当然，超简单。今天从深大地铁站出来，这个问题突然冒了出来，到公司的路上花了几分钟思考了下实现细节。从最简单的玩法开始：相同颜色的泡泡三个以上可以消除。 <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 核心数据结构我采用链表数组，将相同颜色且邻接的泡泡串成一个链表。采用这种数据结构，是基于下面考虑：1）通过颜色划分缩小搜索区域；2）没有排序，没有中间插入节点的需求；3）节省内存。当然，游戏界面中的泡泡还是把它对应到一个二维数组中，每个元素存储一个泡泡对象的指针，该对象中至少包含：颜色、坐标，分值。如下图所示： <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/7a9d2cb25d28_14D24/Image(8)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(8)" border="0" alt="Image(8)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/7a9d2cb25d28_14D24/Image(8)_thumb.png" width="640" height="320"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 剩下需要考虑的是发射泡泡颜色如何产生？如果从空关卡开始，前面可以用随机，后面就要使用统计信息了。在每个链表头可以统计该堆泡泡开闭性、数量等，利用这些信息可以决定发射泡泡的颜色。 <img src ="http://www.cppblog.com/heath/aggbug/195752.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-11-27 23:43 <a href="http://www.cppblog.com/heath/archive/2012/11/27/195752.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hacking笔记&amp;mdash;&amp;mdash;HDDHACKR自制320GB XBOX SLIM硬盘</title><link>http://www.cppblog.com/heath/archive/2012/11/27/195751.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 27 Nov 2012 15:40:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/11/27/195751.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/195751.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/11/27/195751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/195751.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/195751.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为360装上硬盘，最大的好处就是减少光驱的使用，避免噪音。HDDHackr可以将西部数据特定型号的硬盘(WD3200BPVT、WD3200BEVT)刷写成微软360所使用的希捷硬盘。比起不够厚道的MS出的官方硬盘，我当然选择HDDHackr啦。 <p>准备: <p>1）USB DOS启动盘； <p>2）HDDHackr 1.3和360 320 GB固件； <p>3）一台支持SATA接口的电脑。（我有一台SATAIII接口的PC和一台支持SATAII的ThinkPad X200笔记本） <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在PC上运行失败了,出现不能写入的问题，在X200笔记本上成功了。在此过程中,只需要选择写入固件,程序会帮你自动备份原固件。需要妥善保管原固件，以便后面需要用做数据硬盘的时候可以恢复。</p><img src ="http://www.cppblog.com/heath/aggbug/195751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-11-27 23:40 <a href="http://www.cppblog.com/heath/archive/2012/11/27/195751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hacking笔记&amp;mdash;&amp;mdash;为XBOX360 SLIM刷光驱</title><link>http://www.cppblog.com/heath/archive/2012/11/27/195750.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 27 Nov 2012 15:37:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/11/27/195750.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/195750.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/11/27/195750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/195750.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/195750.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 机器2011年1月份购于香港，前后买了6张正版碟。最近周末可以双休了，正好Black OpsII出了，想到机器已经过了保修期，所以今天动手把机器拆开看看光驱的FW版本，看能否为去买几元一张的碟子玩。根据网上的拆机教程，需要破坏两个保修封条。拆开后发现是0225，JungleFlasher0.1.92(304)已经可以读取它的DVD KEY了。但我的PC主板芯片组是INTEL P45，南桥芯片为ICH10R，虽然网上很多说该芯片不能识别建兴0225，但我还是抱着试一试的心态。因为机箱上有eSATA接口，所以我接机箱内部SATA线接在了SATA1位置（其他位置不能被JF识别，现象可能今天是SATA1可用，明天就SATA6可用了，WIN7内部做了什么恐怕只能MS清楚了）。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/XBOX360-SLIM_1475B/Image(7)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(7)" border="0" alt="Image(7)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/XBOX360-SLIM_1475B/Image(7)_thumb.png" width="504" height="377"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后进入BIOS，将SATA模式从AHCI改为Enhanced IDE（在我的电脑上也不能用Compatible IDE，不然会出现可以识别不能读取的问题）。至于XBOX何时启动的问题，我给出的结论是无所谓，如果XBOX后启动，则需要进设备管理器扫瞄一下新设备。在整个操作过程中，虽然在设备管理器中看不到光驱，但是进入JF的DVDKey 32页签是可以看到的（注意选择I/O Port）。如果是第一次提取光驱的KEY，DVD KEY一项会显示not found，这是正常的，因为程序找不到与已知KEY匹配的。最后点击SlimKey，过程中不要unlock。 <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来就是去网上淘9504，将0225上提取的KEY合入其中。 <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 被骗了，拿到的还是0225，值得庆幸的是光驱是02年4月份的MXIC版，具体用什么方法破解的，我也难的去拆开细究。问了LT刷的是哪个版本，回答是3.0。在网上又买了两张LT3.0和一张不分版本的（应该就是低于AP2.5的吧）。结果是3.0可以安装，运行提示＂此光盘不支援＂，另外一张不分2.0还是3.0的可以运行，于是开始怀疑光驱刷的是2.0。为了验证自己的怀疑，决定自己动手刷LT plus 3.0，另一方面也验证一下破解是否完美（不用拆板焊线就可以反复刷），结果将决定是否退掉光驱。 <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在Win7下试了N次，SATA1,6都试了，就是写入不了（status 0x051），但是可以识别和读KEY。没办法，改变策略：1)先用JF拿前面提取的KEY和LT+3.0合成固件；2)用U盘启动，到纯DOS下使用dosflash来写入固件。这个方案很奏效，成功写入固件，到win7下用JF查看光驱KEY的状态是verified。启动360，买的LT3.0碟子都能玩了。 <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 网上的资料繁杂而难以辨别真伪，所以凡事都要自己实践。补充一下： <p>1）dashboard版本与刷光驱固件有没有关系？没有。光驱的电源接口提供三种电压(3.3、5.0、12）、出舱控制、托盘状态外其余都是地线，所以刷机时的数据通讯只会通过SATA线传输，因此360无法干预刷机过程。我用u盘离线从13599更新到了最新的15574，能玩「黑色行动2」、「极品17」、「忍龙3」。 <p>2）验证光盘是否是LT3.0：用abgx加载光盘信息，如果出现<strong>Topology data is currently verified</strong>就说明是LT3.0（注意对于超刻的碟，普通光驱无法识别，或者读取出错）。 <p>3）dosflash使用注意事项：将SATA线接在第一个口上。进入dos后先别启动360，运行dosflash一次，确保所有sata接口没有错误提示。然后执行dosflash，正常情况下应该没有错误提示，最后选w直接选合好的固件写入。 <img src ="http://www.cppblog.com/heath/aggbug/195750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-11-27 23:37 <a href="http://www.cppblog.com/heath/archive/2012/11/27/195750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>针对CUDA的GPU架构知识与性能对比</title><link>http://www.cppblog.com/heath/archive/2012/11/27/195748.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Tue, 27 Nov 2012 15:13:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/11/27/195748.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/195748.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/11/27/195748.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/195748.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/195748.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 5年前将《GPU Gems 2》中的“Octree Textures on the GPU”用到了论文的实时纹理创作一节，那时候CUDA才刚出生，OpenCL应该还在规范阶段，所以将GPU用于加速和通用计算的成熟方法还是compution by texturing。至于同样的计算量在CPU和GPU上跑，性能到底提升多少，也没有做过对比实验。周末翻了下《CUDA by Example: An Introduction to General-Purpose GPU Programming》，基本掌握了用CUDA编写GPU思想和语法，比起将数据做为纹理、Shader写算法来，进步了不少：1）开发人员不需要熟悉渲染管线及图形API；2）不用花时间去搭建DX或者OpenGL的框架；3）Host与Device代码混编；4）不必采用Hacking思想处理包装成纹理的数据；5）可指定参与计算的线程数。有了如此方便的编程环境，就随手来做一下对比吧，这个例子来自《CUDA by Example》的4.2.2生成Julia集。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 测试代码需要做一些调整，才能更好地体现出GPU的平行计算优势，这其中牵涉到支持CUDA的GPU架构知识，在这里做一下梳理。 <p>&nbsp;&nbsp;&nbsp;&nbsp; 在Nvidia推出Fermi架构之前，支持CUDA的Nvidia显示芯片都是由多个Streaming Multiprocessor（简称SM）组成，每个SM包含了八个Stream Processor（简称SP），每四个SP组成一个组，也就是说SM实际上可以看成包含两组4D的SIMD处理器。此外，每个SM还包含Register、share memory、texture cache以及constant cache。在执行 CUDA 程序的时候，每个SM对应一个 block，而每个SP就是对应一个 thread。虽然一个SM只有八个SP，但是由于SP进行各种运算都有延迟，更不用提内存存取的延迟了，因此 CUDA 在执行程序的时候，实际是以 warp 为单位。目前的支持CUDA显卡，一个 warp 里面有32个 threads，分成两组16 threads的half-warp。由于SP的运算至少有4个时钟周期的延迟，因此对一个4D的SP来说，一次至少执行16个 threads(即 half-warp)才能有效覆盖掉各种运算的延迟[1]。 <p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image" border="0" alt="Image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image_thumb.png" width="500" height="362"></a></p> <p align="center">图 1 <p>&nbsp;&nbsp;&nbsp;&nbsp; 在GeForce GTX 400系列上，Nvidia采用了全新的Fermi架构[2]，之后的显卡的Compute Capability也从1.3跃升至2.0。SP改名为CUDA Core，提升到了32个/SM[3]。图2为Fermi核心演变，从GF104和由其发展起来的GF114、GF106、GF108的CUDA Core都上升到了48个/SM，支持2.1的Compute Capability，而GF100和GF110依旧是32个。最新基于Kepler架构的GeForce GTX 680支持3.0的Compute Capability，CUDA Core数量达到了192个/SM。 <p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(1)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(1)" border="0" alt="Image(1)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(1)_thumb.png" width="500" height="194"></a></p> <p align="center">图 2 <p>&nbsp;&nbsp;&nbsp;&nbsp; 由于测试平台采用的是GTX 560 Ti，所以需要分析一下它的架构。GTX 560 Ti由8个SM组成，下图中，左边是从程序获取的设备属性，右边为单个SM内部结构示例图。可以看到，GTX 560 Ti的每个SM配备了两个Warp调度器，因此每个周期对两个包含32个线程的Warp进行分发。另外，对于一个二维图像，为kernel指定2D的grid和block可使代码更加直观。为此，block采用（16,16），总共分配256个（64*4）threads在一个SM上执行，如果需要产生1024*1024的Julia分形图，则需要grid为（64,64）。 <p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(2)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(2)" border="0" alt="Image(2)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(2)_thumb.png" width="244" height="120"></a> <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(3)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(3)" border="0" alt="Image(3)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(3)_thumb.png" width="245" height="484"></a></p> <p align="center">图 3 <p>&nbsp;&nbsp;&nbsp;&nbsp; <strong>测试平台为：</strong> <p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(4)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(4)" border="0" alt="Image(4)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(4)_thumb.png" width="640" height="130"></a></p> <p>&nbsp;&nbsp;&nbsp;&nbsp; <strong>测试代码说明：</strong> <p>&nbsp;&nbsp;&nbsp;&nbsp; 1）代码分为CPU实现和CUDA实现； <p>&nbsp;&nbsp;&nbsp;&nbsp; 2）均采用CPU计时方法； <p>&nbsp;&nbsp;&nbsp;&nbsp; 3）只针对计算部分测试，不包括内存分配、传输以及文件写入； <p>&nbsp;&nbsp;&nbsp;&nbsp; 下面列出main函数代码，左边为CPU实现，右边为CUDA实现，均编译为release版本。 <p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(5)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(5)" border="0" alt="Image(5)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(5)_thumb.png" width="500" height="222"></a><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(6)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image(6)" border="0" alt="Image(6)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/Image(6)_thumb.png" width="500" height="296"></a></p> <p>&nbsp;&nbsp;&nbsp;&nbsp; <strong>测试结论：</strong>CPU版本耗时244ms，CUDA版本耗时2.1087ms。这可是100倍的效率提升啊。不过CPU版本没有经过多核优化，所以这样这样对比实在不公平，但这却凸显出CUDA C将并行思想融入语言规则的优势。 <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/out.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="out" border="0" alt="out" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/87923948178a_13D80/out_thumb.png" width="484" height="484"></a> <p>&nbsp;&nbsp;&nbsp;&nbsp; 在惊讶GPU用作通用计算的执行效率时，别忘了它还是有诸多应用上的问题： <p>&nbsp;&nbsp;&nbsp;&nbsp; 1)初始化耗时，需要在显存分配空间，然后将数据从内存copy到显存；<br>&nbsp;&nbsp;&nbsp;&nbsp; 2)数据量受GPU显存限制；<br>&nbsp;&nbsp;&nbsp;&nbsp; 3)对本身就需要GPU参与运算的程序，如：3D游戏，通用计算会争夺GPU资源，如果做平衡？<br>&nbsp;&nbsp;&nbsp;&nbsp; 4)计算数据之间的不相关性限制了GPU通用计算的应用范围； <p>&nbsp;&nbsp;&nbsp;&nbsp; 5)CPU算法到适合GPU架构算法的移植； <p>&nbsp;&nbsp;&nbsp;&nbsp; 最后，GPU硬件设计本身就已经决定了它的强项是密集数据处理（如：科学计算、医疗图像处理），在逻辑处理方面还是CPU的天下，所以它们是互补的，只会有整合而非替代的趋势。 <p>[1] <a href="http://www2.kimicat.com/gpu%E7%9A%84%E7%A1%AC%E9%AB%94%E6%9E%B6%E6%A7%8B">http://www2.kimicat.com/gpu%E7%9A%84%E7%A1%AC%E9%AB%94%E6%9E%B6%E6%A7%8B</a> <p>[2] <a href="http://www.chip.cn/index.php?option=com_content&amp;view=article&amp;id=2857:geforce-gtx-400-gpu&amp;catid=7:test-technology&amp;Itemid=15">http://www.chip.cn/index.php?option=com_content&amp;view=article&amp;id=2857:geforce-gtx-400-gpu&amp;catid=7:test-technology&amp;Itemid=15</a> <p>[3] <a href="http://www.geeks3d.com/20100606/gpu-computing-nvidia-cuda-compute-capability-comparative-table/">http://www.geeks3d.com/20100606/gpu-computing-nvidia-cuda-compute-capability-comparative-table</a> <p>[4] <a href="http://www.expreview.com/13590-2.html">http://www.expreview.com/13590-2.html</a> <p>[5] <a href="http://en.wikipedia.org/wiki/CUDA#cite_note-15">http://en.wikipedia.org/wiki/CUDA</a><img src ="http://www.cppblog.com/heath/aggbug/195748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-11-27 23:13 <a href="http://www.cppblog.com/heath/archive/2012/11/27/195748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Pentax的小眼睛</title><link>http://www.cppblog.com/heath/archive/2012/09/23/191723.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 23 Sep 2012 09:34:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/09/23/191723.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/191723.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/09/23/191723.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/191723.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/191723.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 摄影算是实现Ray-Tracing Rendering的完美方式了吧，以快门速度、光圈大小、感光度作为控制参数，渲染出想要表达的光影效果。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有时候，你会突然对某事很感兴趣，但理性思维会让你冷静一下，看是不是一时冲动。N年前，对摄影的需求仅满足于旅游记录，所以一般DC就足够。一个多月前，想要提升照片品质的需求突然串了出来，让这种想法发酵了几天后，发现可能是该入一台DSLR的时候了。在Nikon D7000/Pentax K-5/Canon 60D中选择了K5，就成像效果D7000与K5是同一档次，喜欢K5的手感和味道，小巧是个很重要的因素，这样同样喜欢摄影的Rain也可以用得很好。宾得的对焦系统和镜头群一向都被CN饭喷，不过个人认为K5的对焦在日常拍摄中已经够用，镜头少但全。对于刚使用DSLR不久的我来说，DA 18-55mm F/3.5-5.6 AL虽然在成像锐度方面弱了点，但日常的风景人像还是足够了。DA 55-300mm F/4-5.8 ED近端大光圈拍人像的虚化效果和远端打鸟的远摄效果都还比较满意，由于55-110光圈可以恒定在4，110-200最大光圈恒定在4.5，所以两者组合起来在性价比上要比DA 18-135mm F/3.5-5.6 ED高。凤凰50mm F/1.7手动头，在成像效果方面真心对得起315RMB，有兴趣的同学可以看<a href="http://www.flickr.com/photos/pentaxtinyeye/sets/72157631600231938/" target="_blank">这里</a>。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 摄影技术的提高是个漫长的过程，对初级阶段需要掌握的知识，我总结如下：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1）器材的熟悉到精通：阅读使用手册，熟知各个按钮及选项的意义。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2）保证对焦点（想拍摄物）清晰。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3）相机的基本原理：快门、光圈、感光度对影像的影响。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4）构图：左右对称、三等分、曲线、对角线、T/L型、明暗对比…</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5）光线感知：如何才能做到合适的曝光。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6）利用学到的新知识，不断练习，让相机成为你的另一只眼睛。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在参考书方面，虽然反感“宝典”之流，但《数码单反摄影完全宝典》还算是本不错的入门书了，涵盖了DSLR的基础知识，加上配图（包括拍摄参数），可以提升对好照片的认知。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 写此文的同时，快门数也近3k了，遂将一些习作（没有后期）整理了放入flickr上，ID就萌一点吧『<a href="http://www.flickr.com/photos/pentaxtinyeye" target="_blank">Pentax的小眼睛</a>』。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 彼得森的《理解曝光》是我学习的第二本书，对掌握测光技巧从而正确曝光有很大帮助，距离所想即所得的目标有近了一步。此书还涉及了快门速度、光圈对拍摄效果产生的影响，应该是入门者必读的一本经典之作。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 国庆去了厦门，经过一个月的准备，拍出的片较之前有很大进步，感觉生活又多了些乐趣。</p><img src ="http://www.cppblog.com/heath/aggbug/191723.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-09-23 17:34 <a href="http://www.cppblog.com/heath/archive/2012/09/23/191723.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从CPU超频中学些硬件知识</title><link>http://www.cppblog.com/heath/archive/2012/06/10/178365.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 10 Jun 2012 15:16:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/06/10/178365.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/178365.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/06/10/178365.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/178365.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/178365.html</trackback:ping><description><![CDATA[<p><strong><font size="4">一、前言</font></strong> 
<p>&nbsp;&nbsp;&nbsp;&nbsp; 从大学到现在配过两台PC，第一台Celeron的机器从大二用到研究生毕业，之后开始用笔记本。第二台PC是09年入手的，那阵子玩超频，但心浮气躁，胡乱尝试一下就浅尝辄止了，连一些基本原理都没有弄清楚。最近刚搞好新房安顿下来，有了自己的工作间，在重新组装PC和设置BIOS的时候又想超频了，但这次我期望做到知其所以然，故在网上查阅了一些资料恶补了一下硬件知识，权当作学习笔记。由于网络上关于硬件（特别是内存部分）知识很杂，仅以自己认为比较靠谱的内容为依据，如有不准确之处，欢迎指正。由于使用的是Intel CPU，本文限于Intel架构，且不适用I系列架构。 
<p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/500px-Motherboard_diagram.svg_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="500px-Motherboard_diagram.svg" border="0" alt="500px-Motherboard_diagram.svg" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/500px-Motherboard_diagram.svg_thumb.png" width="500" height="770" /></a> 
<p align="center">总线概览 
<p><strong><font size="4">二、术语</font></strong> 
<p><strong><br /></strong>
<p><strong>主板芯片组：</strong>北桥芯片和南桥芯片。 
<p><strong>北桥（Northbridge）：</strong>PC主板芯片组其中之一，设计用来处理高速信号，与CPU、内存、AGP/PCIE、南桥芯片进行通信。 
<p>南桥（Southbridge）：PC主板芯片组其中之一，设计用来处理低俗信号，通过北桥和CPU通信，与大多数I/O控制设备接口，如PCI控制器、ATA控制器、USB控制器、网络控制器、音效控制器。各个芯片厂商对南桥芯片的命名有所不同，Intel将其称为ICH，nVidia称为MCP，ATI称为IXP/SB。 
<p><strong>前端总线（FSB, Front Side Bus）：</strong>指CPU与北桥芯片之间的数据传输通道。 
<p><strong>锁相环（PLL, Phase-Locked Loop）：</strong>一个闭环的反馈控制系统，它可以使PLL的输出可以与一个参考信号保持固定的相位关系。 
<p><strong>时钟频率：</strong>确切点是晶振频率，与锁相环电路配合使用为PC提供定时信号，通过倍频/分频产生不同频率的基准信号，用以同步系统的每一步操作。对于CPU主频，它是由晶振提供的频率通过CPU内部的PLL电路倍频而来。 
<p><strong>CPU外频：</strong>系统总线的工作频率，体现了CPU与芯片组之间的总线速度。 
<p><strong>前端总线频率：</strong>CPU与北桥芯片之间的总线工作频率。之所以将CPU外频与前端总线频率区分开来，是因为Intel在Pentium 4中加入了Quad Pumped Bus架构，使得系统总线在一个时钟周期内传输4次数据，也就相当于工作频率为CPU外频的4倍。 
<p><strong>CPU倍频：</strong>为倍频系数的简称，是指CPU主频与CPU外频之间的相对比例关系。在PC发展初期，由于CPU速度不高，大部分元件时钟均保持同步，直到80486时代，在CPU制程持续进步下，CPU的速度也加速增长，当时由于其他外部元件受电气结构所限，无法跟进成长，因此Intel首次在CPU中加入了倍频设计。它的作用是使系统总线工作在相对较低的频率上，而CPU速度可以通过倍频来提升。 
<p><strong>双倍数据速率（DDR, Double Data Rate）：</strong>使SDRAM在一个时钟周期内进行两次数据传输的技术，具体地说它在信号的上升沿和下降沿传输数据一次，数据传输率是之前仅利用上升沿进行数据传输的SDRAM的两倍。 
<p><strong>内存频率：</strong>分为核心频率(Internal rate)和I/O总线频率(Bus clock)。每条内存都是由内存芯片组成，内存芯片的频率就是核心频率。I/O总线频率是指北桥与内存之间的总线频率。通常内存条标称的实际上是最大数据传输频率：I/O总线频率X2。其实，从DDR到DDR3，其内存颗粒的频率没有怎么提升，提升的是总线频率。JEDEC制定的DDR三代参数对照如下表所示： 
<p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/Image(11)_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Image(11)" border="0" alt="Image(11)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/Image(11)_thumb.png" width="644" height="140" /></a> 
<p><strong>双通道：</strong>就是在北桥芯片里设计两个内存控制器，这两个内存控制器可相互独立工作，每个控制器控制一个内存通道。在这两个内存通道上CPU可分别寻址、读取数据，从而使内存的带宽增加一倍，数据存取速度也相应增加一倍（理论上）。流行的双通道内存构架是由两个64bit DDR内存控制器构筑而成的，其带宽可达128bit。因为双通道体系的两个内存控制器是独立的、具备互补性的智能内存控制器，因此二者能实现彼此间零等待时间，同时运作。两个内存控制器的这种互补&#8220;天性&#8221;可让有效等待时间缩减50%，从而使内存的带宽翻倍。双通道内存技术是解决CPU总线带宽与内存带宽的矛盾的低价、高性能的方案。 
<p>&nbsp; 
<p><strong><font size="4">三、原理</font></strong> 
<p align="center"><em><font size="4">CPU主频=外频&#215;倍频</font></em></p><em>
<p><br /></p></em>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 从公式可以看出，要提升CPU主频可以从提高外频和倍频两方面着手。然而在实际操作过程中，两者都会受CPU本身及外部硬件（主要是主板）体质的限制，如：锁倍频、主板FSB Frequency上限。 
<p>1）提高外频 
<p>&nbsp;&nbsp;&nbsp;&nbsp; 因为CPU外频的设置直接影响系统总线工作频率，所以通过提升外频和搭配合适的内存，可以在主板支持的前端总线频率上限内有效提升系统的整体性能。之所以要搭配合适的内存，是因为前端总线频率提高，最大的受影响者就是内存，所以内存能够支持的最高工作频率也需要考虑。虽然GPU数据也要通过前端总线由CPU经过北桥到达显卡，但是在仅针对CPU超频的情况下，一般会将CPU与显卡之间通信的频率锁定在100MHz。举个例子：有一块前端总线上限频率为1600MHz的主板，假如搭配一块上限为1600MT/s的DDRIII内存，1:2分频比的前提下，需要将CPU的外频提升到接近400MHz，整个系统才会比较平衡。 
<p>2）提高倍频 
<p>&nbsp;&nbsp;&nbsp;&nbsp; 通过倍频的定义，可以看出，在外频一定的情况下，提高倍频，只能单纯地提高CPU工作频率。虽然，CPU的计算能力除了跟工作频率有关外，还与硬件架构和指令集有关，成倍提高工作频率肯定不等于成倍提高了计算能力，但可以肯定的是频率提高肯定会在一定程度上提高计算能力。 
<p><strong><font size="4">四、实作</font></strong> 
<p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/CaptureMB.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="CaptureMB" border="0" alt="CaptureMB" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/CaptureMB_thumb.png" width="573" height="118" /></a> 
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<p>&nbsp;&nbsp;&nbsp; 五电容版E5200具有很强的超频空间，在倍频定在X8的情况下，1.2V便可以轻松上370MHz。主板在不超频情况下FSB就已经支持1600MHz了，Corsair在使用XMP时支持1600，在整体考量（散热、CPU寿命）后决定将CPU外频定在350MHz、倍频设为x10，这样FSB可工作在1400MHz，内存按照 1:2分频比I/O总线工作在700MHz下（数据传输频率为1400MT/s）。BIOS设置如下： 
<p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/IMG_0602.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="IMG_0602" border="0" alt="IMG_0602" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/IMG_0602_thumb.jpg" width="640" height="478" /></a> 
<p>内存CL、tRCD等值让其自动读取SPD配置。 
<p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/IMG_0604.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="IMG_0604" border="0" alt="IMG_0604" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/IMG_0604_thumb.jpg" width="640" height="478" /></a> 
<p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/Capture.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Capture" border="0" alt="Capture" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/Capture_thumb.png" width="496" height="480" /></a><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/CaptureMem.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CaptureMem" border="0" alt="CaptureMem" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/18e4652fc073_1450A/CaptureMem_thumb.png" width="499" height="480" /></a></p><strong>
<p><br /></p></strong>
<p><strong>参考：</strong> 
<p><strong><br /></strong>
<p>[1] 前端总线 <a href="http://zh.wikipedia.org/wiki/%E5%89%8D%E7%AB%AF%E6%80%BB%E7%BA%BF">http://zh.wikipedia.org/wiki/%E5%89%8D%E7%AB%AF%E6%80%BB%E7%BA%BF</a> 
<p>[2] 晶振及其选用指南 <a href="http://www.naiteli.com.cn/Info/Detail_50139_7547.html">http://www.naiteli.com.cn/Info/Detail_50139_7547.html</a> 
<p>[3] 倍频 <a href="http://baike.baidu.com/view/25647.htm">http://baike.baidu.com/view/25647.htm</a> 
<p>[4] DDR SDRAM <a href="http://en.wikipedia.org/wiki/DDR_SDRAM">http://en.wikipedia.org/wiki/DDR_SDRAM</a> 
<p>[5] DDR2 SDRAM <a href="http://en.wikipedia.org/wiki/DDR2_SDRAM">http://en.wikipedia.org/wiki/DDR2_SDRAM</a> 
<p>[6] DDR3 SDRAM <a href="http://en.wikipedia.org/wiki/DDR3_SDRAM">http://en.wikipedia.org/wiki/DDR3_SDRAM</a> 
<p>[7] 五电容E5200 <a href="http://tech.163.com/digi/09/0316/08/54H0RJNT001618J7.html">http://tech.163.com/digi/09/0316/08/54H0RJNT001618J7.html</a> </p><img src ="http://www.cppblog.com/heath/aggbug/178365.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-06-10 23:16 <a href="http://www.cppblog.com/heath/archive/2012/06/10/178365.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Window调试中的符号文件与源代码管理</title><link>http://www.cppblog.com/heath/archive/2012/03/26/169068.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Mon, 26 Mar 2012 15:10:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/03/26/169068.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/169068.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/03/26/169068.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/169068.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/169068.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 游戏开始进行第二次封闭测试，这次参与人数较多，随之而来的便是无数的崩溃dump。虽然在自动构建流程中已经对PDB和EXE按版本号进行了保存，但由于构建操作人员手动修改构建号，出现多个版本对应相同版本号的问题，以及BUG单填写人以基线版本号而非真实版本号提交的情况，经常浪费开发人员的时间和精力去找对应的PDB，降低了崩溃解决的响应速度。所以非常有必要建立一套自动化方案，得到dump文件后启动WinDbg进行分析时能够自动获取对应的PDB和源代码，WinDbg就提供了这样一套方便实用的工具。</p> <p><b><font size="3">1. 建立源代码索引</font></b>  <p><b></b>&nbsp;&nbsp;&nbsp;&nbsp; WinDbg提供了一套用于管理pdb对应的源代码的工具，位于其安装目录的srcsrv下，对VSS、SVN、CVS、Perforce提供了支持，分别对应vssindex.cmd、svnindex.cmd、cvsindex.cmd、p4index.cmd这四个perl脚本。其实，ssindex.cmd才是具体实现，它根据传入的版本控制系统标识，调用对应的perl module。  <p>&nbsp;&nbsp;&nbsp;&nbsp; svnindex.cmd通过/source和/symbols参数来指定源代码目录和PDB目录，/debug可输出处理的详细信息，/user和/pass提供svn账户和密码。PDB文件中有一节专门用于存放源代码文件列表及处理命令，可通过pdbstr -r -p:PdbFileName -s:srcsrv查看。  <p>&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; svnindex.cmd /debug /source="E:\CodeBase_SVN\Client\trunk\tools\CutSceneEditor" /symbols="E:\CodeBase_SVN\Client\trunk\bin\Release\CutSceneEditor" /user="user" /pass="pwd"  <p>&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; 在执行上面命令前，确保Perl和Subversion已经被安装且设置了PATH环境变量。该命令将提取source code的服务器路径和当前Revision，然后写入PDB。下面是通过pdbstr获取的信息：  <p>&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image(9)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(9)" border="0" alt="Image(9)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image(9)_thumb.png" width="569" height="278"></a>  <p>&nbsp;&nbsp;&nbsp;&nbsp; 上面输出是经过格式化的，原始信息可以通过srctool -n查看：  <p>&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image(10)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(10)" border="0" alt="Image(10)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image(10)_thumb.png" width="547" height="202"></a>  <p>&nbsp;&nbsp;&nbsp;&nbsp; 可以看出，原始代码路径后面跟了一条svn cat指令，由于没有指定sourcepath，所以%targ%缺省为当前路径（"C:\Program Files\Debugging Tools for Windows (x64)\srcsrv"）。&nbsp; <p><b><font size="3">2. 创建符号服务器</font></b>  <p>&nbsp;&nbsp;&nbsp; 所谓符号服务器，最简单的形式就是文件共享服务器。我们使用<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms681378%28v=vs.85%29.aspx" target="_blank">symstore命令</a>，将1中产生的pdb添加到一个文件共享服务器上，如：  <p>&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; symstore.exe add /f "E:\CodeBase_SVN\Client\trunk\bin\Release\CutSceneEditor\*.pdb" /s "\\server.com\pub\Symbols" /t "CutSceneEditor" /v "Build 4171" /c "fix memory leak"  <p>&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp; 该命令会根据PDB的signature和age产生一个GUID，并将PDB放置于以改GUID为名字的目录下：  <p>&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image8.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Image8" border="0" alt="Image8" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/69eadbd9ff75_13A77/Image8_thumb.png" width="304" height="505"></a>  <p>&nbsp;&nbsp;&nbsp; 当debug时，将UNC路径添加到_NT_SYMBOL_PATH中（如：_NT_SYMBOL_PATH=CACHE*F:\Symbols;SRV*http://msdl.microsoft.com/download/symbols;SRV*\\server.com\pub\Symbols），调试器会自动到指定的符号服务器上去搜索对应的pdb文件。  <p>&nbsp;&nbsp;&nbsp;&nbsp; symstore大大简化了符号的版本管理问题，关于它的详细介绍可参考<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms681417%28v=vs.85%29.aspx" target="_blank">symstore介绍</a>。  <p>&nbsp;&nbsp;&nbsp;&nbsp; 值得注意的是，symstore没有锁机制，并不支持多人同时操作。实际情况中，也只有自动构建时才会做此操作。 </p> <p> <p><b><font size="3">3. 使用WinDbg分析Dump文件</font></b>  <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong>我们在代码中加入发生异常写MiniDump的功能，在程序崩溃时产生dump文件。在使用WinDbg分析dump文件时，需要设置Symbol File Path和Source File Path，也可以直接设置环境变量_NT_SYMBOL_PATH和_NT_SOURCE_PATH。在设置_NT_SOURCE_PATH时使用"SRV*CachePath"将表示启用代码提取功能，执行svn cat写入到CachePath指定的目录，否则将使用原始路径。此后，通过点击Call Stack中的函数调用便会触发从svn读取对应代码的操作（通常会有一个安全警告窗口弹出）。  <p>&nbsp;&nbsp;&nbsp;&nbsp; 对于使用WinDbg进行调试在此就不多讲了，推荐一本不错的书《Advanced Windows Debugging》。  <p><font size="3"><strong></strong></font>&nbsp; <p><font size="3"><strong>参考资料</strong></font>  <p>[1] <a href="http://www.codeproject.com/Articles/115125/Source-Indexing-and-Symbol-Servers-A-Guide-to-Easi" target="_blank">Source Indexing and Symbol Servers: A Guide to Easier Debugging</a>  <p>[2] <a href="http://msdn.microsoft.com/en-us/magazine/cc163563.aspx" target="_blank">Source Server Helps You Kill Bugs Dead In Visual Studio 2005</a></p><img src ="http://www.cppblog.com/heath/aggbug/169068.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-03-26 23:10 <a href="http://www.cppblog.com/heath/archive/2012/03/26/169068.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Arduino实践&amp;mdash;&amp;mdash;用PS3手柄遥控你的玩具</title><link>http://www.cppblog.com/heath/archive/2012/02/02/164857.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Thu, 02 Feb 2012 15:33:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/02/02/164857.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/164857.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/02/02/164857.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/164857.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/164857.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 趁着过年放假前的空闲时间，开始着手实现在“<a href="http://www.cppblog.com/heath/archive/2011/11/13/160032.html" target="_blank">Arduino实践——遥控4WD小车</a>”一文中提到过使用PS3手柄作为遥控器的方案，因为过年没有带笔记本回家，现在来补一下。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先要介绍一下USB Host Shield[1]。它是Oleg从2009年春开始设计的Arduino Shield，采用MAX3421E控制芯片，目前最新版本为2.0，旨在让Arduino能够与USB设备（如，键盘、鼠标、游戏手柄、相机、GPS、手机）进行通讯，当然也能完成ADK的功能。在软件方面，Oleg也在github上开放了驱动代码和例子程序[2]，此后又有人基于前者的代码给出了更为方便简洁的USB蓝牙适配器与PS3手柄通讯的示例代码[3,4]。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/28054b1c079f_1416A/image_6.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/28054b1c079f_1416A/image_thumb_2.png" width="652" height="488"></a></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PS3手柄只能与具有相同蓝牙地址的主机配对，所以需要先将USB蓝牙适配器的地址写入PS3手柄。可以使用[3]中的PS3Pair代码，将BDADDR值修改为蓝牙适配器的地址。[4]中提供的PS3BT例子，将蓝牙地址修改和通讯功能整合到了一起，省了一次sketch的upload，注意也需要将代码中的my_bdaddr修改为适配器的地址。配对时需要将PS3手柄连接线与USB Host Shield相连，待完成后将蓝牙适配器接上，打开手柄，可从Serial Monitor看到日志（注意波特率的一致）。</p> <p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/28054b1c079f_1416A/image_4.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/28054b1c079f_1416A/image_thumb_1.png" width="363" height="484"></a><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/28054b1c079f_1416A/image_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/28054b1c079f_1416A/image_thumb.png" width="306" height="448"></a></p> <p align="left">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; USB Host Shield占用了SPI、P9、P10，注意不要冲突了。</p> <p>&nbsp;</p> <p><font size="4">Reference:</font></p> <p>[1] <a title="http://www.circuitsathome.com/arduino_usb_host_shield_projects" href="http://www.circuitsathome.com/arduino_usb_host_shield_projects">http://www.circuitsathome.com/arduino_usb_host_shield_projects</a></p> <p>[2] <a title="https://github.com/felis/USB_Host_Shield_2.0" href="https://github.com/felis/USB_Host_Shield_2.0">https://github.com/felis/USB_Host_Shield_2.0</a></p> <p>[3] <a title="https://github.com/Lauszus/PS3-Controller-BT-Library-for-Arduino" href="https://github.com/Lauszus/PS3-Controller-BT-Library-for-Arduino">https://github.com/Lauszus/PS3-Controller-BT-Library-for-Arduino</a></p> <p>[4] <a title="https://github.com/TKJElectronics/USB_Host_Shield_2.0" href="https://github.com/TKJElectronics/USB_Host_Shield_2.0">https://github.com/TKJElectronics/USB_Host_Shield_2.0</a></p><img src ="http://www.cppblog.com/heath/aggbug/164857.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-02-02 23:33 <a href="http://www.cppblog.com/heath/archive/2012/02/02/164857.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Playing with Proxmark</title><link>http://www.cppblog.com/heath/archive/2012/01/08/163832.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 08 Jan 2012 08:21:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2012/01/08/163832.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/163832.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2012/01/08/163832.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/163832.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/163832.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2012/01/08/163832.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/163832.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2012-01-08 16:21 <a href="http://www.cppblog.com/heath/archive/2012/01/08/163832.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Arduino实践——遥控4WD小车</title><link>http://www.cppblog.com/heath/archive/2011/11/13/160032.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 13 Nov 2011 10:22:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/11/13/160032.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/160032.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/11/13/160032.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/160032.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/160032.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2011/11/13/160032.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/160032.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-11-13 18:22 <a href="http://www.cppblog.com/heath/archive/2011/11/13/160032.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RFID Security</title><link>http://www.cppblog.com/heath/archive/2011/11/12/159992.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 12 Nov 2011 09:43:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/11/12/159992.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/159992.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/11/12/159992.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/159992.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/159992.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 虽然MIFARE Classic encryption Crypto-1算法在08年就被攻破，因为升级成本以及大众对其产生的安全问题还未引起足够的重视等原因，S50/70目前仍旧大量用于诸如公交卡、校园一卡通之类的小额支付卡。目前已经有基于libnfc的开源工具可以获取M1的KEY。用NFC reader做了一下实验，获取一张M1 S50的A/B KEY大概需要1小时左右。</p>
<p>&nbsp;&nbsp;&nbsp; 手上的ShenZhen Tong和HongKong Octopus均是SONY的<a href="http://en.wikipedia.org/wiki/FeliCa">Felica Card</a>，与ISO/IEC 18092（NFC）使用类似的调制方法，采用曼切斯特编码，在13.56MHZ以212kbit/s进行通讯。使用动态密钥，加密算法为DES、3-DES、AES，攻击难度较大，但是从动态密钥的交换过程入手，还是有机会的。目前，有些手机制造商（NOKIA,SAMSUNG,BLACKBERRY）将NFC Reader集成到手机上，未来RFID的应用将比现在更广，安全问题也会越来越受到关注。</p>
<p>&nbsp;</p>
<p><font size="5">References:</font></p>
<p><a title="http://rfidiot.org/" href="http://rfidiot.org/">http://rfidiot.org/</a></p>
<p><a title="http://wiki.yobi.be/wiki/RFID" href="http://wiki.yobi.be/wiki/RFID">http://wiki.yobi.be/wiki/RFID</a></p>
<p><a title="http://www.openpcd.org/" href="http://www.openpcd.org/">http://www.openpcd.org/</a></p>
<p><a href="http://cq.cx/proxmark3.pl">http://cq.cx/proxmark3.pl</a><br /><a href="http://www.proxmark.org/">http://www.proxmark.org/</a></p>
<p><a title="http://www.libnfc.org/documentation/introduction" href="http://www.libnfc.org/documentation/introduction">http://www.libnfc.org/documentation/introduction</a></p>
<p><a title="http://www.cs.ru.nl/~flaviog/publications/Pickpocketing.Mifare.pdf" href="http://www.cs.ru.nl/~flaviog/publications/Pickpocketing.Mifare.pdf">http://www.cs.ru.nl/~flaviog/publications/Pickpocketing.Mifare.pdf</a></p>
<p><a title="http://www.sos.cs.ru.nl/applications/rfid/2008-esorics.pdf" href="http://www.sos.cs.ru.nl/applications/rfid/2008-esorics.pdf">http://www.sos.cs.ru.nl/applications/rfid/2008-esorics.pdf</a></p><img src ="http://www.cppblog.com/heath/aggbug/159992.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-11-12 17:43 <a href="http://www.cppblog.com/heath/archive/2011/11/12/159992.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BackTrack 5 KDE 64bit USB启动不能进入X的解决方法</title><link>http://www.cppblog.com/heath/archive/2011/11/12/159986.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 12 Nov 2011 05:24:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/11/12/159986.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/159986.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/11/12/159986.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/159986.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/159986.html</trackback:ping><description><![CDATA[<p>rm /root/.kde/cache-root/icon-cache.kcache</p> <p>rm /root/.kde/cache-root/plasma_theme_Volatile.kcache</p> <p>rm /root/.kde/cache-bt/icon-cache.kcache</p> <p>rm /root/.kde/cache-bt/plasma_theme_Volatile.kcache</p><img src ="http://www.cppblog.com/heath/aggbug/159986.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-11-12 13:24 <a href="http://www.cppblog.com/heath/archive/2011/11/12/159986.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hierarchical Path-Finding</title><link>http://www.cppblog.com/heath/archive/2011/11/12/159984.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 12 Nov 2011 04:50:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/11/12/159984.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/159984.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/11/12/159984.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/159984.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/159984.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 《<a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.7041&amp;rep=rep1&amp;type=pdf">Near Optimal Hierarchical Path-Finding</a>》中提出了一种层次A*算法，正好能够用于解决项目大地图寻路的问题。大致思路是：1）预处理。将地图划分为nxn大小的区块，找出每个区块与周围四个区块在边界上的互通点，在区块中使用局部A*对找出的点做连通性测试并将其保存下来；2）寻路时，使用预处理得到的数据（边界上的可通点与区块内部的互通点），先在区块层级上做一次A*，根据结果再在每个区块中使用局部A*找到区块与区块之间的路径，最终得到完整路径。  <p><font size="5">一、A* Path-Finding</font>  <p>&nbsp;&nbsp;&nbsp;&nbsp; A*算法就不多讲了，可参考：  <ul> <li><a href="http://theory.stanford.edu/~amitp/GameProgramming/">http://theory.stanford.edu/~amitp/GameProgramming/</a>  <li><a href="http://www.policyalmanac.org/games/aStarTutorial.htm">http://www.policyalmanac.org/games/aStarTutorial.htm</a></li></ul>&nbsp;&nbsp;&nbsp;&nbsp; A*算法的优化可从搜索节点储存和OpenList排序两方面入手。  <p><font size="5">二、预处理</font>  <p>&nbsp;&nbsp;&nbsp;&nbsp; 每个相邻区块（C1和C2）都有一条由公共边，该边两侧小格组成L1和L2，则连通点集E满足下列条件：  <ul> <li>E ⊂ L1 ∪ L2  <li>∀t ∈ L1 ∪ L2 : t ∈ E ⇔ symm(t) ∈ E ，其中symm(t)为对称关系  <li>E不含不可行走格子</li></ul>&nbsp;&nbsp;&nbsp;&nbsp; 对在E中且同边的连续格子取其中点，如下图所示：  <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(6)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(6)" border="0" alt="Image(6)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(6)_thumb.png" width="832" height="641"></a>  <p>&nbsp;&nbsp;&nbsp; 对上面得到的位于同一区块的点集合使用local A*做连通性测试，下图用直线连接来表示两点互通：  <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(7)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(7)" border="0" alt="Image(7)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(7)_thumb.png" width="826" height="631"></a>  <p><font size="5">三、寻路</font>  <p>&nbsp;&nbsp;&nbsp;&nbsp; 使用区块连通信息，进行区块级A*，得到区块之间的连接点，如果在预处理时保存了区块内互通点的路径，就不必再进行区块内的local A*了。  <p>&nbsp;&nbsp;&nbsp;&nbsp; 实验结果表明，在未采用区块内预存路径的情况下，中长距离寻路使用层次A*后的平均效率是普通A*的5倍以上，距离越长效率对比越明显。  <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_thumb.png" width="903" height="469"></a>  <p align="left">&nbsp;&nbsp;&nbsp;&nbsp; A* 93ms  <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_4.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_thumb_1.png" width="888" height="516"></a></p> <p>HPA* 15ms  <p>&nbsp;&nbsp;&nbsp;&nbsp; 从上图中可以看出，HPA*得到的路径并不是最优的，它是在最优和效率上的折中，适合作为长距离寻路的一种优化方案。  <p><font size="5">四、优化点</font>  <ul> <li>可扩展为多层而不仅限于一层  <li>预存区块内连通点路径  <li>区块边界可通面积较大时，产生不自然路径，如下图所示：</li></ul> <blockquote> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_6.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/image_thumb_2.png" width="460" height="112"></a></p></blockquote> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个改进的方法是对过长的边界再做划分：  <blockquote> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(5)_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Image(5)" border="0" alt="Image(5)" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/ea51ff519841_B02D/Image(5)_thumb.png" width="244" height="234"></a></p></blockquote><img src ="http://www.cppblog.com/heath/aggbug/159984.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-11-12 12:50 <a href="http://www.cppblog.com/heath/archive/2011/11/12/159984.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>修正D3DXQuaternionSquad不能正确处理反向Quaternions的BUG</title><link>http://www.cppblog.com/heath/archive/2011/08/21/154037.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 21 Aug 2011 14:16:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/08/21/154037.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/154037.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/08/21/154037.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/154037.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/154037.html</trackback:ping><description><![CDATA[<p>微软DX库里提供了对Quaternion进行球面四边形内插的接口，能够在多个Quaternion之间平滑插值。这里涉及到两个接口：</p><pre>void D3DXQuaternionSquadSetup(
  __out&nbsp; D3DXQUATERNION *pAOut,
  __out&nbsp; D3DXQUATERNION *pBOut,
  __out&nbsp; D3DXQUATERNION *pCOut,
  __in&nbsp;&nbsp; const D3DXQUATERNION *pQ0,
  __in&nbsp;&nbsp; const D3DXQUATERNION *pQ1,
  __in&nbsp;&nbsp; const D3DXQUATERNION *pQ2,
  __in&nbsp;&nbsp; const D3DXQUATERNION *pQ3
);</pre><pre>D3DXQUATERNION* D3DXQuaternionSquad(
  __inout&nbsp; D3DXQUATERNION *pOut,
  __in&nbsp;&nbsp;&nbsp;&nbsp; const D3DXQUATERNION *pQ1,
  __in&nbsp;&nbsp;&nbsp;&nbsp; const D3DXQUATERNION *pA,
  __in&nbsp;&nbsp;&nbsp;&nbsp; const D3DXQUATERNION *pB,
  __in&nbsp;&nbsp;&nbsp;&nbsp; const D3DXQUATERNION *pC,
  __in&nbsp;&nbsp;&nbsp;&nbsp; FLOAT t
);</pre><pre>其中，D3DXQuaternionSquadSetup用于返回内插的控制点。它们具体的实现公式和用法，有兴趣的同学可以参考MSDN。在此需要说明的是，</pre><pre>D3DXQuaternionSquad使用了Slerp作为内部实现，会导致在两个夹角为180°左右的Quaternion之间插值会出现断裂的问题。下面代码通过</pre><pre>实现一个考虑了上述情况的Slerp版本，在q1和q2夹角在0°或者180°时，使用线性内插而非球面，来解决该问题。</pre>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:1cd98649-9aef-4333-8ab4-db2524382469" class="wlWriterEditableSmartContent">
<div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li><span style="color:#010001">Quaternion</span> <span style="color:#010001">QuatSlerpNoInvert</span>(<span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">q1</span> , <span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">q2</span> , <span style="color:#0000ff">float</span> <span style="color:#010001">t</span>)</li>
<li style="background: #f3f3f3">{</li>
<li>    <span style="color:#0000ff">float</span> <span style="color:#010001">cosAngle</span> = <span style="color:#010001">DotProduct</span>(<span style="color:#010001">q1</span>, <span style="color:#010001">q2</span>);</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li>    <span style="color:#0000ff">float</span> <span style="color:#010001">c1</span>, <span style="color:#010001">c2</span>;</li>
<li style="background: #f3f3f3">    <span style="color:#008000">// Linear interpolation for close orientations</span></li>
<li>    <span style="color:#0000ff">if</span> ((1.0f - <span style="color:#010001">fabs</span>(<span style="color:#010001">cosAngle</span>)) &lt; 1e-5f)</li>
<li style="background: #f3f3f3">    {</li>
<li>        <span style="color:#010001">c1</span> = 1.0f - <span style="color:#010001">t</span>;</li>
<li style="background: #f3f3f3">        <span style="color:#010001">c2</span> = <span style="color:#010001">t</span>;</li>
<li>    }</li>
<li style="background: #f3f3f3">    <span style="color:#0000ff">else</span></li>
<li>    {</li>
<li style="background: #f3f3f3">        <span style="color:#008000">// Spherical interpolation</span></li>
<li>        <span style="color:#0000ff">float</span> <span style="color:#010001">angle</span>    = <span style="color:#010001">acos</span>(<span style="color:#010001">fabs</span>(<span style="color:#010001">cosAngle</span>));</li>
<li style="background: #f3f3f3">        <span style="color:#0000ff">float</span> <span style="color:#010001">sinAngle</span> = <span style="color:#010001">sin</span>(<span style="color:#010001">angle</span>);</li>
<li>        <span style="color:#010001">c1</span> = <span style="color:#010001">sin</span>(<span style="color:#010001">angle</span> * (1.0f - <span style="color:#010001">t</span>)) / <span style="color:#010001">sinAngle</span>;</li>
<li style="background: #f3f3f3">        <span style="color:#010001">c2</span> = <span style="color:#010001">sin</span>(<span style="color:#010001">angle</span> * <span style="color:#010001">t</span>) / <span style="color:#010001">sinAngle</span>;</li>
<li>    }</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li>    <span style="color:#010001">Quaternion</span> <span style="color:#010001">q</span> = <span style="color:#010001">q1</span> * <span style="color:#010001">c1</span> + <span style="color:#010001">q2</span> * <span style="color:#010001">c2</span>;</li>
<li style="background: #f3f3f3">    <span style="color:#010001">q</span>.<span style="color:#010001">Normalize</span>();</li>
<li>&nbsp;</li>
<li style="background: #f3f3f3">    <span style="color:#0000ff">return</span> <span style="color:#010001">q</span>;</li>
<li>}</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li><span style="color:#010001">Quaternion</span> <span style="color:#010001">QuatSquad</span>(<span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">p1</span> , <span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">p2</span> , <span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">p3</span> , <span style="color:#0000ff">const</span> <span style="color:#010001">Quaternion</span>&amp; <span style="color:#010001">p4</span> , <span style="color:#0000ff">float</span> <span style="color:#010001">t</span>)</li>
<li style="background: #f3f3f3">{</li>
<li>    <span style="color:#0000ff">static</span> <span style="color:#010001">Quaternion</span> <span style="color:#010001">a</span> , <span style="color:#010001">b</span> , <span style="color:#010001">c</span>;</li>
<li style="background: #f3f3f3">&nbsp;</li>
<li>    <span style="color:#010001">D3DXQuaternionSquadSetup</span>((<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">a</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">b</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">c</span> ,</li>
<li style="background: #f3f3f3">        (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">p1</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">p2</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">p3</span> , (<span style="color:#010001">D3DXQUATERNION</span>*)&amp;<span style="color:#010001">p4</span>);</li>
<li>&nbsp;</li>
<li style="background: #f3f3f3">    <span style="color:#0000ff">return</span> <span style="color:#010001">QuatSlerpNoInvert</span>(<span style="color:#010001">QuatSlerpNoInvert</span>(<span style="color:#010001">p2</span> , <span style="color:#010001">c</span> , <span style="color:#010001">t</span>) , <span style="color:#010001">QuatSlerpNoInvert</span>(<span style="color:#010001">a</span> , <span style="color:#010001">b</span> , <span style="color:#010001">t</span>) , 2 * <span style="color:#010001">t</span> * (1-<span style="color:#010001">t</span>));</li>
<li>}</li>
</ol>
</div>
</div>
</div>
<p>&nbsp;</p>
<p>参考：</p>
<p>[1] <a href="http://msdn.microsoft.com/en-us/library/bb205419(v=vs.85).aspx">http://msdn.microsoft.com/en-us/library/bb205419(v=vs.85).aspx</a></p>
<p>[2] <a href="http://msdn.microsoft.com/en-us/library/bb205420(v=vs.85).aspx">http://msdn.microsoft.com/en-us/library/bb205420(v=vs.85).aspx</a></p><img src ="http://www.cppblog.com/heath/aggbug/154037.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-08-21 22:16 <a href="http://www.cppblog.com/heath/archive/2011/08/21/154037.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个QTE原型框架</title><link>http://www.cppblog.com/heath/archive/2011/08/13/153251.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 13 Aug 2011 02:25:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/08/13/153251.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/153251.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/08/13/153251.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/153251.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/153251.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: QTE为Quick Time Event的简写，多见于主机游戏中，通常以在规定时间内根据提示完成（一系列）按键操作的形式出现。就表现上看，其实是过场动画的一种分解触发机制，用于表现看似复杂实则固定的动作或者场景效果，一方面在消除了单纯过场乏味感的同时增强了游戏的互动性，另一方面还降低了表现复杂效果的开发难度。<br>本文主要根据自己在项目中开发的QTE系统，介绍一个相对比较简单的原型框架。&nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2011/08/13/153251.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/153251.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-08-13 10:25 <a href="http://www.cppblog.com/heath/archive/2011/08/13/153251.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现一个以字符串为Key大小写不敏感的Hash Map</title><link>http://www.cppblog.com/heath/archive/2011/07/13/150906.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Wed, 13 Jul 2011 15:36:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/07/13/150906.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/150906.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/07/13/150906.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/150906.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/150906.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; Hash Map有两个关键方法：哈希值计算方法和比较方法。以STLPort为例，通过Hash Map的模版定义可以看出，其缺省的哈希Functor是hash，比较functor为equal_to：</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:4eae06a8-1ba3-4127-b9ef-add2254f5ac4" class="wlWriterEditableSmartContent"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #ddd; max-height: 300px; overflow: auto"> <ol start="1" style="background: #ffffff; margin: 0 0 0 2em; padding: 0 0 0 5px;"> <li><span style="color:#0000ff">template</span> &lt;<span style="color:#0000ff">class</span> <span style="color:#010001">_Key</span>, <span style="color:#0000ff">class</span> <span style="color:#010001">_Tp</span>, <span style="color:#010001">_STLP_DFL_TMPL_PARAM</span>(<span style="color:#010001">_HashFcn</span>,<span style="color:#010001">hash</span>&lt;<span style="color:#010001">_Key</span>&gt;),</li> <li style="background: #f3f3f3">          <span style="color:#010001">_STLP_DFL_TMPL_PARAM</span>(<span style="color:#010001">_EqualKey</span>,<span style="color:#010001">equal_to</span>&lt;<span style="color:#010001">_Key</span>&gt;),</li> <li>          <span style="color:#010001">_STLP_DEFAULT_PAIR_ALLOCATOR_SELECT</span>(<span style="color:#010001">_STLP_CONST</span> <span style="color:#010001">_Key</span>, <span style="color:#010001">_Tp</span>) &gt;</li> <li style="background: #f3f3f3"><span style="color:#0000ff">class</span> <span style="color:#010001">hash_map</span></li> </ol> </div> </div> </div> <p>&nbsp;&nbsp;&nbsp; 在_hash_fun.h中有针对各种类型的哈希值计算特化版本，下面仅摘录针对C字符串的代码：</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:6cfec1ef-9640-4f1e-b059-60456851b718" class="wlWriterEditableSmartContent"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #ddd; max-height: 500px; overflow: auto"> <ol start="1" style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;"> <li><span style="color:#0000ff">inline</span> <span style="color:#010001">size_t</span> <span style="color:#010001">__stl_hash_string</span>(<span style="color:#0000ff">const</span> <span style="color:#0000ff">char</span>* <span style="color:#010001">__s</span>) {</li> <li style="background: #f3f3f3">  <span style="color:#010001">_STLP_FIX_LITERAL_BUG</span>(<span style="color:#010001">__s</span>)</li> <li>  <span style="color:#0000ff">unsigned</span> <span style="color:#0000ff">long</span> <span style="color:#010001">__h</span> = 0;</li> <li style="background: #f3f3f3">  <span style="color:#0000ff">for</span> ( ; *<span style="color:#010001">__s</span>; ++<span style="color:#010001">__s</span>)</li> <li>    <span style="color:#010001">__h</span> = 5*<span style="color:#010001">__h</span> + *<span style="color:#010001">__s</span>;</li> <li style="background: #f3f3f3">&nbsp;</li> <li>  <span style="color:#0000ff">return</span> <span style="color:#010001">size_t</span>(<span style="color:#010001">__h</span>);</li> <li style="background: #f3f3f3">}</li> <li>&nbsp;</li> <li style="background: #f3f3f3"><span style="color:#010001">_STLP_MOVE_TO_STD_NAMESPACE</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3"><span style="color:#010001">_STLP_TEMPLATE_NULL</span></li> <li><span style="color:#0000ff">struct</span> <span style="color:#010001">hash</span>&lt;<span style="color:#0000ff">char</span>*&gt; {</li> <li style="background: #f3f3f3">  <span style="color:#010001">size_t</span> <span style="color:#0000ff">operator</span>()(<span style="color:#0000ff">const</span> <span style="color:#0000ff">char</span>* <span style="color:#010001">__s</span>) <span style="color:#0000ff">const</span> {</li> <li>    <span style="color:#010001">_STLP_FIX_LITERAL_BUG</span>(<span style="color:#010001">__s</span>)</li> <li style="background: #f3f3f3">    <span style="color:#0000ff">return</span> <span style="color:#010001">_STLP_PRIV</span> <span style="color:#010001">__stl_hash_string</span>(<span style="color:#010001">__s</span>);</li> <li>  }</li> <li style="background: #f3f3f3">};</li> <li>&nbsp;</li> <li style="background: #f3f3f3"><span style="color:#010001">_STLP_TEMPLATE_NULL</span></li> <li><span style="color:#0000ff">struct</span> <span style="color:#010001">hash</span>&lt;<span style="color:#0000ff">const</span> <span style="color:#0000ff">char</span>*&gt; {</li> <li style="background: #f3f3f3">  <span style="color:#010001">size_t</span> <span style="color:#0000ff">operator</span>()(<span style="color:#0000ff">const</span> <span style="color:#0000ff">char</span>* <span style="color:#010001">__s</span>) <span style="color:#0000ff">const</span> {</li> <li>    <span style="color:#010001">_STLP_FIX_LITERAL_BUG</span>(<span style="color:#010001">__s</span>)</li> <li style="background: #f3f3f3">    <span style="color:#0000ff">return</span> <span style="color:#010001">_STLP_PRIV</span> <span style="color:#010001">__stl_hash_string</span>(<span style="color:#010001">__s</span>);</li> <li>  }</li> <li style="background: #f3f3f3">};</li> </ol> </div> </div> </div> <p>&nbsp;&nbsp;&nbsp; __stl_hash_string实现了一个简单的哈希算法，因为算法中使用了字符的ASCII码，为了达到大小写不敏感的目的，可将每个字符转换成小写/大写来计算。对于hash functor，我们也需要一个string的特化版。</p> <p>&nbsp;&nbsp;&nbsp; 在_function_base.h中定义了equal_to functor：</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:6c6a9c7b-a88e-49e4-8166-78deea0aa1d4" class="wlWriterEditableSmartContent"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #ddd; max-height: 300px; overflow: auto"> <ol start="1" style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;"> <li><span style="color:#0000ff">template</span> &lt;<span style="color:#0000ff">class</span> <span style="color:#010001">_Arg1</span>, <span style="color:#0000ff">class</span> <span style="color:#010001">_Arg2</span>, <span style="color:#0000ff">class</span> <span style="color:#010001">_Result</span>&gt;</li> <li style="background: #f3f3f3"><span style="color:#0000ff">struct</span> <span style="color:#010001">binary_function</span> {</li> <li>  <span style="color:#0000ff">typedef</span> <span style="color:#010001">_Arg1</span> <span style="color:#010001">first_argument_type</span>;</li> <li style="background: #f3f3f3">  <span style="color:#0000ff">typedef</span> <span style="color:#010001">_Arg2</span> <span style="color:#010001">second_argument_type</span>;</li> <li>  <span style="color:#0000ff">typedef</span> <span style="color:#010001">_Result</span> <span style="color:#010001">result_type</span>;</li> <li style="background: #f3f3f3"><span style="color:#0000ff">#if</span> !<span style="color:#0000ff">defined</span> (<span style="color:#010001">__BORLANDC__</span>) || (<span style="color:#010001">__BORLANDC__</span> &lt; 0x580)</li> <li><span style="color:#0000ff">protected</span>:</li> <li style="background: #f3f3f3">  <span style="color:#008000">/* See unary_function comment. */</span></li> <li>  ~<span style="color:#010001">binary_function</span>() {}</li> <li style="background: #f3f3f3"><span style="color:#0000ff">#endif</span></li> <li>};</li> <li style="background: #f3f3f3">&nbsp;</li> <li><span style="color:#0000ff">template</span> &lt;<span style="color:#0000ff">class</span> <span style="color:#010001">_Tp</span>&gt;</li> <li style="background: #f3f3f3"><span style="color:#0000ff">struct</span> <span style="color:#010001">equal_to</span> : <span style="color:#0000ff">public</span> <span style="color:#010001">binary_function</span>&lt;<span style="color:#010001">_Tp</span>, <span style="color:#010001">_Tp</span>, <span style="color:#0000ff">bool</span>&gt; {</li> <li>  <span style="color:#0000ff">bool</span> <span style="color:#0000ff">operator</span>()(<span style="color:#0000ff">const</span> <span style="color:#010001">_Tp</span>&amp; <span style="color:#010001">__x</span>, <span style="color:#0000ff">const</span> <span style="color:#010001">_Tp</span>&amp; <span style="color:#010001">__y</span>) <span style="color:#0000ff">const</span> { <span style="color:#0000ff">return</span> <span style="color:#010001">__x</span> == <span style="color:#010001">__y</span>; }</li> <li style="background: #f3f3f3">};</li> </ol> </div> </div> </div> <p>&nbsp;&nbsp;&nbsp; 通过定制一个string版本的equal_to，使用stricmp进行字符串比较。下面列出实现及测试代码：</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:09167350-9b87-41ad-b212-1d98081ecfb6" class="wlWriterEditableSmartContent"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px">Test Codes</div> <div style="background: #ddd; max-height: 500px; overflow: auto"> <ol start="1" style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;"> <li><span style="color:#0000ff">#include</span> <span style="color:#a31515">&lt;hash_map&gt;</span></li> <li style="background: #f3f3f3"><span style="color:#0000ff">#include</span> <span style="color:#a31515">&lt;string&gt;</span></li> <li><span style="color:#0000ff">#include</span> <span style="color:#a31515">&lt;algorithm&gt;</span></li> <li style="background: #f3f3f3"><span style="color:#0000ff">#include</span> <span style="color:#a31515">&lt;cctype&gt;</span></li> <li>&nbsp;</li> <li style="background: #f3f3f3"><span style="color:#0000ff">inline</span> <span style="color:#010001">size_t</span> <span style="color:#010001">__stl_hash_string</span>(<span style="color:#0000ff">const</span> <span style="color:#0000ff">char</span>* <span style="color:#010001">__s</span>) </li> <li>{</li> <li style="background: #f3f3f3">    <span style="color:#0000ff">unsigned</span> <span style="color:#0000ff">long</span> <span style="color:#010001">__h</span> = 0;</li> <li>    <span style="color:#0000ff">for</span> ( ; *<span style="color:#010001">__s</span>; ++<span style="color:#010001">__s</span>)</li> <li style="background: #f3f3f3">        <span style="color:#010001">__h</span> = 5*<span style="color:#010001">__h</span> + <span style="color:#010001">tolower</span>(*<span style="color:#010001">__s</span>);</li> <li>&nbsp;</li> <li style="background: #f3f3f3">    <span style="color:#0000ff">return</span> <span style="color:#010001">size_t</span>(<span style="color:#010001">__h</span>);</li> <li>}</li> <li style="background: #f3f3f3">&nbsp;</li> <li><span style="color:#0000ff">template</span>&lt;&gt;</li> <li style="background: #f3f3f3"><span style="color:#0000ff">struct</span> <span style="color:#010001">stlport</span>::<span style="color:#010001">hash</span>&lt;<span style="color:#010001">stlport</span>::<span style="color:#010001">string</span>&gt;</li> <li>{</li> <li style="background: #f3f3f3">    <span style="color:#010001">size_t</span> <span style="color:#0000ff">operator</span>()(<span style="color:#0000ff">const</span> <span style="color:#010001">stlport</span>::<span style="color:#010001">string</span>&amp; <span style="color:#010001">__s</span>) <span style="color:#0000ff">const</span></li> <li>    {</li> <li style="background: #f3f3f3">        <span style="color:#0000ff">return</span> <span style="color:#010001">__stl_hash_string</span>(<span style="color:#010001">__s</span>.<span style="color:#010001">c_str</span>());</li> <li>    }</li> <li style="background: #f3f3f3">};</li> <li>&nbsp;</li> <li style="background: #f3f3f3"><span style="color:#0000ff">template</span>&lt;&gt;</li> <li><span style="color:#0000ff">struct</span> <span style="color:#010001">stlport</span>::<span style="color:#010001">equal_to</span>&lt;<span style="color:#010001">stlport</span>::<span style="color:#010001">string</span>&gt; </li> <li style="background: #f3f3f3">    : <span style="color:#0000ff">public</span> <span style="color:#010001">stlport</span>::<span style="color:#010001">binary_function</span>&lt;<span style="color:#010001">stlport</span>::<span style="color:#010001">string</span> , <span style="color:#010001">stlport</span>::<span style="color:#010001">string</span> , <span style="color:#0000ff">bool</span>&gt;</li> <li>{</li> <li style="background: #f3f3f3">    <span style="color:#0000ff">bool</span> <span style="color:#0000ff">operator</span>()(<span style="color:#0000ff">const</span> <span style="color:#010001">stlport</span>::<span style="color:#010001">string</span>&amp; <span style="color:#010001">__x</span>, <span style="color:#0000ff">const</span> <span style="color:#010001">stlport</span>::<span style="color:#010001">string</span>&amp; <span style="color:#010001">__y</span>) <span style="color:#0000ff">const</span> </li> <li>    { </li> <li style="background: #f3f3f3">        <span style="color:#0000ff">return</span> !<span style="color:#010001">_stricmp</span>(<span style="color:#010001">__x</span>.<span style="color:#010001">c_str</span>() , <span style="color:#010001">__y</span>.<span style="color:#010001">c_str</span>()); </li> <li>    }</li> <li style="background: #f3f3f3">};</li> <li>&nbsp;</li> <li style="background: #f3f3f3"><span style="color:#0000ff">int</span> <span style="color:#010001">_tmain</span>(<span style="color:#0000ff">int</span> <span style="color:#010001">argc</span>, <span style="color:#010001">_TCHAR</span>* <span style="color:#010001">argv</span>[])</li> <li>{</li> <li style="background: #f3f3f3">    <span style="color:#010001">stlport</span>::<span style="color:#010001">hash_map</span>&lt;<span style="color:#010001">stlport</span>::<span style="color:#010001">string</span> , <span style="color:#0000ff">int</span>&gt; <span style="color:#010001">map</span>;</li> <li>&nbsp;</li> <li style="background: #f3f3f3">    <span style="color:#010001">map</span>.<span style="color:#010001">insert</span>(<span style="color:#010001">stlport</span>::<span style="color:#010001">make_pair</span>(<span style="color:#a31515">&quot;Test&quot;</span> , 123));</li> <li>&nbsp;</li> <li style="background: #f3f3f3">    <span style="color:#010001">stlport</span>::<span style="color:#010001">hash_map</span>&lt;<span style="color:#010001">stlport</span>::<span style="color:#010001">string</span> , <span style="color:#0000ff">int</span>&gt;::<span style="color:#010001">iterator</span> <span style="color:#010001">iter</span> = <span style="color:#010001">map</span>.<span style="color:#010001">find</span>(<span style="color:#a31515">&quot;teSt&quot;</span>);</li> <li>    <span style="color:#0000ff">if</span>(<span style="color:#010001">iter</span> != <span style="color:#010001">map</span>.<span style="color:#010001">end</span>())</li> <li style="background: #f3f3f3">        <span style="color:#010001">printf</span>(<span style="color:#a31515">&quot;Found!&#92;n&quot;</span>);</li> <li>&nbsp;</li> <li style="background: #f3f3f3">    <span style="color:#0000ff">return</span> 0;</li> <li>}</li> </ol> </div> </div> </div><img src ="http://www.cppblog.com/heath/aggbug/150906.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-07-13 23:36 <a href="http://www.cppblog.com/heath/archive/2011/07/13/150906.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让VC++ 2003与Win7和睦相处</title><link>http://www.cppblog.com/heath/archive/2011/03/14/141837.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Mon, 14 Mar 2011 15:49:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/03/14/141837.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/141837.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/03/14/141837.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/141837.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/141837.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 微软太谦虚了，Win7对VS2003的兼容性并不像他说的那样差。其实仅有两个问题：</p> <p>1、search时程序死掉</p> <p>2、debug时锁住pdb不释放，下次build时出现文件写错误</p> <p>&nbsp;&nbsp;&nbsp; 对于第一个问题，在devenv.exe属性的Compatibility的Settings中勾选“Disable visual themes”，或者停用Aero主题，使用Basic themes。</p> <p>&nbsp;&nbsp;&nbsp; 对于第二个问题，可使用sysinternals工具<a href="http://technet.microsoft.com/en-us/sysinternals/bb896655" target="_blank">handle</a>来释放对pdb的引用，在此不列出handle的使用，有兴趣可以自己研究。下面给出一个批处理，关闭指定名称的pdb文件占用：</p> <p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:45bc8aec-c6b1-457e-a654-2fb55167abc7" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">@echo</span><span style="color: #000000;"> </span><span style="color: #0000FF;">off</span><span style="color: #000000;">
</span><span style="color: #0000FF;">cd</span><span style="color: #000000;"> </span><span style="color: #000000;">/</span><span style="color: #000000;">d </span><span style="color: #000000;">"</span><span style="color: #000000;">%~dp0</span><span style="color: #000000;">"</span><span style="color: #000000;">
</span><span style="color: #0000FF;">for</span><span style="color: #000000;"> </span><span style="color: #000000;">/</span><span style="color: #000000;">f </span><span style="color: #000000;">"</span><span style="color: #000000;">tokens=2-3 skip=5 delims=:</span><span style="color: #000000;">"</span><span style="color: #000000;"> %%a in </span><span style="color: #000000;">(</span><span style="color: #000000;">'handle -p devenv</span><span style="color: #000000;">.</span><span style="color: #000000;">exe </span><span style="color: #000000;">"</span><span style="color: #000000;">%1.pdb</span><span style="color: #000000;">"</span><span style="color: #000000;">'</span><span style="color: #000000;">)</span><span style="color: #000000;"> </span><span style="color: #0000FF;">do</span><span style="color: #000000;"> </span><span style="color: #000000;">(</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> </span><span style="color: #000000;">/</span><span style="color: #000000;">f </span><span style="color: #000000;">"</span><span style="color: #000000;">tokens=1,4</span><span style="color: #000000;">"</span><span style="color: #000000;"> %%c in </span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">%%a%%b</span><span style="color: #000000;">"</span><span style="color: #000000;">)</span><span style="color: #000000;"> </span><span style="color: #0000FF;">do</span><span style="color: #000000;"> </span><span style="color: #000000;">(</span><span style="color: #000000;">
      handle</span><span style="color: #000000;">.</span><span style="color: #000000;">exe -c %%d -y -p %%c
  </span><span style="color: #000000;">)</span><span style="color: #000000;">
</span><span style="color: #000000;">)</span><span style="color: #000000;">
</span><span style="color: #0000FF;">@echo</span><span style="color: #000000;"> </span><span style="color: #0000FF;">on</span><span style="color: #000000;">
</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div></p>
<p>&nbsp;&nbsp;&nbsp; 将其保存到一个文件，放在project的pre-build event。当然，还需要一个参数来喂批处理中的%1。</p><img src ="http://www.cppblog.com/heath/aggbug/141837.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-03-14 23:49 <a href="http://www.cppblog.com/heath/archive/2011/03/14/141837.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HACKING EBOOT.BIN</title><link>http://www.cppblog.com/heath/archive/2011/03/06/141220.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 06 Mar 2011 09:52:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/03/06/141220.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/141220.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/03/06/141220.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/141220.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/141220.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2011/03/06/141220.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/141220.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-03-06 17:52 <a href="http://www.cppblog.com/heath/archive/2011/03/06/141220.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>算法优化&amp;mdash;&amp;mdash;递归到循环</title><link>http://www.cppblog.com/heath/archive/2011/03/05/141160.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 05 Mar 2011 05:42:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/03/05/141160.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/141160.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/03/05/141160.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/141160.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/141160.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 递归通常很直白地描述了一个求解过程，因此也是最容易被想到和实现的算法。循环其实和递归具有相同的特性（即：做重复任务），但有时，使用循环的算法并不会那么清晰地描述解决问题步骤。单从算法设计上看，递归和循环并无优劣之别。然而，在实际开发中，因为函数调用的开销，递归常常会带来性能问题，特别是在求解规模不确定的情况下。而循环因为没有函数调用开销，所以效率会比递归高。除少数编程语言对递归进行了优化外，大部分语言在实现递归算法时还是十分笨拙，由此带来了如何将递归算法转换为循环算法的问题。算法转换应当建立在对求解过程充分理解的基础上，有时甚至需要另辟蹊径。  <p>&nbsp;&nbsp;&nbsp;&nbsp; 前段时间遇到过这样的问题：已知一2D地图格子的长宽（w、h）及每个格子的边长（a，格子为正方形），给定物体的2D坐标（pos[x , y]）及半径（r），求解物体在2D地图格子中所占的格子，仅考虑n*n的情况。大概的求解过程如下：  <p>1）根据半径，确定n*n中的n。假定计算公式为：n = Round(2*r / a)  <p>2）根据2D坐标得到物体的“中心格子”。根据n的奇偶，计算公式不同，如下图所示。  <p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_10.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_4.png" width="239" height="244"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_12.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_5.png" width="240" height="244"></a></p> <p align="center">n为偶数[1]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n为奇数[2]</p> <p>[1]：grid(x , y) = Round(pos / a)  <p>[2]：grid(x , y) = Floor(pos / a)  <p>其中，格子坐标x &gt;= 0 , y &gt;= 0。  <p>3）以“中心格子”为基础，求出物体占据的其他格子。这样的描述，让人容易想到递归，就像用深度优先方法遍历树那样，伪代码算法如下：</p> <div style="padding-bottom: 0px; padding-left: 0px; width: 1032px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:866d37ab-87f1-4aea-9d49-b7235fcfb0e9" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">if</span><span style="color: #000000;"> n is even
{
    get the index of </span><span style="color: #800000;">'</span><span style="color: #800000;">center grid</span><span style="color: #800000;">'</span><span style="color: #000000;"> (row , col)
    ExtendHeldGrid(row , col , n)
    ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col , n)
    ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , n)
    ExtendHeldGrid(row , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , n)
}
</span><span style="color: #0000FF;">else</span><span style="color: #000000;">
{
    get the index of </span><span style="color: #800000;">'</span><span style="color: #800000;">center grid</span><span style="color: #800000;">'</span><span style="color: #000000;"> (row , col)
    ExtendHeldGrid(row , col , n)
}

</span><span style="color: #0000FF;">function</span><span style="color: #000000;"> ExtendHeldGrid(row , col , level)
{
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(level </span><span style="color: #000000;">&lt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
        </span><span style="color: #0000FF;">return</span><span style="color: #000000;">

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">((row </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> row </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> MaxGridWidth) </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> (col </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> col </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> MaxGridHeight))
    {
        mark the grid(row , col)
        ExtendHeldGrid(row , col , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
        </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;"> </span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
        {
            ExtendHeldGrid(row </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row , col </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
            ExtendHeldGrid(row </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , col </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> , level </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
        }
    }
}
</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>虽然，该算法得到了正确的求解结果，但是由于每个格子都会标记周围的8个格子，所以存在大量的重复，再者如果上面的过程每帧都进行的话，函数调用开销也是相当可观。</p>
<p>循环自然是不可避免的，消除重复便成了优化的目标。分析格子图和n为2和3的情况，试图找出用循环代替递归的方法，我发现了下面一个有趣的规律：</p>
<p align="center"><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_16.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_7.png" width="239" height="244"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_18.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_8.png" width="240" height="244"></a></p>
<p>从“中心格子”出发，顺时针（或逆时针）以上图方式可以走遍所求解的每个格子而不重复。在实现上，每个转角也是有规律的，可以通过一个2*2的转角矩阵来控制：</p>
<p align="center">[1 , 0][0 , -1]</p>
<p align="center">[0 , 1][-1 , 0]</p>
<p align="center">顺时针方式的转角阵</p>
<p align="left">&nbsp;</p>
<p>矩阵中的每个元素代表从当前格子走到下个格子在row和col上的变化。加之，在转角之间的路长（以格子个数计）有每转两次递增单位1的规律，算法就不难得到了，下面同样以伪代码示：</p>
<div style="padding-bottom: 0px; padding-left: 0px; width: 1032px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:c1053f9b-292c-4f91-b901-a530b31c17c3" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #000000;">conerMat </span><span style="color: #000000;">=</span><span style="color: #000000;"> 
{
    {</span><span style="color: #800080;">0</span><span style="color: #000000;"> , </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">} , 
    {</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;"> , </span><span style="color: #800080;">0</span><span style="color: #000000;">} ,
    {</span><span style="color: #800080;">0</span><span style="color: #000000;">  , </span><span style="color: #800080;">1</span><span style="color: #000000;">} ,
    {</span><span style="color: #800080;">1</span><span style="color: #000000;">  , </span><span style="color: #800080;">0</span><span style="color: #000000;">}
}

dir </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">     </span><span style="color: #000000;">///</span><span style="color: #000000;"> 转角控制，四个转角顺时针0~</span><span style="color: #800080;">3</span><span style="color: #000000;">
span </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">    </span><span style="color: #000000;">///</span><span style="color: #000000;"> 转角间的跨度
count </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">   </span><span style="color: #000000;">///</span><span style="color: #000000;"> 每两次增加一个跨度
rin </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">     </span><span style="color: #000000;">///</span><span style="color: #000000;"> 下一个转角的循环索引

</span><span style="color: #0000FF;">if</span><span style="color: #000000;"> n is even
    get the index of </span><span style="color: #800000;">'</span><span style="color: #800000;">center grid</span><span style="color: #800000;">'</span><span style="color: #000000;"> (row , col)
</span><span style="color: #0000FF;">else</span><span style="color: #000000;">
    get the index of </span><span style="color: #800000;">'</span><span style="color: #800000;">center grid</span><span style="color: #800000;">'</span><span style="color: #000000;"> (row , col)

</span><span style="color: #0000FF;">for</span><span style="color: #000000;">(i </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">; i </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> n </span><span style="color: #000000;">*</span><span style="color: #000000;"> n; </span><span style="color: #000000;">++</span><span style="color: #000000;">i)
{
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">((row </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> row </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> MaxGridWidth) </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> (col </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> col </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> MaxGridHeight))
        mark the grid(row , col)

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(i </span><span style="color: #000000;">==</span><span style="color: #000000;"> rin)
    {
        dir </span><span style="color: #000000;">=</span><span style="color: #000000;"> (dir </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">) </span><span style="color: #000000;">%</span><span style="color: #000000;"> </span><span style="color: #800080;">4</span><span style="color: #000000;">

        </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(count </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #800080;">2</span><span style="color: #000000;">)
        {
            </span><span style="color: #000000;">++</span><span style="color: #000000;">span
            count </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">
        }
        </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
            </span><span style="color: #000000;">++</span><span style="color: #000000;">count

        rin </span><span style="color: #000000;">=</span><span style="color: #000000;"> i </span><span style="color: #000000;">+</span><span style="color: #000000;"> span
    }

    row </span><span style="color: #000000;">=</span><span style="color: #000000;"> row </span><span style="color: #000000;">+</span><span style="color: #000000;"> conerMat[dir][</span><span style="color: #800080;">0</span><span style="color: #000000;">]
    col </span><span style="color: #000000;">=</span><span style="color: #000000;"> col </span><span style="color: #000000;">+</span><span style="color: #000000;"> conerMat[dir][</span><span style="color: #800080;">1</span><span style="color: #000000;">]
}

</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>用MFC程序验证了一下算法的正确性，标号展示了循环的路线（注意GDI的坐标系中Y的正方向朝下）：</p>
<p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_20.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/e7377895b269_9CB8/image_thumb_9.png" width="863" height="510"></a></p><img src ="http://www.cppblog.com/heath/aggbug/141160.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-03-05 13:42 <a href="http://www.cppblog.com/heath/archive/2011/03/05/141160.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对TortoiseSVN的扩展实践</title><link>http://www.cppblog.com/heath/archive/2011/01/23/139190.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 23 Jan 2011 13:55:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2011/01/23/139190.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/139190.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2011/01/23/139190.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/139190.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/139190.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 个人有个需求，希望在update时用颜色高亮出自己感兴趣的文件，目前我只对sln及vcproj文件感兴趣。</p> <p>&nbsp;&nbsp;&nbsp; 首先想到的是用TSVN的hook script(client side)，但仔细研究后发现传入script的参数仅有操作路径，且通过script也不可能访问/修改Notify对话框中的信息和字体颜色。唯一的办法就是修改源代码重新编译，从TSVN官方代码库获取到了trunk source code后，按照根路径下的build.txt文档进行构建（doc\build-zh_CN.txt有些过时了，不要按照该文档进行构建），最新代码需要用到VC++10.0编译，过程中除了hunspell下affixmgr.cxx、hashmgr.cxx和hunspell.cxx三个文件由于svn的编码转换导致文件内容异常外，没什么大问题。</p> <p>&nbsp;&nbsp;&nbsp; TSVN的代码写得很beautiful，这个要赞一下。在清晰的结构下很快对source code进行了分析，发现TSVN的操作处理代码位于src\TortoiseProc下面，而对各种操作的UI反馈主要放在SVNProgressDlg中。找到要修改的地方，添加了几行代码，用NAnt构建后，替换现装版中的对应文件，出现subversion too old问题，点开TortoiseProc.exe发现最新代码中的subversion版本已经用到了1.7.2，而TSVN对外发布的最新版却还是1.6.15，可能是开发者认为跨MinorVersion就算too old了吧。算了，不折腾了，直接拉发布版1.6.12的tag来修改吧。</p> <p>&nbsp;&nbsp;&nbsp; 1.6.12版的source code用VC++9.0编译，按照build文档调整一下与前面构建有差异的地方，值得注意的是TSVN用到了Ribbon，所以必须先安装一下vs2008 sp1补丁。在构建TortoiseProc时，有个头文件中重复声明了MFC中已经定义了的类型，导致构建失败，需要将重复定义之处注释掉。TortoiseProc一出，我的目的就达到了，由于构建的版本与我安装的一致，所以只需替换TortoiseProc.exe，经测试一切OK。</p> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/3869eb50ee51_FB58/test_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="test" border="0" alt="test" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/3869eb50ee51_FB58/test_thumb.png" width="671" height="310"></a> </p> <p>&nbsp;&nbsp;&nbsp; 个人觉得，对TSVN的扩展还是麻烦了一点，整个构建过程花费了大量时间，建议增强hook script。</p><img src ="http://www.cppblog.com/heath/aggbug/139190.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2011-01-23 21:55 <a href="http://www.cppblog.com/heath/archive/2011/01/23/139190.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用Android手机的Recovery模式Downgrade &amp;amp; Jailbreak PS3</title><link>http://www.cppblog.com/heath/archive/2010/12/25/137418.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 25 Dec 2010 04:34:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/12/25/137418.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/137418.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/12/25/137418.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/137418.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/137418.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 从HK买来一台白色slim已经好几个月了，一直玩碟子和下载游戏，系统保持在3.5。周末到电子市场逛，看看二手碟子价格，随便也甩了手上收藏价值不大的游戏。从几个JS处得知现在他们都已经不进新碟了，收二手的也就几十块钱。郁闷了回家，决定让小白JB了。印象中似乎JB代码已经开源，而且有人已经把它放在Android手机上了，在网上搜索了一下，可以用psfServiceMod刷Recovery来很方便的实现DG&amp;JB，下面是摘自制作者博客（<a href="http://www.klutsh.com">www.klutsh.com</a>）上手机支持列表：</p> <h4>psfServiceMod Recovery Images</h4> <p><a href="http://www.klutsh.com/download/63/">Commtivia Z71 - 0.3.1</a> <small>» 3.7 MiB - 55 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/68/">HTC Aria - 0.3.1</a> <small>» 3.8 MiB - 35 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/52/">HTC Desire (CDMA) - 0.3.1</a> <small>» 3.4 MiB - 74 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/51/">HTC Desire (GSM) - 0.3.1</a> <small>» 3.4 MiB - 381 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/50/">HTC Desire HD - 0.3.1</a> <small>» 4.2 MiB - 166 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/67/">HTC Desire Z (G2) - 0.3.1</a> <small>» 4.3 MiB - 55 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/57/">HTC Dream/Sapphire (32B) - 0.3.1</a> <small>» 3.3 MiB - 156 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/62/">HTC Droid Eris - 0.3.1</a> <small>» 3.4 MiB - 39 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/86/">HTC Droid Incredible - 0.3.2</a> <small>» 3.6 MiB - 75 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/75/">HTC Evo 4G - 0.3.1</a> <small>» 3.4 MiB - 109 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/61/">HTC Hero (CDMA) - 0.3.1</a> <small>» 3.4 MiB - 75 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/59/">HTC Hero (GSM) - 0.3.1</a> <small>» 3.4 MiB - 94 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/79/">HTC Magic/Sapphire (32A) - 0.3.1</a> <small>» 3.4 MiB - 73 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/84/">HTC Tattoo - 0.3.1</a> <small>» 3.2 MiB - 77 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/53/">HTC Wildfire - 0.3.1</a> <small>» 3.6 MiB - 140 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/73/">Motorola Droid - 0.3.1</a> <small>» 3.4 MiB - 132 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/66/">Nexus One - 0.3.1</a> <small>» 3.4 MiB - 122 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/85/">T-Mobile myTouch 3G Slide - 0.3.1</a> <small>» 3.8 MiB - 34 hits - December 21, 2010<br></small> <p><a href="http://www.klutsh.com/download/58/">T-Mobile myTouch 4G - 0.3.1</a> <small>» 4.3 MiB - 30 hits - December 21, 2010</small><small></p></small> <p>&nbsp;&nbsp;&nbsp; 笔者用的HTC Magic(32A)也在其中，于是用fastboot的USB方式（关机后按Power+Return进入后接上USB至PC，当然PC必须安装Driver）刷了Recovery。进入Recovery模式（关机后按Power+Home），断开USB连接，选择"PSFreedom settings"进入发现用于DG的"Put PS3 in Service Mode"、用于JB的"Jailbreak FW 3.41"、以及从SD卡加载Payload的功能项一应俱全。</p> <p><small><a href="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/AndroidRecoveryJailbreak-PS3_9D67/psfServiceMod_2.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="psfServiceMod" border="0" alt="psfServiceMod" src="http://www.cppblog.com/images/cppblog_com/heath/Windows-Live-Writer/AndroidRecoveryJailbreak-PS3_9D67/psfServiceMod_thumb.jpg" width="484" height="292"></a></small></p> <p>&nbsp;&nbsp;&nbsp; 剩下的就和用Dog一样的操作方式来DG&amp;JB了，值得注意的是操作时都需要接在右边USB口上（JB操作提示是接在左边）：</p> <li>DG操作 </li> <p>&nbsp;&nbsp;&nbsp; 1）关闭PS3并切断电源，选择"Put PS3 in Service Mode"进入；</p> <p>&nbsp;&nbsp;&nbsp; 2）将手机连接至PS3右边USB口；</p> <p>&nbsp;&nbsp;&nbsp; 3）打开PS3电源，按开机键后迅速按出仓键；</p> <p>&nbsp;&nbsp;&nbsp; 4）手柄连接主机重新配对后，PS3进入Factory/Service Mode，关闭PS3；</p> <p>&nbsp;&nbsp;&nbsp; 5）找一个U盘（只要是PS3识别的FAT/FAT32格式，未必需格式化）插上PC，解压3.41修改版固件，有三个文件夹：“Lv2diag.self FILE 1”，“Lv2diag.self FILE 2”和“Modified 3.41 PUP”。 将Lv2diag.self FILE 1中的Lv2diag.self以及Modified 3.41 PUP中的PS3UPDAT.PUP拷贝到U盘根目录；</p> <p>&nbsp;&nbsp;&nbsp; 6）拔下U盘插入PS3右边的USB口，打开PS3，屏幕没有任何显示，PS3主机的硬盘灯和U盘的指示灯会闪烁，等待大约3分钟直到PS3电源绿灯闪烁并自动关机；</p> <p>&nbsp;&nbsp;&nbsp; 7）拔下U盘，PS3正常开机，仍在服务模式，确认系统信息已经变成3.41。（如需继续降级到更低系统版本，勿删除U盘上的Lv2diag.self，将其它系统版本PS3UPDATE.PUP放入U盘，重新执行一遍步骤6）。若不需继续降级，关闭PS3电源；</p> <p>&nbsp;&nbsp;&nbsp; 8）在PC上，删除U盘中的Lv2diag.self和PS3UPDAT.PUP两个文件，把Lv2diag.self FILE 2文件夹中的Lv2diag.self拷贝到U盘根目录。将U盘插上PS3并开机，仍然黑屏，等待10秒后会自动关机。再开机，会出现重新连接手柄、新建用户的初始开机画面，完成设置后进入系统信息查看，已是普通的3.41系统了，降级步骤全部完成。</p> <li>JB操作 </li> <p>&nbsp;&nbsp;&nbsp; 1）关闭PS3并切断电源，选择"Jailbreak FW 3.41"进入；</p> <p>&nbsp;&nbsp;&nbsp; 2）将手机连接至PS3右边USB口；</p> <p>&nbsp;&nbsp;&nbsp; 3）打开PS3电源，按开机键后迅速按出仓键；</p> <p>&nbsp;&nbsp;&nbsp; 4）确认JB成功与否，查看Game下面是否多了两个新菜单项；</p> <p>&nbsp;&nbsp;&nbsp; 5）之后就可以到<a href="http://www.ps3-hacks.com/downloads.php" target="_blank">PS3-Hacks</a>去下载BackupManager/OpenManager了。</p> <p>&nbsp;&nbsp;&nbsp; 其实JB就是让PS3进入Debug模式，一旦进入后便可移除JB设备。PS3刚JB那会儿，BackupManager是必备工具，后面出的Manager都是在其基础上增强，OpenManager比BackupManager多了从外接硬盘copy/play game的功能。此外Gaia manager也是个很受欢迎的Manager，除了在UI上比OpenManager好看之外，还加入了Direct Boot/FTP Server等功能，但Direct Boot并不是那么好使，比如《忍者龙剑传 Sigma2》用Gaia就花屏死机，用OM就不会，总体感觉还是OM更稳定。</p> <p>Reference</p> <p><small></small><small><em>[1] <a title="http://www.klutsh.com" href="http://www.klutsh.com">http://www.klutsh.com</a></em></small></p> <p><small></small><small><em>[2] <a title="http://www.ps3-hacks.com/" href="http://www.ps3-hacks.com/">http://www.ps3-hacks.com/</a></em></small></p> <p><small></small><small><em>[3] <a href="http://depressme.com/?p=12" target="_blank">Simple Tutorial on How to Downgrade and Jailbreak your PS3 with PsfServiceMod</a></em></small></p> <p><small></small><small><em>[4] <a title="http://ps3.cngba.com/ps3_xw/20101215119290.shtml" href="http://ps3.cngba.com/ps3_xw/20101215119290.shtml">http://ps3.cngba.com/ps3_xw/20101215119290.shtml</a></em></small></p><img src ="http://www.cppblog.com/heath/aggbug/137418.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-12-25 12:34 <a href="http://www.cppblog.com/heath/archive/2010/12/25/137418.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows下Perforce Command Line处理中文参数的两种方法</title><link>http://www.cppblog.com/heath/archive/2010/11/15/133692.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Mon, 15 Nov 2010 09:58:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/11/15/133692.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/133692.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/11/15/133692.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/133692.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/133692.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; Windows下Command Line中的中文字符是采用ANSI编码来处理的，而Perforce command line要求传入的中文参数（文件（夹）名）为UTF-8编码，所以需要将中文参数转换为UTF-8后再做处理，下面介绍两种处理方法。</p> <p>一、系统调用</p> <p>&nbsp;&nbsp;&nbsp; 通过使用WinExec、ShellExecute或system，如：</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:a202efe8-f955-49cf-8f11-16a2b3b1f36b" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #008080;">_snprintf</span><span style="color: #000000;">(cmdbuf , </span><span style="color: #800080;">1024</span><span style="color: #000000;"> , </span><span style="color: #800000;">"</span><span style="color: #800000;">p4 -c %s add \</span><span style="color: #800000;">"</span><span style="color: #000000;">%</span><span style="color: #000000;">s\</span><span style="color: #800000;">""</span><span style="color: #000000;"> , argv[</span><span style="color: #800080;">1</span><span style="color: #000000;">] , ANSIToUTF8(path.c_str()));
system(cmdbuf);</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>&nbsp;&nbsp;&nbsp; 此方法的虽然简单，但存在效率问题，因为有创建进程的巨大开销。此外不同版本的Perforce也会出现不同的执行结果，针对特定的中文会出现操作失败的诡异问题。</p>
<p>二、Perforce SDK</p>
<p>&nbsp;&nbsp;&nbsp; Perforce提供有SDK用以扩展或集成到其他应用中，虽然没有详细的文档，但可以通过学习SDK中的sample文件来学习，此方法最稳定。</p>
<p>&nbsp;&nbsp;&nbsp; 下面代码展示了通过SDK中ClientAPI来递归添加指定文件夹下的所有文件：</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:891e1b70-295a-4daf-9c0d-8f0ad2ef8b07" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #800000;">"</span><span style="color: #800000;">clientapi.h</span><span style="color: #800000;">"</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #800000;">"</span><span style="color: #800000;">i18napi.h</span><span style="color: #800000;">"</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #800000;">"</span><span style="color: #800000;">CharSetConvertUtil.h</span><span style="color: #800000;">"</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">vector</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">list</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">
</span><span style="color: #000000;">#</span><span style="color: #000000;"> include </span><span style="color: #000000;">&lt;</span><span style="color: #000000;">io.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">

using namespace std;

</span><span style="color: #000000;">//</span><span style="color: #000000;"> structure to hold a directory </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> all its filenames.
struct FILELIST
{
    string path;
    vector</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> theList;
};


void TransverseDirectory(string path, list</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FILELIST</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&amp; theList)
{
    struct </span><span style="color: #008080;">_finddatai</span><span style="color: #000000;">64</span><span style="color: #008080;">_t</span><span style="color: #000000;"> data;
    string fname </span><span style="color: #000000;">=</span><span style="color: #000000;"> path </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">\\*.*</span><span style="color: #800000;">"</span><span style="color: #000000;">;
    long h </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #008080;">_findfirsti</span><span style="color: #800080;">64</span><span style="color: #000000;">(fname.c_str(),&amp;data);
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(h </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
    {
        FILELIST thisList;
        theList.push_back(thisList);
        list</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FILELIST</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator it </span><span style="color: #000000;">=</span><span style="color: #000000;"> theList.</span><span style="color: #0000FF;">end</span><span style="color: #000000;">();
        it</span><span style="color: #008000;">--</span><span style="color: #008000;">;</span><span style="color: #008000;">
</span><span style="color: #000000;">
        (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).path </span><span style="color: #000000;">=</span><span style="color: #000000;"> path;
        </span><span style="color: #0000FF;">do</span><span style="color: #000000;"> {
            </span><span style="color: #0000FF;">if</span><span style="color: #000000;">( (data.attrib &amp; </span><span style="color: #008080;">_A_SUBDIR</span><span style="color: #000000;">) )
            {
                </span><span style="color: #000000;">//</span><span style="color: #000000;"> make sure we skip </span><span style="color: #800000;">"</span><span style="color: #800000;">.</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">..</span><span style="color: #800000;">"</span><span style="color: #000000;">.  Have to use strcmp here because
                </span><span style="color: #000000;">//</span><span style="color: #000000;"> some file names can start with a dot, so just testing </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> the
                </span><span style="color: #000000;">//</span><span style="color: #000000;"> first dot is </span><span style="color: #0000FF;">not</span><span style="color: #000000;"> suffient.
                </span><span style="color: #0000FF;">if</span><span style="color: #000000;">( strcmp(data.name,</span><span style="color: #800000;">"</span><span style="color: #800000;">.</span><span style="color: #800000;">"</span><span style="color: #000000;">) !</span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> &amp;&amp;strcmp(data.name,</span><span style="color: #800000;">"</span><span style="color: #800000;">..</span><span style="color: #800000;">"</span><span style="color: #000000;">) !</span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
                {
                    </span><span style="color: #000000;">//</span><span style="color: #000000;"> We found a sub</span><span style="color: #000000;">-</span><span style="color: #000000;">directory, so get the files </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> it too
                    fname </span><span style="color: #000000;">=</span><span style="color: #000000;"> path </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">\\</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> data.name;
                    </span><span style="color: #000000;">//</span><span style="color: #000000;"> recurrsion here!
                    TransverseDirectory(fname,theList);
                }

            }
            </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
            {
                </span><span style="color: #000000;">//</span><span style="color: #000000;"> this is just a normal filename.  So just add it to our vector
                (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).theList.push_back(data.name);

            }
        }</span><span style="color: #0000FF;">while</span><span style="color: #000000;">( </span><span style="color: #008080;">_findnexti</span><span style="color: #800080;">64</span><span style="color: #000000;">(h,&amp;data) </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">);
        </span><span style="color: #008080;">_findclose</span><span style="color: #000000;">(h);

    }
}

int main( int argc, char </span><span style="color: #000000;">**</span><span style="color: #000000;">argv )
{
    list</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FILELIST</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> MyList;
    string path;
    ClientUser ui;
    ClientApi client;
    StrBuf msg;
    Error e;

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(argc </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> </span><span style="color: #800080;">4</span><span style="color: #000000;">)
    {
        fprintf( stderr , </span><span style="color: #800000;">"</span><span style="color: #800000;">P4 Transverse Add: Arguments Error!\n</span><span style="color: #800000;">"</span><span style="color: #000000;">);
        </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">;
    }

    client.SetPort(argv[</span><span style="color: #800080;">1</span><span style="color: #000000;">]);
    client.SetClient(argv[</span><span style="color: #800080;">2</span><span style="color: #000000;">]);
    client.SetTrans(CharSetApi::UTF_8 , CharSetApi::UTF_8 , 
        CharSetApi::UTF_8,
        CharSetApi::UTF_8);

    TransverseDirectory(argv[</span><span style="color: #800080;">3</span><span style="color: #000000;">],MyList);

    </span><span style="color: #000000;">//</span><span style="color: #000000;"> Connect to server
    client.Init( &amp;e );

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">( e.Test() )
    {
        e.Fmt( &amp;msg );
        fprintf( stderr, </span><span style="color: #800000;">"</span><span style="color: #800000;">%s\n</span><span style="color: #800000;">"</span><span style="color: #000000;">, msg.Text() );
        </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">;
    }

    list</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">FILELIST</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator it;
    </span><span style="color: #0000FF;">for</span><span style="color: #000000;">(it </span><span style="color: #000000;">=</span><span style="color: #000000;"> MyList.begin(); it !</span><span style="color: #000000;">=</span><span style="color: #000000;"> MyList.</span><span style="color: #0000FF;">end</span><span style="color: #000000;">(); it</span><span style="color: #000000;">++</span><span style="color: #000000;">)
    {
        vector</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::iterator its;
        </span><span style="color: #0000FF;">for</span><span style="color: #000000;">(its </span><span style="color: #000000;">=</span><span style="color: #000000;"> (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).theList.begin(); its !</span><span style="color: #000000;">=</span><span style="color: #000000;"> (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).theList.</span><span style="color: #0000FF;">end</span><span style="color: #000000;">(); its</span><span style="color: #000000;">++</span><span style="color: #000000;">)
        {
            path </span><span style="color: #000000;">=</span><span style="color: #000000;"> (</span><span style="color: #000000;">*</span><span style="color: #000000;">it).path </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">\\</span><span style="color: #800000;">"</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;">its);
            char</span><span style="color: #000000;">*</span><span style="color: #000000;"> pText </span><span style="color: #000000;">=</span><span style="color: #000000;"> ANSIToUTF8(path.c_str());
            client.SetArgv( </span><span style="color: #800080;">1</span><span style="color: #000000;"> , &amp;pText);
            client.Run( </span><span style="color: #800000;">"</span><span style="color: #800000;">add</span><span style="color: #800000;">"</span><span style="color: #000000;"> , &amp;ui );
        }
    }

    </span><span style="color: #000000;">//</span><span style="color: #000000;"> Close connection
    client.Final( &amp;e );

    </span><span style="color: #0000FF;">if</span><span style="color: #000000;">( e.Test() )
    {
        e.Fmt( &amp;msg );
        fprintf( stderr, </span><span style="color: #800000;">"</span><span style="color: #800000;">%s\n</span><span style="color: #800000;">"</span><span style="color: #000000;">, msg.Text() );
        </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">;
    }
    
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;
}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>&nbsp;&nbsp;&nbsp; 此方法省去了创建p4进程的开销，任务执行效率会提高不少，而且也不会出现执行结果不稳定的问题。&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;</p>
<p>附一：SDK下载地址</p>
<p><a title="ftp://ftp.perforce.com/perforce/" href="ftp://ftp.perforce.com/perforce/">ftp://ftp.perforce.com/perforce/</a></p>
<p>附二：附上ANSI转UTF-8代码</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:de1a1357-3f18-424a-bec7-b29768d70f5f" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #000000;">
wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;"> ANSIToUnicode( const char</span><span style="color: #000000;">*</span><span style="color: #000000;"> str )
{
    int    textlen ;
    wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;"> result;
    textlen </span><span style="color: #000000;">=</span><span style="color: #000000;"> MultiByteToWideChar( CP_ACP, </span><span style="color: #800080;">0</span><span style="color: #000000;">, str,</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,    NULL,</span><span style="color: #800080;">0</span><span style="color: #000000;"> );  
    result </span><span style="color: #000000;">=</span><span style="color: #000000;"> (wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;">)malloc((textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(wchar_t));  
    memset(result,</span><span style="color: #800080;">0</span><span style="color: #000000;">,(textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(wchar_t));  
    MultiByteToWideChar(CP_ACP, </span><span style="color: #800080;">0</span><span style="color: #000000;">,str,</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,(LPWSTR)result,textlen );  
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;">    result;  
}

char</span><span style="color: #000000;">*</span><span style="color: #000000;"> UnicodeToANSI( const wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;">str )
{
    char </span><span style="color: #000000;">*</span><span style="color: #000000;"> result;
    int textlen;
    </span><span style="color: #000000;">//</span><span style="color: #000000;"> wide char to multi char
    textlen </span><span style="color: #000000;">=</span><span style="color: #000000;"> WideCharToMultiByte( CP_ACP,    </span><span style="color: #800080;">0</span><span style="color: #000000;">,    str,    </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,    NULL, </span><span style="color: #800080;">0</span><span style="color: #000000;">, NULL, NULL );
    result </span><span style="color: #000000;">=</span><span style="color: #000000;">(char </span><span style="color: #000000;">*</span><span style="color: #000000;">)malloc((textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(char));
    memset( result, </span><span style="color: #800080;">0</span><span style="color: #000000;">, sizeof(char) </span><span style="color: #000000;">*</span><span style="color: #000000;"> ( textlen </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> ) );
    WideCharToMultiByte( CP_ACP, </span><span style="color: #800080;">0</span><span style="color: #000000;">, str, </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">, result, textlen, NULL, NULL );
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> result;
}

wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;"> UTF8ToUnicode( const char</span><span style="color: #000000;">*</span><span style="color: #000000;"> str )
{
    int    textlen ;
    wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;"> result;
    textlen </span><span style="color: #000000;">=</span><span style="color: #000000;"> MultiByteToWideChar( CP_UTF8, </span><span style="color: #800080;">0</span><span style="color: #000000;">, str,</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,    NULL,</span><span style="color: #800080;">0</span><span style="color: #000000;"> );  
    result </span><span style="color: #000000;">=</span><span style="color: #000000;"> (wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;">)malloc((textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(wchar_t));  
    memset(result,</span><span style="color: #800080;">0</span><span style="color: #000000;">,(textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(wchar_t));  
    MultiByteToWideChar(CP_UTF8, </span><span style="color: #800080;">0</span><span style="color: #000000;">,str,</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,(LPWSTR)result,textlen );  
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;">    result;  
}

char</span><span style="color: #000000;">*</span><span style="color: #000000;"> UnicodeToUTF8( const wchar_t </span><span style="color: #000000;">*</span><span style="color: #000000;">str )
{
    char </span><span style="color: #000000;">*</span><span style="color: #000000;"> result;
    int textlen;
    </span><span style="color: #000000;">//</span><span style="color: #000000;"> wide char to multi char
    textlen </span><span style="color: #000000;">=</span><span style="color: #000000;"> WideCharToMultiByte( CP_UTF8,    </span><span style="color: #800080;">0</span><span style="color: #000000;">,    str,    </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">,    NULL, </span><span style="color: #800080;">0</span><span style="color: #000000;">, NULL, NULL );
    result </span><span style="color: #000000;">=</span><span style="color: #000000;">(char </span><span style="color: #000000;">*</span><span style="color: #000000;">)malloc((textlen</span><span style="color: #000000;">+</span><span style="color: #800080;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">*</span><span style="color: #000000;">sizeof(char));
    memset(result, </span><span style="color: #800080;">0</span><span style="color: #000000;">, sizeof(char) </span><span style="color: #000000;">*</span><span style="color: #000000;"> ( textlen </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;"> ) );
    WideCharToMultiByte( CP_UTF8, </span><span style="color: #800080;">0</span><span style="color: #000000;">, str, </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">, result, textlen, NULL, NULL );
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> result;
}

char</span><span style="color: #000000;">*</span><span style="color: #000000;"> ANSIToUTF8(const char</span><span style="color: #000000;">*</span><span style="color: #000000;"> str)
{
    wchar_t</span><span style="color: #000000;">*</span><span style="color: #000000;"> pUnicodeBuff </span><span style="color: #000000;">=</span><span style="color: #000000;"> ANSIToUnicode(str);
    char</span><span style="color: #000000;">*</span><span style="color: #000000;"> pUtf8Buff </span><span style="color: #000000;">=</span><span style="color: #000000;"> UnicodeToUTF8(pUnicodeBuff);
    free(pUnicodeBuff);

    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> pUtf8Buff;
}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div><img src ="http://www.cppblog.com/heath/aggbug/133692.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-11-15 17:58 <a href="http://www.cppblog.com/heath/archive/2010/11/15/133692.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>&amp;quot;Inception&amp;quot; 简评</title><link>http://www.cppblog.com/heath/archive/2010/09/05/125961.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 05 Sep 2010 15:02:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/09/05/125961.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/125961.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/09/05/125961.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/125961.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/125961.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 不愧为“天才导演”，Nolan选取了人们很少关注的梦境作为题材，利用梦中梦的递归手法拓宽了时空感，让观众觉得影片很有嚼头。影片首尾呼应，中间以入侵目标梦境并植入一个想法为主线，递归深度达到了4层，可见导演的用心之处。期间还穿插着一条支线，那就是柯布的梦境，这一直是他的痛，直到故事最后，他才释怀。</p> <p>&nbsp;&nbsp;&nbsp; 心理学为该影片了理论基础，盗梦的目的就是为了窥探目标埋藏在心里的秘密，因为梦是伪装得最少的潜意识表现。而作为进入目标梦境的工具，导演却是一笔带过，不得不说是一个遗憾，因而该影片也就成了一部纯科幻电影。</p> <p>&nbsp;&nbsp;&nbsp; 观影毕，个人感觉Dream Design应该也和Game Design相似吧：故事、人物、时间、场景的设计。Programmer也深刻地温习了一下递归吧。</p> <p>&nbsp;</p> <p>B.T.W. 多年以来，能够撼动我思想的影片仅有两部："The Matrix"和"Inception"。</p> <p>&nbsp;</p> <p><a href="http://www.cppblog.com/images/cppblog_com/heath/WindowsLiveWriter/Inception_13B82/Inception_2.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Inception" border="0" alt="Inception" src="http://www.cppblog.com/images/cppblog_com/heath/WindowsLiveWriter/Inception_13B82/Inception_thumb.jpg" width="409" height="570"></a></p><img src ="http://www.cppblog.com/heath/aggbug/125961.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-09-05 23:02 <a href="http://www.cppblog.com/heath/archive/2010/09/05/125961.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Kindle DXG</title><link>http://www.cppblog.com/heath/archive/2010/08/21/124193.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 21 Aug 2010 08:44:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/08/21/124193.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/124193.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/08/21/124193.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/124193.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/124193.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; Amazon在7月7日发布了代号为Graphite的Kindle DX，同时全面下调kindle 2和kindle DX的价格。原计划等IPad在HK上市后去那边买的，后来考虑到仅用于看电子书，还是E-INK屏比较好，正好9.7寸屏的Kindle DXG也落到了心理价位，于是决定入手之。 7月9日下单，期间遇上了海关严打，货被扣了2周后交税放行，7月30日到手。使用近一个月，总体来讲还不错：</p> <p>1）Free 3G速度快，看新闻方便；</p> <p>2）分辨率高，字体清晰；</p> <p>2）Native PDF Support，翻页速度已经很快了，对于内嵌中文字体也有很好地支持。看PDF文档时，9.7寸屏比6寸屏更易于阅读。Zoom功能近乎鸡肋，因为很不喜欢拉着滚动条阅读，看扫描书的时候顶多用一下横屏。此外，由于Kindle会把颜色转换为灰度，所以对于非纯色的文字，会显得很淡。</p> <p>3）由于Amazon将Mobipocket收归旗下的缘故，所以对mobi/prc文件格式的支持和azw格式一样好，提供指译、字体缩放、注释/笔记等功能；</p> <p>4）通过Gift Card的方式购买电子书也挺方便，免去了买纸质书的运费和运输延迟。不过技术书的电子版本很少，且价格昂贵；</p> <p>5）待机时间长，这是E-INK阅读器的一大优势；</p> <p>6）加上原装皮套，重量和一本A4 600页左右的书差不多。</p> <p>&nbsp;&nbsp;&nbsp; 对于电子书转换工具，个人推荐：Mobipocket和Calibre（仅Mac OS）。后者是开源的，功能和输出文件质量胜于前者。</p> <p><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/WindowsLiveWriter/KindleDXG_DFA1/image_3.png" width="804" height="604"></p> <p><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/WindowsLiveWriter/KindleDXG_DFA1/image_6.png" width="804" height="604"> </p> <p><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/WindowsLiveWriter/KindleDXG_DFA1/image_9.png" width="804" height="604"> </p> <p><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/heath/WindowsLiveWriter/KindleDXG_DFA1/image_12.png" width="804" height="604"></p><img src ="http://www.cppblog.com/heath/aggbug/124193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-08-21 16:44 <a href="http://www.cppblog.com/heath/archive/2010/08/21/124193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CruiseControl.NET for CI in Game development</title><link>http://www.cppblog.com/heath/archive/2010/08/09/122834.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Mon, 09 Aug 2010 12:22:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/08/09/122834.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/122834.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/08/09/122834.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/122834.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/122834.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 有个项目使用了CruiseControl.NET（以下简称CC.NET）作为持续集成工具，周末抽空研究了一下，发现这款由<b>ThoughtWorks</b>贡献的开源工具功能非常强大，主要体现在下面三个方面：</p> <p>1）灵活、高可配置性，如：多重组合条件触发、多任务队列策略；  <p>2）兼容目前几乎所有的流行SCM工具，使得多种异构系统能够由CruiseControl.NET统一监控和管理；  <p>3）完善的使用文档，使上手和维护变得容易；  <p>&nbsp;&nbsp;&nbsp; 而该项目引以自豪的代码check in触发构建的功能通过CC.NET也很容易实现。之前使用过Hudson，该系统采用主从式架构，使用者通过网页让Master控制Slave动作，由于Master由别的部门管理，出问题后需要联系相关人解决，会有一定的处理延迟，而且安装在构建机上的Slave服务经常崩溃。而CC.NET直接安装在构建机上，配置IIS后可通过网页直接访问，操作维护都较前者容易。由于之前的构建脚本是用VisualBuild实现的，所以不可能再花时间用CC.NET再写一遍。而通过实验得知，其实CC.NET能够以ExecutableTask的形式很好地与VisualBuild集成，目前每小时定时构建、NightBuild和构建成功后触发的自动测试都已经放到了CC.NET上了。  <p>&nbsp;&nbsp;&nbsp; ccnet.config Example: </p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:50b99a40-bc5a-4f79-b1ff-e2e4471bf333" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">cruisecontrol </span><span style="color: #FF0000;">xmlns:cb</span><span style="color: #0000FF;">="urn:ccnet.config.builder"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">queue </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="Q1"</span><span style="color: #FF0000;"> duplicates</span><span style="color: #0000FF;">="ApplyForceBuildsReAdd"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">queue </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="Q2"</span><span style="color: #FF0000;"> duplicates</span><span style="color: #0000FF;">="ApplyForceBuildsReAdd"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">project </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="AgileBuild"</span><span style="color: #FF0000;"> queue</span><span style="color: #0000FF;">="Q1"</span><span style="color: #FF0000;"> queuePriority</span><span style="color: #0000FF;">="1"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">AutoBuild</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">filterTrigger </span><span style="color: #FF0000;">startTime</span><span style="color: #0000FF;">="18:00"</span><span style="color: #FF0000;"> endTime</span><span style="color: #0000FF;">="10:00"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">trigger </span><span style="color: #FF0000;">type</span><span style="color: #0000FF;">="intervalTrigger"</span><span style="color: #FF0000;"> name</span><span style="color: #0000FF;">="Continuous"</span><span style="color: #FF0000;"> seconds</span><span style="color: #0000FF;">="1800"</span><span style="color: #FF0000;"> buildCondition</span><span style="color: #0000FF;">="ForceBuild"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDays</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Monday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Tuesday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Wednesday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Thursday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Friday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDays</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">filterTrigger</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">VisBuildCmd.exe</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">E:\GAMEDev\AgileBuilder.bld</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">D:\VisBuildPro7</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">3000</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">project</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">project </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="NightBuild"</span><span style="color: #FF0000;"> queue</span><span style="color: #0000FF;">="Q2"</span><span style="color: #FF0000;"> queuePriority</span><span style="color: #0000FF;">="1"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">AutoBuild</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">scheduleTrigger </span><span style="color: #FF0000;">time</span><span style="color: #0000FF;">="23:00"</span><span style="color: #FF0000;"> buildCondition</span><span style="color: #0000FF;">="ForceBuild"</span><span style="color: #FF0000;"> name</span><span style="color: #0000FF;">="Scheduled"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDays</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Monday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Tuesday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Wednesday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Thursday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
          </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Friday</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDay</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">weekDays</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">scheduleTrigger</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">      
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">  
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">VisBuildCmd.exe</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">"BUILD_OPTION=clientworldeffect" "PACK_TYPE=RAR" E:\GAMEDev\NightBuilder.bld</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">D:\VisBuildPro7</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">0</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">project</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">project </span><span style="color: #FF0000;">name</span><span style="color: #0000FF;">="NightAutoTest"</span><span style="color: #FF0000;"> queue</span><span style="color: #0000FF;">="Q2"</span><span style="color: #FF0000;"> queuePriority</span><span style="color: #0000FF;">="2"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">AutoTest</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">category</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">projectTrigger </span><span style="color: #FF0000;">serverUri</span><span style="color: #0000FF;">="tcp://heath-builder:21234/CruiseManager.rem"</span><span style="color: #FF0000;"> project</span><span style="color: #0000FF;">="NightBuild"</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">triggerStatus</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">Success</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">triggerStatus</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">innerTrigger </span><span style="color: #FF0000;">type</span><span style="color: #0000FF;">="intervalTrigger"</span><span style="color: #FF0000;"> seconds</span><span style="color: #0000FF;">="60"</span><span style="color: #FF0000;"> buildCondition</span><span style="color: #0000FF;">="ForceBuild"</span><span style="color: #FF0000;"> </span><span style="color: #0000FF;">/&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">projectTrigger</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">triggers</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">VisBuildCmd.exe</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">executable</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">E:\GAMEDev\AutoTest.bld</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildArgs</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">D:\VisBuildPro7</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">baseDirectory</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">&lt;</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">0</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">buildTimeoutSeconds</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
      </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">exec</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">tasks</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
  </span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">project</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">  
</span><span style="color: #0000FF;">&lt;/</span><span style="color: #800000;">cruisecontrol</span><span style="color: #0000FF;">&gt;</span><span style="color: #000000;">
</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>References 
<p>[1] <a href="http://cruisecontrol.sourceforge.net/">http://cruisecontrol.sourceforge.net/</a> 
<p>[2] <a href="http://www.kinook.com/VisBuildPro/">http://www.kinook.com/VisBuildPro/</a></p><img src ="http://www.cppblog.com/heath/aggbug/122834.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-08-09 20:22 <a href="http://www.cppblog.com/heath/archive/2010/08/09/122834.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lua Inside</title><link>http://www.cppblog.com/heath/archive/2010/07/18/120686.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 18 Jul 2010 04:46:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/07/18/120686.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/120686.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/07/18/120686.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/120686.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/120686.html</trackback:ping><description><![CDATA[<p>一、Table</p> <p>&nbsp;&nbsp;&nbsp; Table实际上是数组和哈希表的混合体。当保存以连续整数为索引的内容时，使用数组结构；而对于离散索引及键值对，则使用哈希表存储。这样做对于空间节省和查找效率都是有好处的，举例：</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:ad251ceb-f44d-43f6-b5e5-adefe5155df8" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #000000;">tt </span><span style="color: #000000;">=</span><span style="color: #000000;"> {</span><span style="color: #800000;">"</span><span style="color: #800000;">a</span><span style="color: #800000;">"</span><span style="color: #000000;"> , </span><span style="color: #800000;">"</span><span style="color: #800000;">b</span><span style="color: #800000;">"</span><span style="color: #000000;"> , </span><span style="color: #800000;">"</span><span style="color: #800000;">c</span><span style="color: #800000;">"</span><span style="color: #000000;">}
</span><span style="color: #FF00FF;">print</span><span style="color: #000000;">(</span><span style="color: #000000;">#</span><span style="color: #000000;">tt)  </span><span style="color: #008000;">--</span><span style="color: #008000;">&gt; 3</span><span style="color: #008000;">
</span><span style="color: #000000;">tt[</span><span style="color: #800080;">100</span><span style="color: #000000;">] </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">d</span><span style="color: #800000;">"</span><span style="color: #000000;">
</span><span style="color: #FF00FF;">print</span><span style="color: #000000;">(</span><span style="color: #000000;">#</span><span style="color: #000000;">tt)    </span><span style="color: #008000;">--</span><span style="color: #008000;">&gt; 3 (100-"d"键值对放入哈希表)</span><span style="color: #008000;">
</span><span style="color: #000000;">tt[</span><span style="color: #800080;">4</span><span style="color: #000000;">] </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">e</span><span style="color: #800000;">"</span><span style="color: #000000;">
</span><span style="color: #FF00FF;">print</span><span style="color: #000000;">(</span><span style="color: #000000;">#</span><span style="color: #000000;">tt)    </span><span style="color: #008000;">--</span><span style="color: #008000;">&gt; 4</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>二、Closure</p>
<p>&nbsp;&nbsp;&nbsp; Lua的变量引用规则造成了闭包的出现，在Lua中一个复杂数据结构（table、function）被赋予一个变量时，变量仅仅拿取其引用。试考虑下面代码片段：</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:598ca59b-1a84-48fd-810b-febaec375c78" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">local</span><span style="color: #000000;"> f1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">function</span><span style="color: #000000;">() ... </span><span style="color: #0000FF;">end</span><span style="color: #000000;">
</span><span style="color: #0000FF;">local</span><span style="color: #000000;"> f2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">function</span><span style="color: #000000;">() ... </span><span style="color: #0000FF;">end</span><span style="color: #000000;">
</span><span style="color: #0000FF;">local</span><span style="color: #000000;"> f3 </span><span style="color: #000000;">=</span><span style="color: #000000;"> f1</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>&nbsp;&nbsp;&nbsp; 判断f1与f2是否相等，得到的结果为假，而f3与f1则为真。这是因为f1与f2引用了两个不同的函数chunk（也可称为“定义”），而f1直接将其引用（可以看成C/C++中的地址）赋给f3，故而相等。<br>理解了上面问题，再看看下面的一个函数：</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:d3dec4b2-08d0-47d8-9ad3-a178ba2d3858" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">function</span><span style="color: #000000;"> createCounter()
    </span><span style="color: #0000FF;">local</span><span style="color: #000000;"> x </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #0000FF;">function</span><span style="color: #000000;">()
        x </span><span style="color: #000000;">=</span><span style="color: #000000;"> x </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">
        </span><span style="color: #FF00FF;">print</span><span style="color: #000000;">(x)
    </span><span style="color: #0000FF;">end</span><span style="color: #000000;">
</span><span style="color: #0000FF;">end</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>&nbsp;&nbsp;&nbsp; 那么，下面c1与c2相等吗？</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:ac4c159d-b86d-4c7d-b73e-5a95439ebd95" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #000000;">c1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> createCounter()
c2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> createCounter()</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>&nbsp;&nbsp;&nbsp; 由于createCounter中的return部分创建了一个新函数，因此c1和c2引用的函数并不相同。因为return的匿名函数中使用到了外部函数(即createCounter)的局部变量x，所以Lua必须要在某个地方保存这个变量，又因为每次返回的都是一个新函数，所以Lua不能共享createCounter中的x，进而Lua必须为每个新函数分配一个保存x的地方，这个问题导致了闭包概念的产生。<br>&nbsp;&nbsp;&nbsp; 通过上面分析，可以明白是语言机制导致了闭包，而绝非Lua作者故意制造出这么一个看似有点神秘的东西。<br>&nbsp;&nbsp;&nbsp; 下面给出闭包的定义：一个保留了创建时上下文的函数。而upvalue的定义是：被闭包访问的保留变量。实际上所有在Lua中创建的函数都是闭包，在许多情况下仅有一个原型的闭包存在，因为函数块只执行了一次（也可以说定义了一次）。 
<p>&nbsp;&nbsp;&nbsp; 下面代码用闭包实现了一个对象工厂： 
<p></p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:b3baf5b1-7284-4db3-9e3e-187f40a81440" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">local</span><span style="color: #000000;"> </span><span style="color: #0000FF;">function</span><span style="color: #000000;"> CounterFactory()
    </span><span style="color: #0000FF;">local</span><span style="color: #000000;"> x </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> 
    {
        Increase </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">function</span><span style="color: #000000;">()
            x </span><span style="color: #000000;">=</span><span style="color: #000000;"> x </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">end</span><span style="color: #000000;"> ,
        Decrease </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">function</span><span style="color: #000000;">()
            x </span><span style="color: #000000;">=</span><span style="color: #000000;"> x </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">
        </span><span style="color: #0000FF;">end</span><span style="color: #000000;"> ,
        GetValue </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">function</span><span style="color: #000000;">()
            </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> x
        </span><span style="color: #0000FF;">end</span><span style="color: #000000;">
    }
</span><span style="color: #0000FF;">end</span><span style="color: #000000;">

</span><span style="color: #0000FF;">local</span><span style="color: #000000;"> c1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> CounterFactory()
</span><span style="color: #0000FF;">local</span><span style="color: #000000;"> c2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> CounterFactory()

c1.Increase()
c1.Increase()
</span><span style="color: #FF00FF;">print</span><span style="color: #000000;">(c1.GetValue())</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p></p>
<p>三、Tail Call</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 首先需要明确What is ‘Tail Call’?——其形式为“return f(…)”，return语句中的函数调用仅限于单一调用，涉及函数返回值运算的复合表达式不是尾调用，如：return i * f(i - 1)。由定义可以看出尾调用实际上是对位于返回语句中的函数调用的优化。通常调用一个函数都需要将其上下文入栈，然后再进入被调函数。在Lua中执行符合尾调用形式的函数时，因为该函数已经没有代码需要执行了，故作者作了不保存上下文的优化。这样带来的好处是：对于精心构建的递归调用，不需要有栈的消耗，因而绝对不会出现overflow，看看下面递归调用产生的死循环：</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:5da219fa-2b40-4878-8186-af832f2d6798" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">local</span><span style="color: #000000;"> </span><span style="color: #0000FF;">function</span><span style="color: #000000;"> f(n)
    </span><span style="color: #0000FF;">local</span><span style="color: #000000;"> i </span><span style="color: #000000;">=</span><span style="color: #000000;"> n </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">
    </span><span style="color: #FF00FF;">print</span><span style="color: #000000;">(i)
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> f(i)  </span><span style="color: #008000;">--</span><span style="color: #008000;"> tail call</span><span style="color: #008000;">
</span><span style="color: #0000FF;">end</span><span style="color: #000000;">

f(</span><span style="color: #800080;">0</span><span style="color: #000000;">)</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>四、Metatable</p>
<p>&nbsp;&nbsp;&nbsp; Metatable常用来扩展table的行为，通过setmetatable(table , metatable)将metatable挂接到table上，很多开发者用该特性来实现面向对象的设计。Metatable中提供了Metamethods，这些方法都以双下划线__开头，如：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __add , __call , __concat , __div , __eq , __index...</p>
<p>&nbsp;&nbsp;&nbsp; 以上Metamethods中，__index被调用的条件是：key不在对应的table中。利用该特性可以实现类-对象、继承等面向对象概念，下面是个简单例子：</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:baf8a2dd-b74f-46f8-bb1f-fb8afa05d38b" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">local</span><span style="color: #000000;"> Actor </span><span style="color: #000000;">=</span><span style="color: #000000;"> {}
Actor.name  </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">unnamed</span><span style="color: #800000;">"</span><span style="color: #000000;">
Actor.hp    </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">100</span><span style="color: #000000;">
Actor.dead  </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">false</span><span style="color: #000000;">
Actor.level </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">1</span><span style="color: #000000;">
Actor.</span><span style="color: #FF00FF;">type</span><span style="color: #000000;">  </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">unknown</span><span style="color: #800000;">"</span><span style="color: #000000;">

</span><span style="color: #0000FF;">function</span><span style="color: #000000;"> Actor:Say(text)
    </span><span style="color: #FF00FF;">print</span><span style="color: #000000;">(self.name..</span><span style="color: #800000;">"</span><span style="color: #800000;">:</span><span style="color: #800000;">"</span><span style="color: #000000;">..text)
</span><span style="color: #0000FF;">end</span><span style="color: #000000;">

</span><span style="color: #0000FF;">function</span><span style="color: #000000;"> Actor:IsDead()
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> self.dead
</span><span style="color: #0000FF;">end</span><span style="color: #000000;">

</span><span style="color: #0000FF;">local</span><span style="color: #000000;"> AttackableActor </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #FF00FF;">setmetatable</span><span style="color: #000000;">({ } , { __index </span><span style="color: #000000;">=</span><span style="color: #000000;"> Actor })
AttackableActor.damage </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">20</span><span style="color: #000000;">

</span><span style="color: #0000FF;">function</span><span style="color: #000000;"> AttackableActor:ReceiveHit(attacker)
    self:Say(</span><span style="color: #800000;">"</span><span style="color: #800000;">I'm being attacked by </span><span style="color: #800000;">"</span><span style="color: #000000;">..attacker.name)
    self.hp </span><span style="color: #000000;">=</span><span style="color: #000000;"> self.hp </span><span style="color: #000000;">-</span><span style="color: #000000;"> attacker.damage
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> self.hp </span><span style="color: #000000;">&lt;=</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;"> </span><span style="color: #0000FF;">then</span><span style="color: #000000;">
        self:Say(</span><span style="color: #800000;">"</span><span style="color: #800000;">I'm died :(</span><span style="color: #800000;">"</span><span style="color: #000000;">)
        self.dead </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">true</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
        self:Say(</span><span style="color: #800000;">"</span><span style="color: #800000;">My HP is </span><span style="color: #800000;">"</span><span style="color: #000000;">..self.hp)
    </span><span style="color: #0000FF;">end</span><span style="color: #000000;">
</span><span style="color: #0000FF;">end</span><span style="color: #000000;">

</span><span style="color: #0000FF;">function</span><span style="color: #000000;"> AttackableActor:Attack(target)
    </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> target.dead </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #0000FF;">true</span><span style="color: #000000;"> </span><span style="color: #0000FF;">then</span><span style="color: #000000;">
        self:Say(</span><span style="color: #800000;">"</span><span style="color: #800000;">Oh, </span><span style="color: #800000;">"</span><span style="color: #000000;">..target.name..</span><span style="color: #800000;">"</span><span style="color: #800000;"> has been dead!</span><span style="color: #800000;">"</span><span style="color: #000000;">)
    </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
        self:Say(</span><span style="color: #800000;">"</span><span style="color: #800000;">I'm is attacking </span><span style="color: #800000;">"</span><span style="color: #000000;">..target.name)
        target:ReceiveHit(self)
    </span><span style="color: #0000FF;">end</span><span style="color: #000000;">
</span><span style="color: #0000FF;">end</span><span style="color: #000000;">

</span><span style="color: #0000FF;">function</span><span style="color: #000000;"> CreateMonster(name , damage)
    </span><span style="color: #0000FF;">local</span><span style="color: #000000;"> m </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #FF00FF;">setmetatable</span><span style="color: #000000;">({ } , { __index </span><span style="color: #000000;">=</span><span style="color: #000000;"> AttackableActor})
    m.name </span><span style="color: #000000;">=</span><span style="color: #000000;"> name
    m.damage </span><span style="color: #000000;">=</span><span style="color: #000000;"> damage
    m.</span><span style="color: #FF00FF;">type</span><span style="color: #000000;"> </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">monster</span><span style="color: #800000;">"</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> m
</span><span style="color: #0000FF;">end</span><span style="color: #000000;">

</span><span style="color: #0000FF;">function</span><span style="color: #000000;"> CreatePlayer(name , damage)
    </span><span style="color: #0000FF;">local</span><span style="color: #000000;"> p </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #FF00FF;">setmetatable</span><span style="color: #000000;">({ } , { __index </span><span style="color: #000000;">=</span><span style="color: #000000;"> AttackableActor})
    p.name </span><span style="color: #000000;">=</span><span style="color: #000000;"> name
    p.damage </span><span style="color: #000000;">=</span><span style="color: #000000;"> damage
    p.</span><span style="color: #FF00FF;">type</span><span style="color: #000000;"> </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">player</span><span style="color: #800000;">"</span><span style="color: #000000;">
    </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> p
</span><span style="color: #0000FF;">end</span><span style="color: #000000;">

</span><span style="color: #FF00FF;">math.randomseed</span><span style="color: #000000;">(</span><span style="color: #FF00FF;">os.time</span><span style="color: #000000;">())

</span><span style="color: #0000FF;">local</span><span style="color: #000000;"> boss </span><span style="color: #000000;">=</span><span style="color: #000000;"> CreateMonster(</span><span style="color: #800000;">"</span><span style="color: #800000;">Kerrigan</span><span style="color: #800000;">"</span><span style="color: #000000;"> , </span><span style="color: #FF00FF;">math.floor</span><span style="color: #000000;">(</span><span style="color: #800080;">100</span><span style="color: #000000;"> </span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #FF00FF;">math.random</span><span style="color: #000000;">()))
</span><span style="color: #0000FF;">local</span><span style="color: #000000;"> player </span><span style="color: #000000;">=</span><span style="color: #000000;"> CreatePlayer(</span><span style="color: #800000;">"</span><span style="color: #800000;">Raynor</span><span style="color: #800000;">"</span><span style="color: #000000;"> , </span><span style="color: #FF00FF;">math.floor</span><span style="color: #000000;">(</span><span style="color: #800080;">100</span><span style="color: #000000;"> </span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #FF00FF;">math.random</span><span style="color: #000000;">()))

</span><span style="color: #0000FF;">while</span><span style="color: #000000;"> player:IsDead() </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #0000FF;">false</span><span style="color: #000000;"> </span><span style="color: #0000FF;">and</span><span style="color: #000000;"> boss:IsDead() </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #0000FF;">false</span><span style="color: #000000;"> </span><span style="color: #0000FF;">do</span><span style="color: #000000;">
    player:Attack(boss)
    boss:Attack(player)
</span><span style="color: #0000FF;">end</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --></div>
<p>
<p></p>
<p>五、Performance Tips</p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p>&nbsp;&nbsp;&nbsp; 请参考<a href="http://www.lua.org/gems/sample.pdf" target="_blank">Lua Performance Tips</a></p>
<p>六、总结</p>
<p>&nbsp;&nbsp;&nbsp; Lua是一门语法简洁，用法灵活的动态语言。在全面掌握之后，需悉心使用乃可构造出简洁高效的代码。</p><img src ="http://www.cppblog.com/heath/aggbug/120686.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-07-18 12:46 <a href="http://www.cppblog.com/heath/archive/2010/07/18/120686.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>How to install Mac OS X 10.6.3 on PC from Hard Disk</title><link>http://www.cppblog.com/heath/archive/2010/05/14/115403.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Fri, 14 May 2010 13:57:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/05/14/115403.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/115403.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/05/14/115403.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/115403.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/115403.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 想做iphone/ipad开发，又不想买mac机的同学可以参考下&nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2010/05/14/115403.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/115403.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-05-14 21:57 <a href="http://www.cppblog.com/heath/archive/2010/05/14/115403.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Enable AHCI mode after installing Windows xp</title><link>http://www.cppblog.com/heath/archive/2010/05/14/115400.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Fri, 14 May 2010 13:26:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/05/14/115400.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/115400.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/05/14/115400.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/115400.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/115400.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 用Snow Leopard需要开启AHCI，希望在不重装原来XP的提前下让两个系统并存，在网上找到一篇很完美的解决方案，做了一些修改以适应自己的TPower I45。有同样需求的同学可以参考一下&nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2010/05/14/115400.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/115400.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-05-14 21:26 <a href="http://www.cppblog.com/heath/archive/2010/05/14/115400.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++认知误区(1)：成员保护机制</title><link>http://www.cppblog.com/heath/archive/2010/04/24/113445.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 24 Apr 2010 08:16:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/04/24/113445.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/113445.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/04/24/113445.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/113445.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/113445.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 生活、工作中会有各种各样认知误区，与自己认知相悖的，不一定是错误的&nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2010/04/24/113445.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/113445.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-04-24 16:16 <a href="http://www.cppblog.com/heath/archive/2010/04/24/113445.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>写着玩(2)&amp;mdash;&amp;mdash;WoW角色资源读取</title><link>http://www.cppblog.com/heath/archive/2010/04/24/113423.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sat, 24 Apr 2010 04:31:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/04/24/113423.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/113423.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/04/24/113423.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/113423.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/113423.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/heath/archive/2010/04/24/113423.html'>阅读全文</a><img src ="http://www.cppblog.com/heath/aggbug/113423.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-04-24 12:31 <a href="http://www.cppblog.com/heath/archive/2010/04/24/113423.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Slerp or Lerp</title><link>http://www.cppblog.com/heath/archive/2010/03/14/109689.html</link><dc:creator>Heath</dc:creator><author>Heath</author><pubDate>Sun, 14 Mar 2010 09:54:00 GMT</pubDate><guid>http://www.cppblog.com/heath/archive/2010/03/14/109689.html</guid><wfw:comment>http://www.cppblog.com/heath/comments/109689.html</wfw:comment><comments>http://www.cppblog.com/heath/archive/2010/03/14/109689.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heath/comments/commentRss/109689.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heath/services/trackbacks/109689.html</trackback:ping><description><![CDATA[<p><a href="http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/index.html" target="_blank">Understanding Slerp, Then Not Using It</a>对Slerp的起源及性能做了详细的讨论。Slerp并不局限于维数，因而不要认为只对Quaternion有效。作者认为Slerp会带来效率问题，即便经过优化也并不能达到理想的速度(与lerp做比较而言)，而且优化往往会降低代码的易读性。文章给出了一个结论：如果插值过程中的常量速度不是必须的，那么最好使用线性的lerp。</p> <p>Jason Gregory在他的引擎架构设计一书中也用“To SLERP or Not to SLERP (That’s Still the Question)”一小节介绍了开发者对Slerp的争论，并介绍他在Naughty Dog的同事针对PS3的优化方法，使Slerp可达到20周期/关节，相比Lerp的16.25周期/关节已经很不错了。</p> <p>之前确实没对Slerp的效率问题作过多的考虑，引擎的Slerp直接使用的是D3DXQuaternionSlerp，MS应该对其做了优化，效率怎么样要测一下才知道了。</p><img src ="http://www.cppblog.com/heath/aggbug/109689.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heath/" target="_blank">Heath</a> 2010-03-14 17:54 <a href="http://www.cppblog.com/heath/archive/2010/03/14/109689.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>