CATEGORY / Development

遍历 CTreeCtrl

CTreeCtrl 的 GetNextItem 成员函数很诡异,nCode 设为 TVGN_NEXT | TVGN_CHILD 会一直返回传进去的 hItem 值,而不是返回下一个兄弟 item “或”第一个 child item。

所以,只好自己写遍历函数,没有采用递归的做法,用了一个 STL List 容器来保存下一个兄弟 item 和第一个 child item,遍历返回的依据是 item 的 lParam 值等于给定的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
HTREEITEM CModelNodeTreePane::_GetTreeItemByID(const unsigned int uiItemID)
{
    HTREEITEM   hCurrItem = m_kModelNodeTreeCtrl.GetRootItem(),
                hItem;
    std::list kItemList;
 
    kItemList.push_back(hCurrItem);
 
    while (kItemList.size() > 0)
    {
        hCurrItem = kItemList.front();
        kItemList.pop_front();
 
        if ((unsigned int)m_kModelNodeTreeCtrl.GetItemData(hCurrItem) == uiItemID)
        {
            return hCurrItem;
        }
 
        if ((hItem = m_kModelNodeTreeCtrl.GetChildItem(hCurrItem)) != NULL)
        {
            kItemList.push_back(hItem);
        }
        if ((hItem = m_kModelNodeTreeCtrl.GetNextSiblingItem(hCurrItem)) != NULL)
        {
            kItemList.push_back(hItem);
        }
    }
 
    return NULL;
}

动态创建的 CTreeCtrl 实例的消息响应

由于程序里的 CTreeCtrl 控件实例是通过 CTreeCtr::Create() 来创建的,无法通过 VS 的 Properties 面板里的 Control Events 工具来生成消息映射函数,但控件又需要响应鼠标点击事件,这时最简单的办法就是重载 CTreeCtr 实例的 owner 的 OnNotify() 成员虚函数(这个 owner 也必然是 CWnd 的子类):

protected:
    virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BOOL CTreePane::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
    NMHDR* pNMHDR = (NMHDR*)lParam;
    ASSERT(pNMHDR != NULL);
 
    switch (pNMHDR->code)
    {
    case TVN_SELCHANGED:
        _OnTreeCtrlSelChanged(wParam, lParam, pResult);
        break;
 
    default:
        break;
    }
 
    return CWnd::OnNotify(wParam, lParam, pResult);
}

IE8 引发 VS 2005/2008 向导出错的解决方案

Internet Explorer 8 正式版会导致  Visual Studio 2005 / 2008 里的部分 VC++ 向导出错,包括:

  • Add Function
  • Add Variable
  • Smart Device – New Project Creation
  • Smart Device – Add Class

