..;;;;,                     ;;;,    
             ..;;;"` ;;:           ,;;;;;: ,;;;:.,;..
       ,;..,;;"`    :;;'            :;;"`,;;;;;;"":;;
       ;;;"  `:;;. ;;'           ..;;:  .;;,.;;:',;;"
      .;;`   ,;;" .;"          ,;;;;;;" :;`',;",;;"   
     ,;;,:.,;;;  ,;:          :" ,;:` , `:.;;;;;'`            _/
     ;;"'':;;:. .;; .          ,;;;,;:;;,;;;, ,;             _/
    :;;..;;;;;; :;' :.        :;;;"` `:;;;;;,;,.;.      _/_/_/_/_/
  .;;":;;`  '"";;:  ';;       '""   .;;`.;";:;;;;` ;,      _/
 ;;;" `'       "::. ,;;:          .;"`  ::. '   .,;;;     _/ 
 ""             ';;;;;;;"        ""     ';;;;;;;;;;`    
 
                     WIND SOUL PLUS

                  基于 DirectX 的游戏程序库
        A Game Programming Library Base On DirectX    
  
                by 云风 (Cloud Wu)  1999-2000                          

            http://member.netease.com/~cloudwu
            mailto:cloudwu@263.net

目录


使用介绍

  风魂+ 脱胎于C版风魂, 是用 C++ 重新编写, 结构做了较大改动, 但在对外接口上尽力保持一致. 如果你使用过 旧版风魂, 可以跳过这一节. 但仍旧希望仔细阅读, 以了解一些不同之处.

风魂游戏程序库推荐在 Visual C++ 6.0 上使用, 请按照以下步骤:

返回页首

程序库相关

风魂中为了避免一些不使用的功能浪费资源, 冗余代码和静态数据使最终编译出来的 exe 文件过大, 使用模块注册方法由用户自己选择需要的模块. 方法是 INSTALL(模块名)

这是一个宏, 实际调用的是
WSP::install(模块初始化函数指针,模块激活函数指针,模块结束函数指针,模块 ID)
INSTALL(模块名) 将立刻运行模块的初始化函数, 如果加载成功则返回 0. 当存在激活函数, 将注册到一个函数指针数组, 在程序切换时调用; 并在用户程序结束后, 按模块加载的反序调用结束函数. 模块 ID 是一个 32bit 常数, 它将被注册到一个数组中, 用于避免模块被重复加载, 或由用户自己检测某个模块是否已经加载.

如果你想扩展风魂, 请将你的模块写成一个类, 这个类必须有 3 个函数。 init() active() end() 另外请定义一个宏: 模块名_ID . 注意不要和已有 ID 重复. 关于 ID 的定义, 可以参考 wsp.h 请适当注意模块的加载次序, 比如在 MOUSE 模块前加载 DDHAL, MOUSE 光标的显示将使用硬件加速

int WSP:install(模块_ID)

如果已经成功加载模块, 返回 1; 否则返回 0.

返回页首

显示模式

风魂暂时只支持高彩模式. 可以选择 GDI 窗口模式和 DDRAW 全屏模式, 和DDRAW 硬件加速模式. 关于高彩模式, 有 RGB555 和 RGB565 两种子模式. 当你选择不显示的时候(主要用于做图象处理) 系统为你设置的是 565 模式. 如果你选择 GDI 窗口模式, 系统将设置为 555 模式. 而 DDRAW 全屏模式将根据你的显卡来决定 555 还是 565 模式. 所有的位图加载, 颜色设置, 都将依赖于色彩模式. 所以请不要在没有确定色彩模式前使用它们, 否则将可能得到不正确的颜色. 关于 DirectDraw 硬件加速模式, 将放在下一部分详细讲解.

你可以用 INSTALL(GDI) 或者 INSTALL(DDRAW) 初始化显示模块, 或者可以用 INSTALL(AUTO) 根据你是 DEBUG 版本, 还是 RELEASE 版本, 自动选择 GDI/DDRAW. 在初始化显示模块后, 便可以调用 WSP:display(宽,高,图层) 来初始化分辨率. 图层参数是可以省略了, 它描述了 screen 这个屏幕缓冲位图包含的图层. 关于图层, 在位图一节将有详细介绍。 调用了 WSP:display() 后, 色彩模式将确定下来. 在程序中动态切换分辨率是允许的.

int WSP::display(int width,int height,int layer)
设置分辨率为 width * height, 在 GDI 模式下, 可以是任意分辨率 (但建议长宽都是 4 的倍数, 否则有可能某些函数工作效率降低) 在 DDRAW 模式下, 必须是显卡可以支持的分辨率, 比如 320x200, 640x480, 800x600. 如果设置分辨率失败, 函数将返回非 0 值.

关于 ZOOM_MODE
如果你的程序运行在 DDRAW 全屏模式, 风魂支持一种 4 倍放大模式. 就是说, 你的后台缓冲区的大小只有 实际分辨率的 1/4. 然而在显示的时候, 系统将为你滤波放大. 这样可以减少内部的数据量. 设置方法是在参数 layer 上或一个常量 ZOOM_MODE. 例:
WSP::display(320,240,Z_BUFFER|ZOOM_MODE);
将初始化为 640x480 显示模式 , 但后台缓冲位图 screen 的大小为 320x240 (带 Z-Buffer) 在 GDI 模式下, ZOOM_MODE 标记将被忽略.

enum display_mode WSP::get_display_mode()
这个函数将返回当前的显示模式, 是一个枚举类型常量, 目前可能的返回值有: display_none,display_gdi,display_ddraw,display_zoom

void WSP::update_area(int startline,int height)
设置屏幕刷新范围, 参数为开始扫描行和高度.

void WSP::update()
更新屏幕, 将后台缓冲位图 screen 的内容刷新到屏幕显示.

返回页首

DDraw 硬件加速模式

风魂plus 增加了一种利用 DirectDraw HAL 层实现硬件加速功能的模块, 可以使用 INSTALL(DDHAL) 加载. 在设置分辨率后, 模块将检测你的硬件(显卡) 是否支持(主要是显存数量). 如果不支持, 你虽然还是可以使用 DDHAL 相关的函数, 但是将用软件模拟.

为什么同时存在 DDHAL 模块和 DDRAW 模块? 因为 DDHAL 的使用更具有挑战性, 如果使用不适当, 性能反而会降低. 而且使用起来更为烦琐且给调试带来一定麻烦. 另外更重要的是, DDHAL 下, 对 screen 的 alpha 混合等操作会更慢. 所以使用 DDHAL 必须放弃一些效果.

在 DDHAL 的支持下, screen 是放置在显存中的, 所以对 screen 的操作前都必须运行:

int DDHAL::lock()
lock 住 screen, 方能读写. 成功返回 0

lock 的时间不宜太长, 操作完毕后需要调用:

void DDHAL::unlock()
unlock screen.

需要记住的是, 读显存是很慢的操作(至少在现在的硬件条件下), 写显存也比写内存慢. 这些是使用 DDHAL 需要付出的代价. 但是使用硬件加速的好处是, 显卡多支持显存到显存的异步传输, 这使 WSP::update() 的速度大大提高. 而且你可以把位图加载一个副本到显存, 加快后面的blit/maskblit 操作速度. 但是在 DDHAL 模式下, 如果你的位图没有被上载, 不仅仅是做 Alpha 混合, 连 maskblit 都会异常缓慢, 所以 DDHAL 请谨慎用之.

int BMP::upload()
上载位图的副本到显存. 有利于 blit/maskblit 操作. 成功返回 0. 失败的最大可能是无多余的显存可以使用. 注意: 如果位图被创建了子位图, 它的上载并不意味着其子位图的上载

void BMP::unload()
如果位图存在显存副本, 就把它从显存卸载.

这里提供了几个函数只对 screen 操作, 如果在 DDHAL 模式下, 就自动帮你 lock/unlock. 假如你的位图拥有显存镜像. 更可以使用显存异步传输, 提高速度.

BMP::blit(int x1,int y1,int x2,int y2,int w,int h)
这个是专门针对 screen 做的 blit 函数, 但是不支持附加图层. 如果后面 4 个参数省略, 意味着传输整张位图

BMP::maskblit(int x1,int y1,int x2,int y2,int w,int h)
这个是专门针对 screen 做的 maskblit 函数. 如果后面 4 个参数省略, 意味着传输整张位图

诸如 screen.line, screen.rect 等调用, 调用前记得 DDHAL::lock(). 唯一的例外是 screen.printf, 这个函数会帮助你 lock 屏幕. 另外, 不要在 DDHAL 模式下使用 BMP::clear(PIXEL color); 因为你有更好的选择:

void DDHAL::clear(PIXEL color)
清除屏幕到指定颜色, 如有可能将使用硬件加速.

返回页首

脏矩形

脏矩形技术如果灵活使用将比 Double buffer 更快. 它指的是每次只恢复上帧屏幕上被破坏了的矩形部分. 风魂plus 提供了脏矩形的基本支持, 你可以灵活使用它. 如果加载了 DDHAL 模块, 脏矩形将尽可能的使用硬件加速. 系统内部的显示 FPS 的模块, 鼠标绘制部分都使用了脏矩形.

void DIRTYRECT::backup(int sx,int sy,int sw=0,int sh=0)
备份 screen 上左上角 (sx,sy) 大小为 sw * sh的矩形部分. 如果后两个参数省略 (为0). 矩形大小为创建的脏矩形的大小. 例:

	DIRTYRECT rect;
	rect.create(100,100);
这样就定义了一个大小为 100x100 的脏矩形. 当你想保护 screen 上 (100,100)~(200,200) 区间的矩形的时候, 可以用: rect.backup(100,100);

void DIRTYRECT::restore()
恢复上次备份的脏矩形. 上例中保存的 screen 的 (100,100)~(200,200) 的矩形区域, 只需要调用: rect.restore() 就可以恢复.

int DRTYRECT::create(int w,int h,int layer=-1)

创建 (w * h) 大小的脏矩形. 如果 layer 不写, 创建的脏矩形拥有和 screen 一样的附加层结构. 成功返回 0.

void DIRTYRECT::destory()
销毁脏矩形

返回页首

图形都是基于点的, 所以风魂中图形方面里最基本的就是点类 (PIXEL), PIXEL 组成了 BMP, PIXEL 也通常用于描述颜色。

可以这样初始化一个点:

注意: 请不要在全局变量中, 或是调用 WSP::display() 前初始化颜色, 因为这个时候, 并不能确定显示色彩模式是 555 还是 565

PIXEL 变量可以直接赋值, 虽然内部的数据是 16bit 的, 但是赋值的时候统一使用 DWORD, 用 24bit 颜色 (RGB888) 来描述, 用于统一 555 和 565 模式. 有一种特别的颜色被称作掩色. 在图片中, 掩色被处理成透明的. 掩色被定义成粉红 (reg=255, grenn=0, blue=255). 但是要设置一个点的颜色为掩色, 需要调用 mask() 函数.

void mask()
设置为 MASKCOLOR, 例:

	PIXEL p;
	p.mask();

WORD get()
返回 16bit 的颜色值, 一般只用于数据传递, 而不用于数据处理.

void set(WORD)
设置点为一个 16bit 颜色值, 一般较少使用, 例:

	PIXEL p1(0xff0000),p2;
	p2=p1;// 将 p1 赋给 p2
	p2.set(p1.get());// 和上一句是等价的

DWORD truecolor()
将颜色转换为 24bit 真彩色返回

BYTE red()
返回颜色的红色分量 (0~255)

BYTE green()
返回颜色的绿色分量 (0~255)

BYTE blue()
返回颜色的蓝色分量 (0~255)

返回页首

位图

风魂里的图形操作全部是基于位图这个类的. 但是位图类本身的数据只有 4 bytes, 是一个结构指针, 指向位图的数据. 结构的定义如下:


typedef struct {
	int w;	//宽
	int h;	//高
	int pitch;	//行间字节数
	int kx;	//关键点 X 坐标
	int ky;	//关键点 Y 坐标
	int cl;	//剪裁矩形左边界
	int ct;	//剪裁矩形上边界
	int cr;	//剪裁矩形右边界
	int cb;	//剪裁矩形下边界
	void *alpha;	//Alpha 通道指针
	void *zbuffer;	//Z 缓冲偏移
	void *nbuffer;	//法线缓冲偏移
	PIXEL *line[1];
} _BMPPTR;

例如:
BMP t;
t.bmp 指的就是这个结构指针; t.bmp->w 即为位图 t 的宽; 
t.bmp->line[y][x] 即为位图 t 的坐标 (x,y) 处的点

注:关键点的坐标描述的是 BLIT 操作时, 对目标坐标的修正量. 之所以提供它, 是因为, 游戏中为了节约内存, 往往将位图贴着实际有图象的地方裁下来. 但这样, 一组相关图片 在裁减后按左上角并不能对齐, 所以我们必须在每个图片上定义一个对齐点(重心?) 这个点就是关键点.

风魂 plus 中, 每个位图除了基本的图形的颜色信息外, 还可以有 3 个附加层 (layer) 描述其 Alpha 通道, Z 缓冲, 法线缓冲. 这些附加层和主图象分在不同的内存, 可以自由选择创建. 和主颜色图层不同的是, 附加层的每个像素点的信息占一个字节 (而主图层上每个点由两个字节描述颜色)

int create(int width,int height,int layer=0)
创建位图, 大小为 width * height. 层标记 layer 缺省为 0, 即为附加层. 函数运行成功则返回 0. 例:

BMP bmp,tmp(320,200);	// 初始化 tmp 为 320x200 的位图, 不带任何附加层
bmp.create(400,300,ALPHA_CHANNEL|Z_BUFFER);	//创建一个带有 Alpha 通道和 Z-Buffer 的位图

int create_struct(int width,int height,int pitch=0,int layer=0)
只创建位图结构, 而无实际数据区. 但附加层会被分配数据区. 这里可以指定 pitch (即每行数据占用的字节数) 如果 pitch 为 0 则按 width 值计算 pitch. 成功返回 0.

int create_sub_bitmap(BMP fbmp,int x,int y,int width,int height)
创建一个位图的子位图. 子位图将分享父位图的数据区, 拥有和父位图相同的附加图层结构. 成功返回 0

HBITMAP create_gdi_bitmap(HDC dc,int width,int height,int layer)
分配一个DIB BITMAP, 并将位图映射在上面. 调用这个函数必须给出 DC 句柄. 返回的是一个 BITMAP 句柄. 使用这个函数, 必须先 include windows.h

void destroy()
释放位图占用的内存. 当然你不用显式的调用它, 因为在位图对象的生存期结束后, 析构函数将自动调用它

int layer()
获得 BMP 的层信息

void setclip(short left,short top,short right,short bottom)
设置剪裁矩形. 在剪裁矩形外的操作讲忽略. 剪裁矩形内的作用包含了左边界 left 列和上边界 top 行, 但不包含 right 列, 和 bottom 行.

void setclip()
不带参数的 setclip 函数, 将设置剪裁矩形为整个位图面.

void keypoint(int x,int y)

设置关键点位置. 如果一个位图的关键点的坐标是 (10,20); 那么你将它blit 到屏幕 (x,y) 处, 实际效果相当于, 关键点是(0,0) 时, blit 到屏幕的 (x-10,y-20) 处.

PIXEL *getline(int line)

获得位图第 line 行的指针, 在 DEBUG 版中, 函数将检查 line 的合法性. 例:

BMP bmp(300,200);
bmp.getline(5)[20]=0xff0000;	// 相当于 bmp.bmp->line[5][20]=0xff0000;

BYTE *alpha_channel(int line)
获得 Alpha 通道第 line 行的指针

BYTE *z_buffer(int line)
获得 Z Buffer第 line 行的指针

BYTE *n_buffer(int line)
获得 Z Buffer第 line 行的指针

PIXEL pixel(int x,int y)
获得位图(x,y)处的点

int load_bmp(char *filename,int layer=0)
加载.bmp图片, 同时可以为位图创建附加层. 成功返回 0

int save_bmp(char *name)
保存位图到 24bit .bmp 中, 如果位图带有 Alpha 通道, 将根据 Alpha 通道中透明点 0, 将位图的透明部分设置为 MASKCOLOR. (粉红色 0xFF00FF) 成功返回 0

int load_hbm(char *filename,int layer=0)
加载.hbm图片, HBM 文件是风魂 plus 定义的专有图形格式, 支持风魂 plus 的图层结构. 成功返回 0

int save_hbm(char *name)
保存位图到 16bit .hbm 中. 成功返回 0

int load_bitmap(char *filename,int layer=0)
加载图片, 根据扩展名区分 bmp/hbm. 成功返回 0

int register_bmp_type(char *ext,_BMPPTR* (*load_func)(char *,int))
为 load_bitmap 注册新的位图文件类型. 例:

// 读 jpg 文件到一个 _BMPPTR 结构的函数
_BMPPTR *load_jpg(char *filename,int layer)
{
	...
}

// 注册 load_jpg 到 BMP::load_bitmap
	BMP::register_bmp_type("jpg",load_jpg);

int load_alphachannel(char *filename)
从一个 8bit 的 BMP 文件加载Alpha通道. (注:必须是 8bit 的 BMP, 即 3ds max 生成的那种. 成功返回 0

void mask_alphachannel()
在风魂 plus 中, 透明 blit (maskblit) 如果位图拥有一个 Alpha 通道. 会得到很高的效率. 这个函数将为一个位图生成对应的 Alpha 通道. 透明的部分设置为 32, 不透明部分为 0.

void blit(BMP dest,int x1,int y1,int x2,int y2,int w,int h)
BLIT 到 dest 位图, 这个函数仅仅是简单的复制位图, 包括主图层和附加图层. 而附加图层并不参加运算. 参数 (x1,y1) 是源图的需要复制的左上角坐标. (x2,y2) 是目标图的左上角坐标. (w,h) 为复制的长宽.

void blit(BMP dest,int x,int y)
BLIT 的这个版本, 必须整个位图赋值, 只需要给出目标坐标. Alpha 通道将其作用.

void blit(BMP dest,int x,int y,int z)
带 Z Buffer 检查的 BLIT. 如果源图没有 Z-Buffer 层, 那么源图的不透明部分将被赋予相同的 Z 值 z. 如果源图带有 Z-Buffer 层, 它的非透明部分的 Z 值将全部被加上 z. 只有 Z 值大于等于目标图上的 Z 值, 点才会被复制.

void transblit(BMP dest,int x,int y,int alpha)
半透明 BLIT 版本. alpha 范围是 0~32, alpha 越小, 透明度越大, 反之, alpha=32 时, 完全不透明. 这个函数同样支持 alpha 通道. 就是可以将带有 alpha 通道的位图做半透明处理.

void maskblit(BMP dest,int x,int y)
检查透明色的 BLIT 版本. 会利用 Alpha channel 或者 Z-Buffer 做加速处理

void transmaskblit(BMP dest,int x,int y,int alpha)
检查透明色的半透明BLIT

void clear()
清除位图到 MASKCOLOR

void clear(PIXEL color)
清除位图到指定颜色

void clear_layer(int layer)
清除指定附加层. layer 可以是 ALPHA_CHANNEL, Z_BUFFER, N_BUFFER

void additive(BMP dest,int x,int y)
叠加位图到目标位图 (主要用于光照)

void subtract(BMP dest,int x,int y)
从目标位图消减位图 (主要用于阴影)

返回页首

几何绘图函数

风魂的几何函数画到位图上时, 支持多种绘图模式. 分别有

void drawing_mode(enum draw_mode mode,int alpha=16)
设置绘图模式, 如果设置为 draw_trans 模式, 需要指定透明度. 缺省是 16 (50%)

vline(int x,int y1,int y2,PIXEL color)
绘制垂直线

void hline(int x1,int y,int x2,PIXEL color)
绘制水平线

void rect(int x1,int y1,int x2,int y2,PIXEL color)
绘制矩形

void rectfill(int x1,int y1,int x2,int y2,PIXEL color)
填充矩形

void do_line(int x1, int y1, int x2, int y2, void (*proc)(int,int))
这是个静态函数, 和位图无关, 只是沿 (x1,y1) 到 (x2,y2) 直线上每个点调用函数 proc.

void line(int x1,int y1,int x2,int y2,PIXEL color)
绘制直线

void put_pixel(int x,int y,PIXEL color)
绘点(检查剪裁矩形)

返回页首

文字输出

void BMP::printf(int x,int y,PIXEL color,char *format,...)
在位图上输出一行文字

关于汉字:

风魂本身带有简单的 16x16 点阵汉字库支持. 一般只做调试使用, 今后的版本将提供 TTF 解码. 但是点阵字库速度较快, 依旧有很多用途. 风魂本身不带有汉字库, 你需要自己准备 16x16 汉字库.

int HZ::load(char *name,int rev=0)
加载汉字库. 通常 16x16 汉字库文件长度为 267616 字节. 在以前 DOS 版的汉字平台上都可以找到. 只是那些字库的左半边和右半边相对风魂的代码是反的. 建议你自己对字库做预处理. 或者可以带参数 1. 程序加栽后在内存颠倒. 当汉字库正确加载后, BMP::printf 将可以输出汉字

返回页首

键盘管理

程序开始运行了 INSTALL(KEY) 就可以使用风魂中的键盘管理模块

void KEY::state()
获取键盘状态. 当你需要查询某个键的状态前, 必须调用这个函数. 然后就可以通过访问数组 KEY::key[] 来得到具体按键的状态, 例:

	KEY::state();	// 获取键盘状态到 KEY::key[], 按下对应值为 0x80, 释放为 0
	if (KEY::key[KEY_ESC]) screen.printf(0,0,0,"ESC is pressed");
	if (!KEY::key[KEY_SPACE]) screen.printf(0,20,0,"SPACE is not pressed");

int read()
读键盘, 返回最近按的按键. 如果无按键, 返回 0. 例:

	int key=KEY::read();
	switch (key) {
	    case KEY_A: 
	        screen.printf(0,0,0,"A is pressed");
	        break;
	    case KEY_B:
	        screen.printf(0,0,0,"B is pressed");
	        break;
	};

返回页首

鼠标管理

程序开始运行了 INSTALL(MOUSE) 就可以使用风魂中的鼠标管理模块

void MOUSE::state()
获取鼠标状态. 当你需要查询某个鼠标按纽的状态, 或者鼠标的坐标前, 必须调用这个函数. 然后就可以通过访问 MOUSE::x MOUSE::y 来得到鼠标的坐标. 或者访问 MOUSE::button[] 来得到 3 个按纽的状态. (0 左键, 1 右键, 2 中键)

鼠标的光标是一个 CURSOR 类, 可以是静态图片或者是有组图片动画.

int create(BMP *frame,int n=1,int speed=0)
创建鼠标, 如果你只想使用静态鼠标, 只用

	CURSOR mc;
	BMP tmp("mouse.bmp");	//加栽鼠标用的图片
	mc.create(&tmp);	// 利用位图 tmp 创建鼠标
实际上, 还可以写成:
	BMP tmp("mouse.bmp");
	CURSOR mc(&tmp);
注意: 当鼠标创建后, 位图 tmp 里的数据将转移到鼠标 mc 中, 位图 tmp 就成了空, 不可再使用 如果想创建动画鼠标, 需要提供一个位图数组, 和位图帧数, 以及播放速度. speed 越大, 速度越慢. 函数运行成功就返回 0.

void CURSOR::draw(int x,int y)
不鼠标画到屏幕 screen (x,y) 处, 并保存这部分屏幕的原始数据

void CURSOR::restore()
恢复上次画的鼠标

void CURSOR::destroy()
销毁鼠标, 这个将自动调用.

void MOUSE::set(CURSOR mc)
设置鼠标光标

void MOUSE::set()
设置鼠标光标为空, 既不显示

void MOUSE::show()
void MOUSE::hide()
显示隐藏鼠标, 和前面 set() 函数想比, 当 hide 鼠标后, FPS 计数将停止. GDI 模式下, 鼠标不受限制在程序窗口. 甚至很有可能, 程序不再能正确获得鼠标的状态

返回页首

声音管理

程序开始运行了 INSTALL(DSOUND) 就可以使用风魂中的利用 DirectSound 实现的声音管理模块

void DSOUND::on()
打开声音

void DSOUND::off()
关闭声音

void DSOUND::vol(int vol=0)
调整音量, 0 为最大值. VOLMIN(一个负数) 为最小值

风魂中将声音分为 SAMPLE 和 MUSIC 两类. 实际上他们都是采样声音 (从 WAV 文件中加栽) SAMPLE 是将数据全部加载入内存的声音. 而 MUSIC 是一种声音流, 系统将持续的读外存, 播放 MUSIC.

关于播放格式

int MUSIC::load(char *filename,enum play_mode mode=play_loop)
加载声音流, 并可以设置播放模式 (play_once 或 play_loop) 成功返回 0 注意: MUSIC 的所有函数都是静态的, 所以你只能加载一个 MUSIC

void MUSIC::play(enum play_mode mode=music_mode)
播放前面加载的声音流.

void MUSIC::play(char *filename,enum play_mode mode=play_loop)
以声音流形式播放一个 wav 文件.

void MUSIC::stop()
停止音乐

void MUSIC::destroy()
释放音乐占用的资源. 通常会自动调用.

void MUSIC::on()
开启音乐

void MUSIC::off()
关闭音乐 (等同于 stop() )

int SAMPLE::load(char *filename)
加载 wav 文件

void SAMPLE::play(enum play_mode mode=play_once,int vol=0,int pan=0)
播放 SAMPLE, 可以指定播放模式, 音量和 PAN. 关于 PAN 指的声音在左右声道的位置. 0 表示中间, PANLEFT 表示最左边, PANRIGHT 表示最右边.

void SAMPLE::stop()
停止 SAMPLE 的播放

int SAMPLE::play(char *filename,int vol=0,int pan=0)
播放指定 wav 文件, 当声音播放完毕后将释放占用的内存空间

void SAMPLE::adjust(int vol=0,int pan=0)
调整音量和 PAN

enum play_mode playingmode()
返回当前声音状态. 可以用来检测声音是否播放完毕. 比如, 如果返回的是 play_none, 表明声音没有在播放中.

返回页首

数据包管理

  风魂为游戏的数据提供了数据包的管理, 你可以将游戏中用到的所有 数据压缩放在一个数据文件中. 程序中可以有如普通文件那样方便 的处理数据包中的文件. 如果在数据文件外有同名的单独文件, 数据包管理例程将优先处理它, 把它当作普通文件处理. 而包内文件使用 32bit ID 定位, 采用二分检索, 所以速度很快. 数据包是 DATAFILE 类, 而数据文件是 PACKFILE 类.

int DATAFILE::open(char *fname)
打开数据文件并把它设置成当前激活状态, 成功返回 0

void DATAFILE::close()
关闭数据文件. 参数为一个数据文件指针

void DATAFILE::active()
设置当前使用的数据文件. 注: 风魂可以同时打开多个数据文件, 但是激活状态的只能有一个. 这个激活, 影响后面的压缩 文件打开操作从何处寻找文件. 但是, 已经打开的压缩文件, 自己会依附在正确的数据包上, 不受激活状态的影响.

void DATAFILE::chdir(char *s)
数据包文件里可以将压缩文件按虚拟目录存放. 这个函数可以改变虚拟路径.

int PACKFILE::open(char *filename)
打开压缩文件, 先寻找当前目录下是否有同名的单独文件, 然后再在激活的数据包文件中寻找. 所以在你不使用数据包 这个功能的时候, 对于只读的情况还是推荐你使用它去取代 fopen()

void PACKFILE::close(PACKFILE *pf)
关闭压缩文件 (同 fclose() )

DWORD PACKFILE::read(void *buffer, DWORD size)
从压缩文件中读取数据, 基本同 fread() 但比它少那个莫名其妙的参数, 只需要指定读取字节数即可 ;-)

DWORD PACKFILE::tell()
返回压缩文件的读指针, 同 ftell()

void PACKFILE::seek(int offset, int org)
压缩文件读指针定位, 同 fseek()

DWORD PACKFILE::size()
返回文件大小
--------- 以下写给想深一步开发的朋友 ----------

风魂中使用的 LZO 压缩. 提供了一个压缩类 COMPRESS.

int COMPRESS::compress(void *in,unsigned in_len,void *out)
压缩数据块

int COMPRESS::decompress(void *in,unsigned in_len,void *out)
解压数据块

关于数据打包:

风魂中只附带了一个很简单的打包程序 (尚未加入风魂plus). wspack 打包时将需要打包的文件名写在一个 .lst 文件中 然后运行 wsp datafile.dat listfile.lst 就可以完成打包.

网友沐枫(见 Thanks) 用 Delphi 写了一个非常漂亮的 数据包管理程序, 可以方便的管理数据包, 推荐使用.

这个附加程序不放在风魂中. 而提供单独下载, 请访问风魂的主页:

http://member.netease.com/~cloudwu/windsoul

返回页首

调试

风魂plus 较原风魂提供了更为强大的调试支持. 使用它需要你运行 INSTALL(DEBUG) 加载调试模块. 推荐把 DEBUG 模块加载到所有模块之前, 这样你就能看到其他模块输出的调试信息. 风魂的调试模块将另使用单独的窗口显示调试信息. 而不影响程序的正常运行.

TRACEINFO(PIXEL color, char *format,...)
输出一条彩色调试信息到调试窗口

DEBUGINFO(int p,char *format,...)
如果条件 p 成立, 则输出一行红色调试信息到调试窗口

实际上, TRACEINFO 和 DEBUGINFO 都是在 wsp.h 中定义的宏. 如果你不希望在最终代码中生成调试信息代码, 请在 include wsp.h 前定义 OFFDEBUGINFO. 比如可以这样写:

#ifndef _DEBUG
#define OFFDEBUGINFO
#endif

#include "wsp.h"
RELEASE 版中就不会产生调试信息代码. 这和不加载 DEBUG 模块有一点不同. 如果你不加载 DEBUG 模块, DEBUGINFO/TRACEINFO 实际调用的是一个空函数

返回页首

计时器

风魂+ 对原来风魂的记时器模块做的加强, 这个模块 (TIMER) 将自动加载. 用于内部 FPS 的检测. 也可以用来控制游戏的速度. 测试代码的效率等.

DWORD TIMER::CyclePerSec
这个常量放置的是你的 CPU 一秒可以运行多少个时钟周期

int TIMER::CPU()
返回 CPU 的主频, 单位 MHz

void TIMER::reset()
初始化计时器 (风魂自身在初始化时会自动调用)

DWORD TIMER::time()
返回从上次调用 rest() 到当前经过的时间, 单位是 1/10000 秒

DWORD TIMER::timer(int set)
这个是用于代码效率的检测, 用法举例如下:

	DWORD time;
	TIMER::timer(0);	// 开启时钟级记时器
	myfunc();	// 我的需要检测速度的函数
	time=TIMER::timer(1);	// 关闭时钟记时器
	TRACEINFO(0xff0000,"%d",time);	// 输出 myfunc() 运行时间
注意: 请一定保证 myfunc() 函数正确, 不会死循环, 否则将当机. 因为 TIMER::timer(0) 将把优先级设置到最高. 这里检测出来的时间单位是 8 个时钟周期. 最大量程在 P200 上是 2 分半

返回页首

帧数统计

如果你的程序加载了鼠标模块, 就获得了附带的帧数统计的支持.

int FPS::fps()
返回上一秒的帧数. (就是 WSP:update() 在一秒内被调用的次数)

void FPS::show(PIXEL color)
在屏幕左上角显示一秒的上一秒的帧数 (DEBUG 模式下, F12 就可以显示)

如果你没有加载 MOUSE 模块, 则需要你在每次 WSP::update() 前调用 FPS::count() 并在 WSP::update() 后调用 FPS::restore() 恢复可能被破坏掉的屏幕位图

返回页首


云风工作室 制作