风魂++

                 ..;;;;,                     ;;;,
             ..;;;"` ;;:           ,;;;;;: ,;;;:.,;..          _/
       ,;..,;;"`    :;;'            :;;"`,;;;;;;"":;;         _/
       ;;;"  `:;;. ;;'           ..;;:  .;;,.;;:',;;"    _/_/_/_/_/
      .;;`   ,;;" .;"          ,;;;;;;" :;`',;",;;"         _/
     ,;;,:.,;;;  ,;:          :" ,;:` , `:.;;;;;'`         _/
     ;;"'':;;:. .;; .          ,;;;,;:;;,;;;, ,;             _/
    :;;..;;;;;; :;' :.        :;;;"` `:;;;;;,;,.;.          _/
  .;;":;;`  '"";;:  ';;       '""   .;;`.;";:;;;;` ;,  _/_/_/_/_/
 ;;;" `'       "::. ,;;:          .;"`  ::. '   .,;;;     _/
 ""             ';;;;;;;"        ""     ';;;;;;;;;;`     _/

                        Windsoul++

                A Game Programming Library

                by 云风 (Cloud Wu)  1999-2002

          http://www.codingnow.com
          mailto:cloudwu@263.net

在遵守下面的约定的情况下, 你可以任意使用风魂所包含的一切代码. 但是我对使用这些代码带来的任何后果不负责. 我将尽我可能的发现并且修正代码中存在的Bug, 补充新的特性, 回答使用者遇到的问题. 如果有一天我对此失去了兴趣, 却有可能放弃对此代码的维护工作. 所以你自己需要承担使用这些代码可能存在的风险。

版权

风魂系列是云风独立开发完成, 以公开源代码的形式对所有人开放使用. 如果您想将其或其中一部分代码用于商业软件 使用, 请将云风的名字署入软件. 如果用于的软件属非赢利性质, 请在软件使用者可以看到的地方注明使用了风魂. 若想直接将风魂的源代码用于赢利用途(例如收录于各种光盘, 加入到赢利性质的程序库或控件, 编入各种出版物等等) 请务必先和云风联系.

目录

  • 介绍
  • 安装
  • 图形模块
  • 文件模块
  • 辅助模块
  • 程序框架类
  • 附加模块
  • 调试
最后修改于 2002年7月11日 17:27:52


风魂++ 简介

风魂是云风于 1999年3月4日 开始为方便 Windows 下游戏开发而制作的函数库. 最开始完全使用 C 语言开发, 基于 DirectX 3.0, 可以运用于 Windows 9x/NT. 风魂本身也对 Windows 应用程序框架 做了简单的包装，使早期从 DOS 过度过来的程序员(有如云风当年) 能够迅速的在 Windows 平台下开展 工作. 从技术上说, 仅支持了近年来 2D 游戏最常用的 16bit 全屏模式(在 GDI 方式下调试) 没有使用 任何硬件加速特性, 但是为所有可能的操作编写了 MMX 优化版本. 提供了 DirectDraw 所没有的各种 图形特效, 简化了大量的 DirectX 烦琐的初始化, API 调用过程.

应许多风魂的爱好者的要求, 和云风自己意识到的风魂本身结构上的不足, 风魂开始用 C++ 封装, 并且重写了所有的代码, 修改了内部数据结构, 模块的组织方式, 并且去掉了非 MMX 代码, 全面使用 MMX 加速. 这个新的版本被称为"风魂plus", 于2000年4月18日预发了源码. 其最有特点的新特性是 全面支持了 Alpha channel, 和 Z-Buffer 技术.

2000年9月, 云风重新研究了 OOP 技术, 诸多感悟之后, 将原有的所有设计推翻, 风魂系列翻开新的一页, 这就是现在的风魂++, 目前暂时只做了图象部分, 工作在 GDI 模式下 (可以通过一个额外的类作为和 DirectDraw 全屏模式的接口). 并没有为 windows 应用程序本身做封装. 而是以一个类库的形式提供给用户. 风魂++ 支持了各种色彩深度, 而不局限于高彩. 在符合规范的情况下, 可以自己扩展新的位图类. 比如将支持的 Alpha 通道位图等. 对于位图本身的控制, 使用操作符重载和大量隐式转换, 接口简洁. 另外扩展的 CANVAS 模块, 使用异步绘图控制, 内部自动优化. 整个系统采用 C++ 写成, 完全 OOP 结构. 核心绘图部分, 使用的 NASM 编写的高效 MMX 优化代码, 可以用于各种 C++ 编译器.

在做出了大量的工作后,云风感到自己的精力不足,为了将其中一方面做好,先后砍掉了除16bit色外其它颜色深度的支持, (虽然已经写了大量的C++/ASM代码) 和已经可以使用的 Borland C++ Builder 的控件. (虽然有些朋友拿到了 早一点的内部版本, 并可以正常的使用, 但新的版本已经不保证可以正确编译运行)

目前的版本被命名为风魂++16bit版,一般情况下,可以在 http://www.codingnow.com/windsoul/wpp16.cab下载到最新的源码包.

拿到这个类库,你在遵循版权的情况下可以任意修改使用. 对于使用这个类库做商业开发 的同行, 云风可以尽可能的提供技术支持. 同时, 还开发了大量的附加类库, 供商业游戏开发者使用. 比如, jpeg 加载, 256色RLE/AlphaEdge的精灵, 随机数发生器, 声音驱动和管理, 等等. 甚至你需要更多的功能扩展, 都可以直接于 云风联系.

最后修改于 2002年7月11日 17:28:05


风魂++ 安装

开发环境需求

  • 支持 MMX 的 CPU
  • NASM 0.98
  • Visual C++ 6.0 (VC 其他版本可能也能编译, 但没有测试), Borland C++ Builder 5.0 的支持已经不再保证

风魂++ 的安装和设置

  • Visual C++ 6.0
    1. 将源码包带目录解开到一个目录下. (比如 C:\Windsoul, 以下举例用这个)
    2. 将你的 NASM 0.98 的编译程序 (通常叫做 nasmw.exe) 拷贝到 你机器上安装的 VC 的 bin 目录下, 这个工程需要调用它.
    3. 用 Visual C++ 6.0 中打开其中的 WorkSpace 文件 WPP16.DSW
    4. 分别以 DEBUG 模式和 RELEASE 模式编译其中的工程 windsoul. (Build 菜单的 Set Active Configuration, 选 Windsoul. 然后用 F7 编译)
    5. 设置 Visual C++ 6.0 的环境, 在 Tools/Options/Directories 里增加风魂的 Include 文件目录 C:\Windsoul\Include (或你安装的目录) 增加风魂的 Lib 文件目录 C:\Windsoul\Lib (lib 文件是刚才创建的)
    6. 另外提供静态库的版本, wsstatic 工程, 请自行尝试. 但是需要预先编译出 dll 版本, 这样才可以生成 Static Lib 版连接所需要的几个 obj 文件.
    7. 动态连接库的 Release 版本叫做 windsoul.dll, Debug 版本叫做 wsdebug.dll. 被编译输出到 c:\windsoul\dll 下， 请确保您的程序在运行的时候能够找到对应的 dll 文件.
    8. 如果使用静态库(wsstatic.lib) 这个版本, 请在您的游戏工程里预定义 WINDSOUL_STATICLIB 这个宏, 使 windsoul.h 能正确找到 lib 文件进行连接.
    9. 为了方便调试程序, 最好在系统的环境变量的 path 里面加入 c:\windsoul\dll. (如果您使用的 windows 2000, 用鼠标右键点我的电脑,选属性,在高级选项里可以看到修改环境变量的位置)

    备注:如果你缺少 NASM, 可以去 NASM 主页下载, 或者在云风的主页上也可以 download. 编译程序可能是 nasm.exe, 那么改名为 nasmw.exe 即可

  • Borland C++ Builder 5.0
    1. 这个版本已经取消对它的支持, 但是在你下载的源码包中可能还存在有残留物, 给 BCB 的死忠爱好者或者是喜爱冒险的朋友去尝试. 使用这个版本所引起的任何不量后果, 诸如显示器爆炸, 玻璃碎片飞出刺伤眼睛等, 云风一概不负责任. 也不要写 email 给我诉苦.
    2. 将源码包带目录解开到一个目录下.
    3. 由于云风对 BCB 不太熟悉, 还不太清楚怎么让 NASM 和 BCB 协同工作, 所以请手动编译几个 .asm 文件. 运行 makeasm.bat 就可以了.
    4. 用 Borland C++ Builder 5.0 打开其中的 Project 文件 wpp.bpr
    5. 编译项目 WPP.
    6. 将编译出来的 wpp.lib 加入到你需要的工程里去就可以了.
最后修改于 2001年11月11日 11:38:04


风魂++ 图形模块

图形模块

风魂++的基础模块(就是公开发布的这一部分), 最重要的就是这个图象处理的部分. 这里因为有独特的画布优化Engine 的概念, 不得不先讲解下类的结构便于对整个类库的理解.

所有的可绘制对象都是从 WObject 这个基类中派生出来, 基类给出了很多 纯虚函数接口. 所以所有符合风魂的图形模块的可绘制对象, 都可以获得它们的高度,宽度,可以获得并设置关键点. 能够在画布所管理的堆中复制自身, 获取将自己画到位图上的函数指针, 并拥有一个以上的绘制样式. 一些扩展的对象, 比如直线对象, 还可以查询到自己是否破坏了画布上的指定区域. 对 WObject 的详细分析将在后面展开.

如果拿到了一个风魂++里实现的可绘制的对象, 无论它是基础类库中的, 还是扩展类库中的, 不必了解 它们使用的细节, 都可以将它们用于位图或者画布的操作.

  • 可绘制对象基类(WObject)
  • 像素对象(WPixel)
  • 位图对象(WBitmap)
  • 画布(WCanvas)
  • Alpha通道位图(WAlphaBitmap)
  • 几何绘图
  • 文字输出(WFont/WChar)
  • DirectDrawSurface的接口类(WSurface)
最后修改于 2001年8月27日 13:41:08


风魂++ 图形模块:可绘制对象基类(WObject)

WObject

所有可以画在位图(WBitmap), 或画布(WCavnas) 上的对象, 都从它派生出来. WObject 是一个纯虚类, 派生于它的类都必须去实现几个必要的接口(详情见下文). 它有一个数据结构指针, 所有的数据, 必须放在这个结构中, 而不能直接作为类的成员变量, 就是说, 所有 WObject 的派生类, sizeof() 得出的值都是 8. (一个虚函数表, 一个数据结构指针) 不过, 纯 WObject 受体除外, 比如 WCanvas, 它也是从 WObject 继承下来, 但它不能以常规 方式被画在位图或另一个画布上, 而需要额外的函数去实现, 所以它可以不遵循这个规定, 拥有自己的成员变量.

类的定义如下:

class WINDSOUL_API WObject {
protected:
    void *objdata;
public:
    WObject() : objdata(0) {}
    virtual ~WObject() {};
    void *operator new(unsigned size);
    void operator delete(void *p);

    void SetData(void *p);
    WObjStruct *GetObjStruct() const;
    bool IsValid() const;
    void *GetData() const;
    WObject& SetPos(const WPoint &p);
    WObject& SetPos(int x,int y);
    int GetX() const;
    int GetY() const;
    virtual int GetW() const=0;
    virtual int GetH() const=0;
    virtual BLIT_FUNC DrawFunc(DWORD style) const=0;
    virtual WObjStruct *Duplicate(WObjectHeap *heap) const=0;
    virtual bool Affect(int x,int y) const;
    virtual void SetUserData(DWORD data) {};
};
  • 唯一的成员变量是 objdata 这个指针, 它指向一个数据结构, 里面保存着对象拥有的所有私有数据. 在 WObject 在构造的时候, 这个数据结构同时构造出来, 或者指向 NULL.

  • 重载的 new 和 delete 操作符, 使 WObject 都可以快速的动态分配和释放, 它们是用风魂++自己的一个页式 分配所管理的, 比系统提供的 new/delete 要快的多. DEBUG 版里, 在程序结束的时候, 会报告是否有泄露.

  • SetData GetData 提供了数据结构指针的存取操作

  • IsValid 通过检查数据结构指针是否为空, 来确定 WObject 是否可用. 这一般用于 DEBUG 版的断言中.

  • SetPos GetX GetY 可以存取 WObject 的关键点信息. 关于关键点的描述, 见后面对 WObjStruct 的阐述.

  • GetW 是 WObject 的派生类必须实现的接口, 它获得了对象的像素点宽度. 这个宽度值将用于画布Engine的优化

  • GetH 是 WObject 的派生类必须实现的接口, 它获得了对象的像素点高度. 这个高度值将用于画布Engine的优化

  • DrawFunc 是 WObject 的派生类必须实现的接口, 它获得了对象指定样式画向　WObject 的受体(比如 WBitmap, WCanvas) 的函数指针. 这个指针都是以 C 方式命名, 提供于库的内部的. 在风魂++的实现中, 绝大多数 blit 函数都是用 nasm 写的纯汇编代码. 甚至只要你高兴, 可以在 C 语言中利用这些已经编写好的函数. 当然这需要你更多的去研究风魂++的源码.

  • Duplicate 同样是WObject 的派生类必须实现的接口, 它的实现方法很固定, 仅仅是调用在 WObjectHeap 上分配内存的 new 操作符, 返回一个复制出来的数据结构而已, 如果你想自己扩展风魂++, 可以参考任一个 WObject 的派生类(比如 WBitmap) 来实现它.

  • Affect 这个并不是 WObject 的派生类必须改写的接口. 它缺省返回 true. 某些绘图对象需要它是因为, 并不是所有的对象画到画布上时, 会影响全部 Width * Height 的矩形区域. 这个函数提供了一种手段, 让画布可以查询 对象具体影响了哪些区域块. 现在, 这个函数在直线对象中被实现了, 正如所想象的, 一条贯穿矩形对角的斜线, 所影响的区域 远远小于用 GetW() 和 GetH() 求得的整个矩形空间.

  • SetUserData 很多 WObject 派生类需要一些额外的参数来描述 绘制的方式(并不是一定有). 一般可以用这个函数设置用户定义的数据. 通常, 他们还会重载小括号来完成同样的工作.

WObjStruct

WObject 的数据指针, 指向了一个结构, 这个结构必须从 WObjStruct 继承, 也就是说, 必须有 kx, ky 两个数据.

struct WINDSOUL_API WObjStruct {
    int kx;
    int ky;
    void *operator new(unsigned size,WObjectHeap *heap);
    void operator delete(void *p,WObjectHeap *heap) {};
};
  • kx ky 指定了 WObject 的中心点坐标. 这个坐标使得对象不必按左上角(0,0)坐标去对齐去画. 比如当 kx ky 为 (10,10) 时, 把这个对象画到另一张位图的 (0,0) 点. 那么实际上, 这个对象的 (10,10) 这个像素被对应了目标图的 (0,0) 位置. 同时, 对象的左边10像素宽, 和上边 10 像素高被裁掉了. 这个例子同时说明, WObject 都必须完全的支持剪裁操作, 因为并不是每次, 整个对象都会被绘制到目标上, 它的四个方向都可能被剪裁掉一部分, 甚至全部.
    另外, 对于 WObject 的受体, 如Wbitmap, WCanvas, kx ky 还有另一个含义, 就是即将被画上去的对象将被画在什么地方. 诸如 WBitmap 这样可以作为绘制目标对象的类, 所提供的 Draw 函数, 都是不接收坐标参数, 而需要通过修改 kx,ky 值来决定位置的.

  • 这个基础结构还实现了用于画布操作的自己的堆分配 new. 它们统一预先分配了一块空间, 来加速 new 操作. 预分配空间是固定了结构大小的, 我们在 bmpint.h 里定义了一个宏 MAXOBJECTSTRUCTSIZE 来决定结构的大小上限.
    最后修改于 2001年9月12日 18:56:46


风魂++ 图形模块:像素对象

WPixel

在提到风魂++的位图(有如DirectDraw中的Surface)之前, 不得不先解释清 WPixel 像素, 这样有助于我们更好的控制位图.

它的定义是这样的:

struct WPixel {
    union {
        WORD color;
        struct {
            WORD blue:5;
            WORD green:6;
            WORD red:5;
        };
    };
    WPixel() {}
    WPixel(DWORD c);
    WPixel(int r,int g,int b);
    operator DWORD() const;
};

我们可以注意到, 它首先是一个 struct, 所有的成员都是可以直接控制的. 而内部被定义成一个 union, 你可以有更多的控制方法. 这里实现的是一个 16bit 颜色深度的像素(RGB 以 565 方式排列). 如果你用 sizeof 求大小的话, 将得到 2 bytes. 可以直接用 color 去直接修改值. 也可以用 red, green, blue 直接修改他们的分量. 当然需要留心, red 的范围是 0~31, green 的范围是 0~63, blue 的是 0~31.

同时,风魂++提供了几种常用的转换(都是用inline实现的,不必担心它们的效率). 你可以用一个 DWORD 来构造一个像素, 比如 0xff0000 就是红色. 也可以用 WPixel(255,0,0) 来分别提供颜色分量 (这里每个分量都是 0~255).

当然, WPixel 也可以被隐式转换成一个 DWORD

透明掩色

风魂++ 中使用粉红作为透明色. (粉红即0xff00ff. 红色, 兰色分量为最大, 绿色分量为 0). 这是需要注意的一点.

最后修改于 2001年8月27日 18:04:25


风魂++ 图形模块:位图

WBitmap

在风魂++中, 位图是图象处理中最重要的对象. 它的图象数据区是由 WPixel 构成的. 当然, 作为 WObject 的派生类. 它的数据指针指向了自己的一个结构. 这个结构不能太大, 所以并没有包含图象数据区本身, 而只是一个指针.

让我们先看看数据区的结构吧

struct WBmpStruct : public WObjStruct {
    int w;
    int h;
    int pitch;
    void *ptr;
    WBmpData *mem;
    int userdata;
};

对于大多数 WObject 派生出来的类, 它们的数据区的情况是不需要去了解的. 但是如果你希望扩展风魂++, WBitmap 作为 WObject 的受体, 在写新的对象时, 还是需要控制 WBmpStruct 里的数据的.

  • w h 存放的是位图的宽和高

  • pitch 是每行像素的跨度(以字节为单位). 由于数据对齐, 和存在子图这种概念等等原因, 它并不总是等于位图宽度的两倍.

  • ptr 指向位图第一个扫描行的第一个像素点地址.

  • mem 指向位图数据区结构的指针, 详情不做深入开发的话不必去了解. 如果位图的数据区是附在别的位图上(比如子图), 这个指针是 NULL. 你可以想象的到, 一个子图的数据区是附属在父位图上的, 如果父位图先于子位图销毁, 后果是严重的. 但是因为运行时的效率问题, 请使用者自己注意.

  • userdata 某些绘图方式(比如Alpha混合) 需要额外的数据, 所以提供了一个额外的数据位置. (在 Alpha 混合中, 就存放的透明度

构造与解构

  • Create 有三种显式构造函数

    WSERR Create(int w,int h);
    创建出 w * h 的位图, 分配相应的数据区.
    注:数据区里的数据是不可预知的

    WSERR Create(int w,int h,void *ptr);
    创建 w * h 的位图, 给出对应的数据区. 数据区由 ptr 提供. 并由创建者负责回收

    WSERR Create(const WBitmap& parent,int x,int y,int width,int height);
    从 parent 位图中的一个矩形区域创建出一个子图, 其数据区和父位图的对应部分共享.
    注:请不要在销毁子图前销毁父图, 这有可能导致操作子图的时候非法操作

  • 直接使用 WBitmap 的构造函数也是可行的, 它们实际调用了对应的 Create 函数

    WBitmap();
    缺省的构造函数,　并不创建出任何可操作的位图.
    WBitmap(int w,int h);
WBitmap(int w,int h,void *ptr);
WBitmap(const WBitmap& bmp,int x,int y,int width,int height);
    对应上面三种 Create 方式
    WBitmap(const WBitmap& bmp);
WBitmap& operator=(const WBitmap& bmp);
    拷贝构造是合法的. 但是和创建子图一样. 虽然被创建的位图可以当作普通位图来操作. 但是不具有自己的数据区. 而且不得在此副本在销毁前, 解构原本. 等号操作符在这里被重载, 完成了类似的工作.

  • SubBitmap

    WBitmap* SubBitmap(int x,int y,int width,int height) const;
    创建本身的一个子图. 返回的是一个 WBitmap 指针. 用完后应当用 delete 删除
    WBitmap operator() (int x,int y,int width,int height) const;
    风魂++ 重载了小括号的操作符, 如果小括号里带有 4 个整数参数, 那么将从自身构造出一个子图返回. 和 SubBitmap 不同, 它返回的是一个　WBitmap 对象, 而不是一个指针.

  • Destroy

    void Destroy();
    销毁位图. 它在位图的解构函数里会被自动调用

控制函数

  • operator[]

    WPixel * operator[](int y) const;
    风魂++重载了中括号操作, 返回一个扫描行指针. 这是一个 WPixel 指针. 所以用类似 bmp[y][x] 的语法就可以读取位图 (x,y) 坐标处的像素.
    注:风魂是不帮助你检查越界问题的,好自为之

  • SetUserData

    void SetUserData(DWORD userdata);
WBitmap& operator()(DWORD userdata);
    设置用户数据, 对于位图来说, 通常是用来设置透明度. 风魂重载了小括号, 其功用和 SetUserData 相同.

  • SetPos

    WBitmap& operator()(int x,int y);
WBitmap& operator()(WPoint p);
    其实 SetPos 是 WBitmap 基类 WObject 的成员函数. 用于设置对象的关键点. WBitmap 又重载了小括号,更方便的使用它.

  • Clear

    WSERR Clear(WPixel color);
    将位图清为单一色调. 传入参数为一个像素颜色.

  • Draw

    WSERR Draw(const WObject &obj, DWORD style);
    把一个可绘制对象按指定的样式绘制在自身上面. 绘制的位置取决于自己的关键点的坐标. 与被画的对象的关键点的坐标对齐. 样式的可取值, 取决于被画的对象的类型. 对于位图本身来说, 样式可以是以下值之一 (可以用 | 组合)

    • BLIT_NORMAL 普通模型, 既整图传送 (数值为0, 一条默认的规则就是, 任何 WObject 都支持 0 这种最常用的样式)

    • BLIT_COPY 同 BLIT_COPY

    • BLIT_ADDITIVE 色彩叠加方式, 其表现出来的结果是图被加亮, 通常用于光照效果

    • BLIT_SUBTRACT 色彩衰减方式, 其表现出来的结果是图变暗, 通常用于阴影

    • BLIT_TRANS 半透明方式, 透明度取决于 UserData. 0 为完全透明, 255 为完全不透明 (可以与 BLIT_MASK 一起使用)

    • BLIT_MASK 掩色模式, 位图上颜色为粉红(0xff00ff)的部分不会被画上

    • BLIT_BACK 反向传输, 特定环境下可能有用. 它的实际代码和 BLIT_NORMAL 一样, 但是是将自身的图象数据传输到参数给定的位图上.

void Draw(const char *s,WPixel color);

把字符串用颜色 color 输出到位图上. 这通常用于调试. 只能输出 ASCII, 使用的是内置的一种 12 像素点高的字体. 更丰富的文字输出请使用字体类.

  • RegisterDrawFunc

    void RegisterDrawFunc(BLIT_FUNC,DWORD style);

    如果想自己扩展绘图样式, 可以使用这个函数添加. 当然这还需要你研究一下风魂的源码了.

  • Load

    WSERR Load(void *bmpdata);

    从数据指针指向的地方解析一张.bmp文件读入. 这个函数并不做任何 I/O 操作. 所以通常你需要利用别的东西, 比如风魂提供的 文件模块 先把 bmp 文件读入内存, 然后把数据指针传给这个函数. 位图如果在前面已经创建, 将利用创建好的数据区. 如果没有创建,　这个函数会调用 Create 分配出适当的大小

    最后修改于 2001年8月28日 13:31:15


风魂++ 图形模块:带Alpha通道位图

WAlphaBitmap

使用这个类, 需要包含头文件 "wsalpha.h"

WAlphaBitmap 是 WBitmap 的派生类, 你完全可以把它当作一个 WBitmap 使用. 和 WBitmap 不同的是, 它多出了一个 Channel. 存放的 Alpha 信息, 即透明度, 范围是 (0~255). 0 为完全透明的点. 这种图一般是用 3ds max 使用预混合(缺省)方式制作出来的. 位图上的半透明的点(通常在轮廓上), 都已经和背景用 Alpha 值运算过. 所以,如果使用纯黑色做背景色, channel 里面的 alpha 值不可以大于 RGB 分量, 就是说, 如果将这些半透明点还原成和背景未做混合前的颜色. 不可以让 RGB 超过 255. 这一点上, LoadTGA 这个函数帮助你做了合适的修正.

成员函数

WAlphaBitmap 的继承了 WBitmap, 而且构造函数的使用方法也是相同的. 下面只列出一些特有的

  • ChannelLine

    BYTE * ChannelLine(int y) const;

    有时候需要对Alpha Channel 做控制, 这个函数返回了指定扫描行 channel 的数据指针.

  • LoadTGA

    WSERR LoadTGA(const void *tgadata);

    TGA图可以携带Alpha通道. 这个函数就可以加载一个带Alpha通道的图. 可以是 RLE 压缩的, 也可以是不压缩的 TGA, 但是不能是 256 色的.

    注: 和 WBitmap::Load 一样, 这个函数不负责 I/O 操作, 只是把一个 tga 文件的数据印像解释出来

  • Combine

    WSERR Combine(const WAlphaBitmap& bmp);

    通常, WAlphaBitmap 只能以 WBitmap 的形式作为 WObject 的接受体. 如果需要合并两个 WAlphaBitmap, 则需要这个函数.

  • ClearChannel

    void ClearChannel(int alpha);

    把 Channel 清空为单一的 Alpha 值.

最后修改于 2001年9月5日 14:47:31


风魂++ 文件模块

文件模块

风魂++的文件I/O扩展模块, 通过这个模块去操作文件(暂时只有读文件的功能) 可以使你拥有将一堆小文件打包成一个大的数据包的功能. 每个数据包可以被看作一个子目录. 在程序里自由使用. 最多支持 16 个数据包的同时操作.

  • 文件I/O类(WFile)
  • 文件打包/更新工具
最后修改于 2001年10月10日 17:13:31


风魂++ 文件模块:文件I/O类(WFile)

WFile

使用这个类, 需要包含头文件 "wsfile.h"

风魂内部所有的文件I/O都是通过这个类完成的, 同时推荐使用者尽可能的通过这个类来读取文件,而不要使用 stdio 或者 Win32 的 API 等等. 使用它的好处是, 你可以将大量的小文件通过一个工具打包成一个数据包文件. 在程序中, 只要打开了这个数据包, 这个数据包就可以被看作是一个文件夹. 除非外部有一个同名目录, 且下面有同名文件, 程序将优先打开外部文件而不是数据包内部的.

  • OpenDataFile
    static WSERR OpenDataFile(const char *filename);

    打开一个数据包, 这是一个静态函数, 对所有以后的 WFile 操作都有效, 最多可以同时打开 16 个数据包. 每个被打开的数据包文件都被看做是一个虚拟的文件夹. 注意:数据包文件的后缀必须是 wdf

  • Load
    WSERR Load(const char *filename);

    加载一个文件, 这个函数将分配合适的空间来安置这个数据. 当对象生命期结束的时候, 这些空间会被释放掉. 如果调用两次 Load, 前一次分配的空间也将被正确释放.

  • GetPtr
    operator void *() const;
void *GetPtr();

    将 Load 函数加载的数据的地址返回.

    void *GetPtr(int offset);

    将 Load 函数加载的数据的地址加上一个偏移量再返回.

  • Open
    WSERR Open(const char *filename);

    以只读方式打开一个文件.

  • Read
    WSERR Read(void *buffer,int s);

    从打开的文件里读出 s 个字节到 buffer.

    WSERR Read(void *buffer,int s,int offset);

    从打开的文件的 offset 偏移处读出 s 个字节到 buffer. 这个函数的另一个用途是定位文件读指针, 方法是传入的 buffer 为0, 读取字节数也为 0, 只指定 offset 值.

  • Skip
    void Skip(int s);

    将文件读指针向后移 s 字节.

  • GetSize
    DWORD GetSize();

    获得文件的长度

  • Tell
    DWORD Tell() const;

    得到文件读指针的位置

  • Close
    void Close();

    关闭文件

  • IsEnd
    bool IsEnd() const;

    返回文件是否已经读到尾部

    最后修改于 2001年10月10日 17:41:45


风魂++ 图形模块:画布

WCanvas

使用这个类, 需要包含头文件 "wscanvas.h"

画布并不是使用风魂++开发游戏必须的, 但是它是被提出的新概念中最重要的一个. 使用的好, 游戏的速度可以成倍的提高.下面会对画布的原理做一个深入的解说, 理解了原理, 才可以灵活的使用.

画布从 WBitmap protected 继承下来, 它是一个纯粹的 WObject 受体, 通常只能接受 WObject 画在上面, 而取得本身的数据却需要特别的方法. 我们利用 画布进行加速. 原理有四个方面.

  • 画布本身在内部被切割成 64 * 32 的小格子, 每个格子被称为一个优化单位块. 我们知道, 无论2d游戏多么复杂, 在每两帧图之间, 总有一些区域的图象相对上一帧没有变化, 这样, 我们可以直接 保留上一帧的图象, 不用重新操作. 风魂++ 的画布里， 就是以这样的一个个矩形格子作为优化单位的.
  • 靠中层代码(游戏实现和底层图象engine之间的部分)很难直接知道那些区域被修改了, 和上一帧有所不同, 所以这里引入异步绘图指令操作的概念, 让画布在每一帧都接受所有画布上存在的对象的绘图操作指令, 但是并不立刻运行, 而是等待操作全部结束以后, 所有指令都进入了待处理队列. 通过和上一次操作的比较, 来确定每个优化块里的指令运行结果是否和上一帧的运行结果相同, 来决定是否需要实际运行这个指令队列. 风魂++里是怎么实现这一步的呢? 实际画布的每个优化块只记录了上一帧被画的对象数目. 如果数目不同, 绘图结果肯定不同, 绘图指令队列就会被实际运行. 另外需要调用者自己发出消息通知画布, 每个被送上去的 对象是否相对上一帧的对象有所改变, 这种改变可以是对象本身的, 对象的坐标变化, 或者是新增了一个对象.
  • 对于一些会覆盖下方图像的对象, 可以向画布设置一个覆盖矩形, 通知画布某些区域被覆盖掉了, 再它下面 的绘图操作可以忽略. 也正是这种优化形式的存在. 我们向画布送绘图对象和指令时, 是从前向后的方式, 而不是通常画家算法里从后向前的次序.
  • 2d 游戏通常需要卷屏. 卷屏的时候, 大多数区域只是位置的移动, 而数据实际并未改变. 所以画布被设定成游戏世界坐标系而不是屏幕坐标系的. 一般卷屏时, 仅仅是优化块对应屏幕位置的重新组合. 所以在卷屏后, 只要绘图对象画到原来游戏世界的坐标没变, 优化块还是可以正常工作, 它是不理会是否发生卷屏操作了的.

画布的接口

  • Move
    void Move(int x,int y);
void Move(WPoint p);

    相对当前的游戏世界坐标移动画布 (x,y) 这个移动指令必须在当前帧所有绘图指令之前发送, 才可以保证正常的显示

  • MoveTo
    void MoveTo(int x,int y);
void MoveTo(WPoint p);

    和 Move 类似, 这个是移动画布到游戏世界的绝对坐标

  • IsMoved
    bool IsMoved() const;

    返回画布这一帧是否移动过

  • GetX GetY
    int GetX() const;
int GetY() const;

    获取游戏世界坐标 (x,y) 注意并不是你看到的屏幕坐标

  • GetW GetH
    int GetW() const;
int GetH() const;

    获得 Canvas 的可视区域的宽度高度. (注:由于滚动优化的需要,画布的实际数据区要比实际看到的可视区在宽度和高度上都要大一个优化块的, 这组函数得到的是可视区域的宽度高度)

  • GetViewPort
    WPoint GetViewPort(int x,int y) const
WPoint GetViewPort(WPoint p) const;

    从屏幕坐标, 换算成相对游戏地图的坐标.

  • SetPos
    WCanvas& SetPos(int x,int y);
WCanvas& SetPos(WPoint p);
WCanvas& operator() (int x,int y);
WCanvas& operator() (WPoint p);

    设置关键点, 它和 WObject 的关键点不同. 其坐标是按游戏世界的坐标系的. 风魂++ 也重载了小括号来方便这个操作.

  • ViewPort
    WCanvas& ViewPort(int x,int y);
WCanvas& ViewPort(WPoint p);

    以相对视口(既屏幕)的坐标系统来设置关键点. 这个函数会在内部转换成游戏世界坐标系, 调用 SetPos 来完成操作.

  • Draw
    WSERR Draw(const WObject &bmp, DWORD style);

    把一个 WObject 送入画布的指令队列. 这条指令并不会立刻运行. 它会等待 Update 的时候根据和上一帧状态的比较来决定是否真的起作用. 如果需要取得当前画布的实际图象数据, 可以使用一个 WBitmap 利用 BLIT_BACK 来接受,

    void Draw(const char *str, WPixel color);

    使用类库提供的 12 点高 ASCII 字模, 把绘制一个英文字符串的指令放入画布指令队列. (可以使用指定的颜色). 一般情况下, 并不使用这条指令, 而推荐用 WFont 类. 这个大多情况用于调试.

    void Draw(WCanvas &canvas, DWORD style);

    把一个画布画在这个画布上面. 这个函数的内部实现, 或许比你想象的有复杂的多. 它会根据被画的画布的实际改变情况来进行优化. 需要注意的是, 一旦一个画布被画在别的东西上, 它的状态就被设置成等待下一批 的指令传输进去. 缺省的 style 是 BLIT_COPY, 缺省状态时, 它会自动在父 canvas 上设置覆盖矩形. 如果你使用 BLIT_MASK 方式, 最好能自己设置一个合适大小的覆盖矩形.

  • DrawEx
    WSERR DrawEx(const WObject &bmp, DWORD style);

    同 Draw 一样, 只是这个函数针对某些Wobject进行进一步的优化, 比如斜线. 斜线可能占据了很大面积的矩形区域, 而真正影响到的优化块只占这个举行区域的很小比例. 推荐在画线的时候使用 DrawEx 而不是 Draw.

  • Clear
    void Clear();

    不带参数的 Clear 将把画布的状态归0. 它的下一帧的所有操作都必定被运行.

    void Clear(WPixel color);

    把清空画布为指定颜色的指令放入队列. 按照画布的指令是从上想下发送的规则. 这条指令一定是一帧图的最后一条绘图指令. 因为在它之后的指令都没有意义了.

  • SetOvlRect
    void SetOvlRect(int w,int h);
void SetOvlRect(const WRect &rect);

    设置一个覆盖矩形, 当这个矩形被设置到画布, 在设置之后的 Draw 操作, 如果需要画的对象在这个矩形内, 操作将被忽略掉. (注:设置多个覆盖矩形的话,每次设置新的矩形都会和前面已经有的矩形合并, 以达到最好的效果)

  • UnChange
    WCanvas& UnChange();

    通知画布,下面即将画上去的对象相对相对上帧这个对象的位置.状态都没有变化

  • Change
    WCanvas& Change();

    通知画布,下面即将画上去的对象相对相对上帧这个对象的位置或者状态起了些变化

  • SelfChange
    WCanvas& SelfChange();

    通知画布,下面即将画上去的对象相对相对上帧这个对象位置没有变化, 但是自身变化了. 这种变化, 不会影响这个对象后面的东西. 比如游戏里有一堵电影墙. 墙上的电影是动画的, 但是这个动画并不影响墙后面的画面. 所以在每次更新电影墙的时候, 应该用 SelfChange, 比用 Change 可能会有更好点的效果. (当然如果为墙设置一个覆盖矩形, 效果会更妙)

  • Update
    void Update();

    Update 真正去运行了画布的指令队列里, 认为必须运行的指令. 当然这个函数一般不需要使用者主动调用. 下面的诸如 Blit2DC 之类的函数会自己去调用 Update 的.

  • SkipFrame
    void SkipFrame();

    和 Update 不同, 它放弃了所有的绘图指令的直接操作. 一般在游戏运行速度不够的时候做跳帧用的.

  • NextFrame
    void NextFrame();

    在完成了 Update 和将画布的数据 Buffer 的操作后, 需要对画布的一些状态设置, 以准备下一帧的指令接受.

  • Blit2DC
    void Blit2DC(HDC hDC,int x,int y);

    首先 Update 画布指令队列里的操作, 然后把画布和上一帧相比改变了的部分传输到 DC 上. 并为下一帧做好准备.

  • Update2DC
    void Update2DC(HDC hDC,int x,int y) const;

    和 Blit2DC 不同, Update2DC 不 Update 画布的指令队列, 不对画布本身做任何影响, 但是他把画布整个 Buffer 区送到 DC 上. 一般在窗口的 OnPaint 里调用

  • Reset
    void Reset(int f);

    Blit2DC 中有一段控制帧数的代码. 原理是画一帧图前, 检查上一帧图产生的时间间隔. 如果太短, 就用系统的 Sleep 释放出一段 CPU 时间. 这个函数就是设置控制画布刷新帧数的. 如果设置为 0 就是无限制.

画布的使用简介

每画一帧图以下列次序进行

  1. 如果有需要, 就调用 Move 移动画布的视口到指定的游戏直接的位置
  2. 把需要绘制的对象准备在一个链表里
  3. 按从上到小的次序把需要画的对象 Draw 到画布上. 如果对象相对上一帧是新增加的, 或者相当上一帧的对象有改变, 用 Change (或者 SelfChange) 先通知画布再画. 否则用 UnChange 通知画布, 准备优化掉下一次的操作.
  4. 如果有不透明的对话框之类的对象画到画布上, 最好在 Draw 操作完后, 再设置一个相应的覆盖矩形, 充分优化.
  5. 调用 Blit2DC 将画布刷新, 传输到 DC 上
  6. 在窗口的 OnPaint 里调用 Update2DC

录象

可能您的游戏制作完毕后需要录制宣传片, WCanvas 带有一个录象的功能, 可以将它上边的曾经拥有的数据改变过程完整的记录在硬盘上. 当然前提是您有足够大的硬盘空间, 和不太小的内存.

使用这个功能, 需要在 wscanvas.h 里打开 _RECORD_CANVAS 这个宏. 那么 WCanvas 就多了一个成员函数 Record. 这是一个乒乓开关. 第一次调用的时候, WCanvas 将开始记录所以画在自身的数据(放心,只记录跟上帧不同的地方,比较省内存). 第 2 次调用的时候, 会把这期间的数据写盘. 默认的目录是 d:/record, 当然你可以在 Record 的参数中传入目录名, 当然请保证目录的存在和硬盘有足够大的空间, 因为每帧图都要保存为一个 24bit 的 bmp 文件哟.

最后修改于 2001年11月11日 11:54:06


风魂++ 图形模块:几何对象

使用这个类, 需要包含头文件 "wsgeo.h"

风魂++里, 直线, 矩形等等也是一种从 WObject 里派生出来的对象. 下面讲这些几何对象归到一起.

WLine

WLine 不允许拷贝构造, 也不允许用 = 复制. 而且它必须在构造的时候写明斜率和颜色. 下面是它的构造函数:

WLine(int x,int y,WPixel color);

x,y 指明了直线的方向, color 指定了颜色. 构造了直线对象后, 就可以把它画到位图或画布上了. 关键点被映射在 这条线段的起点. 当然你可以去调整它. (比如或许你需要创建一个十字的对象, 它是由两条交叉的 WLine 构成, 调整关键点, 把两条线段的关键点都设置在线段的中间会更方便一些)

WLine 支持了两种绘图方式.

  • BLIT_NORMAL 普通的画线方式
  • BLIT_TRANS 半透明的方式, 依旧按习惯用 SetUserData 设置 (0~255) 的透明度

在画布画斜线的时候, 由于画布是按区域是否改变来优化绘图操作, 普通的 WObject 都是类似矩形的, 而斜线却不是, 它在矩形区域中只占据了很小的区域, 所以建议使用 WCanvas::DrawEx 来画.

WLine& Color(WPixel color)

可以用于更换对象的颜色

WBox

WBox 也不允许拷贝构造, 也不允许用 = 复制. 而且它必须在构造的时候指定其大小和颜色. 下面是它的构造函数:

WBox(int w,int h,WPixel color);

w,h 指明了矩形的大小, color 指定了颜色. 构造了矩形对象后, 就可以把它画到位图或画布上了.

WBox 支持了两种绘图方式.

  • BLIT_NORMAL 普通方式
  • BLIT_TRANS 半透明的方式, 依旧按习惯用 SetUserData 设置 (0~255) 的透明度
WBox& Color(WPixel color)

可以用于更换对象的颜色

最后修改于 2001年11月11日 15:39:51


风魂++ 图形模块:文字对象

使用这个类, 需要包含头文件 "wsfont.h"

风魂++里, 对 Windows 本身的字体做了封装, 以适合位图或画布. 为了将 Windows 提供的文字输出, 这里提供了两个相关的类: WFont 和 WChar. 我们一般先从 Windows 的 HFONT 里创建出一个 WFont, 然后从 WFont 中创建 WChar 画到位图或画布上. 当然 WFont 也提供了简洁的方案可以输出字符串.

WFont

WFont 实际是一个字模点阵数据Cache管理器. 它负责将申请要画出来的文字产生成带 Alpha 的点阵信息. 并由 Cache 管理.

  • Create

    WFont(HFONT font,int alpha=16,int cachesize=128);
WSERR Create(HFONT,int alpha=16,int cachesize=128);

    从 HFONT 里构造出 WFont, 并可以指定 WFont 的 Cache 大小. Cache 越大, 越消耗内存, 但是速度比较快. 建议比较常用的小号的字体设置大一些的 cache, 而反之则设置小一些. 当然可以使用缺省的设置. HFONT 需要用 Win32 的 API: CreateFont 来创建, 一般的创建形式为:

    HFONT font=CreateFont(
        30,0,
        0, 0,
        FW_NORMAL,
        FALSE, FALSE, FALSE,
        DEFAULT_CHARSET,
        OUT_DEFAULT_PRECIS,
        CLIP_DEFAULT_PRECIS,
        PROOF_QUALITY,
        DEFAULT_QUALITY,
        "仿宋");

    如果 alpha 为 0, 就不会创建反混淆用的过度色. 缺省是产生出 16 级灰度.

    不要忘记在不使用这种字体后, 使用 DeleteObject 删掉 HFONT

  • Destroy

    void Destroy();

    销毁字体, 通常不需要显式调用. 在 WFont 的解构函数里已经调用了.

  • GetHeight

    int GetHeight() const;

    得到当前字体的高度(像素点单位). Windows 的字体虽然不等宽, 但是一定等高.

  • Lock

    void Lock();

    通常需要在画一帧图的前面调用这个函数, 锁定 WFont 的 Cache, 这条指令后面所有用到的文字的点阵数据都将保存在 Cache 里, Cache 满后将自己增大 Cache 空间. 直到再次 Lock, 或 Unlock Cache.

  • Unlock

    void Unlock();

    解锁 Cache, Cache 不再增长, 如果 Cache 满, 再请求新的字的时候, 以前使用频率最低的字将被清除 Cache 外.

  • Draw

    void Draw(WBitmap &buffer,const char *str,WPixel color, DWORD style=FONT_ALPHA);
void Draw(WCanvas &buffer,const char *str,WPixel color, DWORD style=FONT_ALPHA);

    以指定样式和颜色, 向位图或者画布输出一字符串.

WChar

我们从 WFont 中创建出 WChar, 就可以输出了. WChar 是从 WObject 派生出来的.

  • Create

    WChar(WFont &font,unsigned int c,WPixel color);
WSERR Create(WFont &,unsigned int c,WPixel color);

    从一个 WFont 中创建出指定字的对象来, 这个字可以是单字节的, 也可以是双字节的.

  • Destroy

    void Destroy();

    销毁, 通常不需要显式调用. 在 WChar 的解构函数里已经调用了.

  • GetWidth

    int GetWidth() const;

    返回字的宽度(像素点单位)

  • Draw 的样式

    WChar 支持两种 Draw 的样式

    • FONT_ALPHA 带 Alpha 融边的输出(推荐)
    • FONT_NOALPHA 不带 Alpha 融边的输出(不推荐)

最后修改于 2001年9月5日 17:32:44


风魂++ 文件模块:文件打包/更新工具

文件打包/更新工具

在发布的 wpp16.cab 源码包里可以找到一个叫做 wdfpck 的子目录, 编译里面的工程, 就可以生成一个叫做 wdfpck.exe 的命令行工具, 主要配合 WFile 使用. 使用方法很简单, 先制作一个 filename.lst 的文件. 里面每行写一个需要打包的文件名, (可以有子目录,但必须是相对路径). 用 wdfpck filename 就可以开始打包. 如果当前目录不存在 filename.wdf 这个文件, 将生成一个新的后缀为 wdf 的数据包. 如果已经存在, 将根据 lst 文件更新数据包, lst 文件里不存在的文件, 将从老的 wdf 文件里删掉, 新的文件将被增加. 同名文件, 如果有数据改动, 也将被更新. 这个工具在更新数据包后, 可能会有数据冗余. 这个设计是为了使新旧包的差异减少而设计的. 没有改变的数据, 都将放在原有的位置. 如果你在意数据包的大小, 每次打包前最好都将旧的数据包文件删除.

最后修改于 2001年10月10日 18:08:16


风魂++ 辅助模块

风魂++ 为方便程序设计, 提供了一些辅助类.

  • 常用运算
  • 坐标点类(WPoint/WPointEx)
  • 矩形类(WRect)
  • 字符串类(WString)
  • 精密时钟类(WTimer)
  • 内存操作
  • 其它
最后修改于 2001年11月11日 12:34:31


风魂++ 常用运算

以下操作都是 inline 的模板, 效率可以保证

  • MIN(T i,T j)

    取 i,j 里较小的一个

  • MAX(T i,T j)

    取 i,j 里较大的一个

  • MOD(T i,T j)

    相当于 i%j. 但是又有不同, 因为 C 语言里对负数取模得到是负数, 但是在游戏里换算坐标的时候, 却不能这样. ok, 你可以用这个函数去做 mod 操作, 会得到你想要的结果.

    例: -1%7 = -1, 而 MOD(-1,7)=6

  • DIV(T i,T j)

    相当于 i/j. 但也有不同, 还是因为 C 语言里对负数的除法的处理的不同. 有时候, 我们希望 -1/7=-1 而不是 0. 这个使用请使用这个函数.

  • ABS(T i)

    取 i 的绝对值

  • SWAP(T &i,T &j)

    交换 i,j 的值

最后修改于 2001年11月11日 12:48:31


风魂++ 辅助模块:坐标点类

WPointEx

template <class T>
struct WPointEx {
    T x;
    T y;
    WPointEx();
    WPointEx(T x,T y);
    WPointEx(const WPointEx &p);
    WPointEx operator+(const WPointEx &p) const;
    WPointEx operator-(const WPointEx &p) const;
    bool operator==(const WPointEx &p) const;
    bool operator!=(const WPointEx &p) const;
    WPointEx& operator+=(const WPointEx &p);
    WPointEx& operator-=(const WPointEx &p);
    WPointEx& operator=(const WPointEx &p);
    bool IsLeft(const WPointEx &p) const;
    bool IsRight(const WPointEx &p) const;
    bool IsUp(const WPointEx &p) const;
    bool IsDown(const WPointEx &p) const;
};

风魂里定义的用于处理坐标点的模板. 可以把一组 (x,y) 做加减, 判断是否相等之类的操作.

WPoint

typedef WPointEx<int> WPoint;

这是 WPointEx 的 int 型的特例. 在风魂的很多函数里用到了这个类型

最后修改于 2001年11月11日 13:14:31


风魂++ 辅助模块:矩形类

WRect

struct WRect {
    int x;
    int y;
    int w;
    int h;
    WRect();
    WRect(int x,int y,int w,int h);
    WRect(WPoint &p,int w,int h);
    bool IsIn(const WRect &rect) const;		// 是否在另一个矩形区域里
    bool IsOut(const WRect &rect) const;		// 是否在另一个矩形区域外
    WRect HorRect(const WRect &rect) const;	// 产生水平相交部分区域
    WRect VerRect(const WRect &rect) const;	// 产生垂直相交部分区域
    WRect& operator+=(WPoint &p);
    WRect& operator-=(WPoint &p);
    WRect operator+(WPoint &p) const;
    WRect operator-(WPoint &p) const;
    bool IsCover(WPoint &p) const;
};

风魂里定义的用于处理矩形的类.

最后修改于 2001年11月11日 13:32:31


风魂++ 辅助模块:字符串

WString

使用这个类, 需要包含头文件 "wsstring.h"

在风魂++中, 提供了一个高效易用的字符串类. 它可以看作是 MFC 中 CString 的一个子集. 但是效率上却比 CString 高出 2~4 倍.

class WINDSOUL_API WString {
    char *str;
static char *_emptystr;
protected:
    const STRING_DATA &GetData() const;
    STRING_DATA &GetData();
    WString(const WString &s,char c);
    WString(char c,const WString &s);
    WString(const WString &s1,const char *s2);
    WString(const char *s1,const WString &s2);
    WString(const WString &s1,const WString &s2);
    WString(const char *s,unsigned len);
public:
    WString();
    WString(char c);
    WString(const char *s);
    WString(const WString &s);
    WString(unsigned max_len);
    ~WString();

    WString & operator=(char c);
    WString & operator=(const char *s);
    WString & operator=(WString &s);

    WString & operator+=(char c);
    WString & operator+=(const char *s);
    WString & operator+=(WString &s);

    WString operator+(char c) const;
    WString operator+(const char *s) const;
    WString operator+(WString &s) const;
    friend inline WString operator+(char c,WString &s);
    friend inline WString operator+(const char *s1,WString &s2);

    int Compare(const char *s) const;
    int CompareNoCase(const char *s) const;

    bool operator==(char c) const;
    bool operator==(const char *s) const;
    bool operator==(const WString &s) const;

    bool operator!=(char c) const;
    bool operator!=(const char *s) const;
    bool operator!=(const WString &s) const;

    bool operator>(char c) const;
    bool operator<(char c) const;

    bool operator>(const char *s) const;
    bool operator<(const char *s) const;

    bool operator>=(char c) const;
    bool operator<=(char c) const;

    char operator[](int id) const;
    char &operator[](int id);

    unsigned GetLength() const;
    bool IsEmpty() const;
    void Empty();
    operator const char*() const;

    WString operator()(int left) const;
    WString operator()(int from,int len) const;
    WString Left(int left) const;
    WString Mid(int from,int len=-1) const;
    WString Right(int right) const;

    void MakeUpper();
    void MakeLower();

    int AsInt() const;

    WString &Format(const char *format, ...);

    char *GetBuffer(int minlen);
    void ReleaseBuffer();

    char *LockBuffer();
    void UnlockBuffer();
};

以上是 WString 的定义. 可以看到, 你可以用const char*, char 要构造它, 也可以在构造的时候指定长度. 或者使用缺省构造函数构造出一个空串.

可以方便的用 +, += 来连接字符串, 用 ==, !=, >, >=, <, <= 来比较大小.

用中括号来取得字符串里的一个字符.

以上所有的这些都和 CString 的使用相同.

  • GetLength

    unsigned GetLength() const;

    获取字符串的长度

  • IsEmpty

    bool IsEmpty() const

    判断字符串是否为空

  • Empty

    void Empty()

    清空字符串

  • Left

    WString operator()(int left) const
WString Left(int left) const

    取左边 left 个字节生成一个新的空字符串

  • Mid

    WString operator()(int from,int len) const
WString Mid(int from,int len=-1) const

    从 from 取 len 长的一个中串. 如果忽略第2个参数, 则从 from 处取到末尾.

  • Right

    WString Right(int right) const

    取右边 right 个字节生成一个新的空字符串

  • MakeUpper

    void MakeUpper()

    把字符串全部变成大写

  • MakeLower

    void MakeLower()

    把字符串全部变成小写

  • AsInt

    int AsInt() const

    把字符串转换为 int

  • Format

    WString &Format(const char *format, ...)

    相当于 sprintf 的功能啦. 不过请不要使用 %f, 这里并不支持 float 类型

  • GetBuffer

    char *GetBuffer(int minlen)

    得到 Buffer(数据可能破坏), 设置最小需要的长度

    注意:和 CString 不同, 这个函数不保证数据安全, 里面原有的数据是可能被破坏掉的

  • ReleaseBuffer

    void ReleaseBuffer()

    释放 Buffer, 设置新长度

  • LockBuffer

    char *LockBuffer()

    lock 住 Buffer(数据不破坏), 不能被引用

  • UnlockBuffer

    void UnlockBuffer()

    unlock 不能被引用的 Buffer

    最后修改于 2001年11月11日 14:00:15


风魂++ 辅助模块:精密时钟类

这个类使用了 Pentium 以上的 CPU 的内部计数器

使用这个类, 需要包含头文件 "wstimer.h"

WTimer

  • CPU
    static int CPU()

    返回 CPU 主频. MHz 为单位. 这个函数在 WTimer 构造的时候自动调用

    注:某些笔记本在空闲的时候会降低主频

  • Reset
    void Reset(int t=0)

    初始化计时器

  • Start
    void Start()

    启动时间检测

  • Stop
    DWORD Stop()

    得到时间检测时间(最小单位是 16 时钟周期, 最大周期 P200 上 5 分)

  • Stop
    DWORD GetTime()

    返回当前计数值 (单位为 1/10000 秒)

最后修改于 2001年11月11日 16:55:31


风魂++ 辅助模块:内存操作

使用风魂++的时候推荐使用风魂++附带的内存操作函数,这样可以有更多的调试信息.

  • WAlloc

    相当于 malloc

  • WFree

    相当于 free

  • WMemCpy

    相当于 memcpy

最后修改于 2001年11月11日 15:22:31


风魂++ 辅助模块:其他

  • WString2ID

    DWORD WINDSOUL_API _stdcall WString2ID(const char* string)

    把一个字符串转换成一个 DWORD 用于Map 或者识别. 虽然有可能两个字符串可能转成同一个 DWORD. 但是这样可能性非常之低

  • WFourCC(str)

    把一个4byte 的字符串比如 "WIND", 转成一个2进制等价的 DWORD

最后修改于 2001年11月11日 15:22:31


风魂++ 程序框架类

风魂++为不想用 MFC 这种庞大的框架类的朋友准备了一组短小精悍的类. 你可以用它们构架出一个简单的 Windows 运用程序.

使用这个类, 需要包含头文件 "wsapp.h"

Sorry.... 还没有写完

最后修改于 2001年11月11日 15:33:31


风魂++ 附加类库

风魂++除了基础类库外, 还拥有丰富的扩展功能. 但是不包括在免费发放的源码包中. 它们是供商业游戏开发者使用. 比如, jpeg 加载, 256色RLE/AlphaEdge的精灵, 随机数发生器, 声音驱动和管理, 等等. 甚至你需要更多的功能扩展, 都可以直接于云风联系.

Sorry.... 还没有写完

最后修改于 2001年11月11日 15:35:31


风魂++ 调试

内存泄露的监控

风魂++对内存泄露问题, 加入了很强的监控信息. 因为所有的 WObject 派生对象都有自己的 new/delete 操作符. 所以, 你的所有分配操作都被记录在案(当然是 DEBUG 模式下). 在 VC 的调试环境下, 用 F5 运行程序, 这些信息都会被输出到 Output 窗口. 一般情况下, 发生泄露的行信息, 并没有记录下来. 如果你希望看到造成泄露的行在哪里, 请在源代码中包含 wsdbgnew.h 这个头文件. 风魂++ 的这项功能, 有时候会和 MFC 中的类似功能发生冲突. 如果真的发生了, 为了避免它, 你可以在你第一次包含 windsoul.h 前面定义一个宏:

#define _IGNORE_WSDEBUGNEW

忽略掉 windsoul 的调试信息记录.

WCanvas 的调试

有时候我们需要看到 WCanvas 的工作情况. 看它是否做到了最大的优化, 是否在帧间没有改变的时候不去刷新那些未改变的块. OK, 你可以选择我为你准备的 CanvasDebug 模式. 在 Project 里可以选择. 或者在 canvasin.h 里定义

#define _DEBUG_CANVAS

这个版本会把上帧未改变的区域标出来. 并会写上每个优化块上被画了多少个 WObject. 一目了然 :)

最后修改于 2001年11月11日 12:12:31