VC++ 团队给出了解决方案:

  1. 运行注册表编辑器 regedit(64 位系统请使用 32 位版本
  2. 定位到“HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet
    Settings\Zones
    ”下
  3. 新建一个名为 1000 的项
  4. 在 1000 这个项下,新建一个 DWORD 值,名为 1207,值为 0x000000

然后重启 VS 即可。

注意:VS 2005 必须装上 SP1

想深究这个问题原因,可以参看原文


3D Coordinates

最近碰到 Gamebryo3DS MAX 的坐标系转换问题,顺便花了几分钟研究了下各 3D 坐标系,真是比当下全球形势还混乱:

除了微软当年为了跟 OpenGL 划清界限,特立独行搞出左手坐标系的 DX 外,其他都是右手系(应该都是受 OGL 这个工业标准的影响),不过 Z 轴朝什么方向的都有,哭死了。


WoW Model Viewer 的编译问题

这段时间要搞角色换装系统的改进,参考魔兽世界的换装系统机制,便先拿了 WoW Model Viewer 的代码来参考。

先拷来一个 0.48b 版本的代码,按照这里说的做后编译是通过了,但运行总报错,跟了一下没找到问题,索性去下了 0.5.08 。该版本使用 wxWidgets 2.8.0、CxImage 5.99c、GLEW 1.3.3,其中 wxWidgets 2.8.0 需要自行下载、编译。

然后打开 wowmodelview.sln,打开工程属性,修改 C++ | Additional Include Directories、Linker | Additional Library Directories 中关于 wxWidgets 的路径,然后编译,这时可能会报一些 build error,基本都是类型没有显式强转的问题,改掉即可。

编译完成后,需要修改配置文件 Config.ini,把 [Locale] 下的“Path=”和“MPQFiles=”后的路径都改为 .mpq 文件所在文件夹根目录,就可以运行了。


看,给这位大老粗穿上粉红色紧身T恤是不是很性感呀?


应用工厂模式解决实际问题

我前段时间去面试时的一道题目,问题如下:

有一个脚本文件,每行有一句指令或空行,指令格式:

Command[,Param[,Value]]

其中Parameter 和 Value 非必须。设计一套解析指令的类,高效且易于扩展(尽可能降低代码内部耦合性)。

当时虽然都想到了,不过满脑混沌,没有完整明白地表达出来。本来想去公司再看看代码是怎么实现的,昨天在网上闲逛的时候忽然看到了这篇笔记,那就顺便也整理了下自己的思路,结合实际温故理论。

假设有“移动(Move)”、“攻击(Attack)”等几个指令;建立一个工厂类,并将所有指令类预先注册到工厂中,由工厂调用每个指令类的静态成员函数 CreateInstance() 来实现指令类实例的创建:

CONTINUE READING »


判断一个点是否在 2D 三角形内

这是我拿到公司 offer 时美国老大给我的面试题,对于当时我这种文盲来说,还是杀死了不少脑细胞。最近闲来无事(嗯。。。被危机了),又拿出来琢磨了一下各算法。

设一在在 2D 空间中的三角形 △ABC ,三个顶点向量 A(ax, ay)、B(bx, by)、C(cx, cy),三条有向边 AB、BC、CA,有一点 P(px, py)。

  1. 叉乘法
  2. 原理:

    沿 △ABC 各有向边按一定方向走(顺时针或逆时针),判断点 P 是否在该边的某侧(右侧或左侧),若点 P 在三条边的同侧,则点 P 在 △ABC 内。

    实现:

    分别计算向量 AB、BC、CA 与向量 AP、BP、CP 的向量积(叉乘),若三个结果均同号(正或负,为零表示 P 在边上),则可得点 P 在 △ABC 内。其中AB = B - A,AB×AP = AB.x*AP.y - AB.y*AP.x。

    该算法只需要做 3 次叉乘(6 次普通数值乘法),效率高,且没有浮点误差。
    这是我当时面试想的算法,Azure 等人也用的类似算法。

  3. 面积法
  4. 原理:

    若点 P 在 △ABC 内,则 △ABP、△BCP、△CAP 的面积之和应等于 △ABC 的面积。

    实现:

    利用两个向量叉积的几何意义为该两个向量所围三角形面积的 2 倍,分别计算 AB×BP、BC×CP、CA×AP、AB×BC,若 |AB×BP| + |BC×CP| + |CA×AP| = |AB×BC|,则得点 P 在 △ABC 内。

    这个算法用得比较普遍,需要做 4 次叉乘(8 次普通数值乘法),效率和叉乘法差不多,同时避免了用海伦公式计算面积的低效和精度问题(数值除法和开方运算)。

我昨天想的一个算法有点类似这篇文章中的方法 3,比它简单一点,但同样需要对向量做归一化处理,效率不高,故放弃了。另外的算法还包括划线交点法、解方程组法、复数法等,但计算量都较大,不再赘述。


The IEEE 754 Floating Point Format

最近碰到用十六进制数表示浮点小数的问题,本科没学好,现在是补习时间。

FP32(单精度浮点数)

  • 第 31 bit 为符号位,0 表示正数,反之为负数,其读数值用 s 表示;
  • 第 30~23 bit 共 8 bits 为指数,其读数值用 e 表示;
  • 第 22~0 bit 共 23 bits 为分数,视为二进制纯小数,假定该小数的十进制值为 f;
 S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
31 30    23 22                    0

v = (-1)s × 2e-127 × 1.f

十进制浮点小数转 IEEE 754 格式的方法,以 −118.625 为例:

  • 由于是负数,得 s = 1;
  • 去符号后,将小数转为二进制数表示(整数部分除以 2 取整,小数部分乘以 2 取整)得 1110110.101;
  • 将该二进制小数正规化,即将小数点向左(为正)或向右(为负)移动,直至形成 1.f 格式的数,得1.110110101×26,补齐 23 bit 从而得到 f = 11011010100000000000000;移动的位数加 127 即为 e,得 e = 133 = 10000101;
  • 最后得到 IEEE 754 格式:1 10000101 11011010100000000000000 = 0xC2ED4000。

CONTINUE READING »


Delphi 终究被 Borland 卖掉了

十二年前的暑假,Pascal 把我领进了 Programming 的大门,它优美的语法、清晰的逻辑,陪伴我度过了初中高中,并有幸拿到了几个小奖。八年前,第一次听到了 Delphi 这个名字 —— “Win32 下的 Pascal” —— 让我不禁兴奋起来,我亲爱的 Pascal,后浪推前浪啊!遂打定主意,等高考完就去学它。

七年前的暑假,没有了压力,跌跌撞撞地开始了 Delphi 之旅。是它完善的 OO 支持、强大的 WYSIWYG 支持、丰富的 VCL 以及对经典 Pascal 语言的完美延续,让我体会到了 Application Development 的乐趣与成就感,也对 Programming 有了越来越深刻的了解。Delphi 几乎就是我的启蒙恩师。

五年前开始转向 C++/VC,尽管 C++ 能做的绝大多数 Delphi 都能做,而 VC/MFC 实在落后 Delphi/VCL 太多年(至今如此),但在 Windows 下,谁能玩得过既当球员又当裁判的 M$?VC 再烂,都有所有 WinAPI、M$ 各 SDK 的原生支持,而 Delphi 永远只能等待大拿们的移植。在 M$ 挖墙脚和推 .net 战略的双重压力下,Borland 开始偏离了自己的方向,被逐步牵着鼻子走向了没落。值得纪念的是,四年前,我倒数第二个用 Delphi 开发的程序,为我带来了 ¥3k 的收入,这在当时,对我来说,已经相当激动了。

再后来,出于纪念意义,陆续装过 Delphi 8/9/10(虽然都是盗版,但精神可嘉,嗯),但都没再用于正式的开发。而 Borland 在2006 年开始打算剥离 IDE 和数据库业务,苦于没有合适的买家接手,Delphi 以及 BCB、JBuilder 等优秀的 IDE 们暂时由 Borland 旗下的 CodeGear 运作。而自从 CodeGear 接手后,Delphi 似乎就再也没有出头过了。

昨天,Borland 和 Embarcadero Technologies 达成了意向,将 CodeGear 以 $23million 的价格出售给后者。

一个曾经辉煌的时代结束了。我们应该对 Borland 说走好呢,还是对 delphi 说走好?

CONTINUE READING »


My first game was born in Oct, 2006

It names 王牌, with folk name 三张牌, here's its face:

It include some animation such as flying jettons. I wrote it in one month based on a net-game development platform.

Now i'm going to write a new game called SiGuoDaZhan (maybe say Chinese Military Chess), good luck to myself :)


Page 3 of 41234