Programming 版 (精华区)
发信人: lansh (沧海一粟), 信区: Programming
标 题: Allegro 游戏程序库 (时钟例程)
发信站: 哈工大紫丁香 (2002年09月11日19:52:42 星期三), 站内信件
发信人: cloudwu (云风), 信区: GAME_Designer
标 题: Allegro 游戏程序库 (时钟例程)
发信站: BBS 水木清华站 (Sun May 10 10:12:38 1998)
______ ___ ___
/\ _ \ /\_ \ /\_ \
\ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
\ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
\ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
\ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
\/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
/\____/
\_/__/ 3.0 版
一个游戏程序库
By Shawn Hargreaves, 1994/97
云风 译
http://www.nease.net/~cloudwu
E-mail:cloudwu@nease.net
========================================
============ 时钟例程 ============
========================================
基本的 PC 时钟只能是每秒触发 18.2 次, 这对于快节奏的动作游戏不
是很适用. Allegro 可以用重新设置过的一个时钟例程来代替系统原来
的,这个重编程过的时钟有更高的触发频率,但是仍然以以前的速度调用
BIOS 处理程序.你可以设置几个你自己的虚拟时钟, 每个可以以不同的
速度运行, Allegro 将不断的重编程时钟使它们在正确的时间被调用.
因为 Allegro 改变了 PIT 始终芯片的设置, 它不能和 djgpp 的 libc
里的 uclock() 函数一起使用.
int install_timer();
加载 Allegro 时钟中断处理程序. 你必须在加载任何用户时钟例程
之前, 和在显示鼠标, 播放 FLI 动画或者 MIDI 音乐,使用其它的
GUI 例程之前执行它.
void remove_timer();
卸载 Allegro 时钟处理程序并且将时钟的控制权交还 BIOS.你不必
明显的调用它,因为 allegro_exit() 将为你做这些.
int install_int(void (*proc)(), int speed);
加载用户始终处理程序, 参数 speed 的单位为万分之一秒. 它和
install_int_ex(proc, MSEC_TO_TIMER(speed)) 作用相同.
int install_int_ex(void (*proc)(), int speed);
在用户时钟处理程序列表上加一个函数, 如果这个函数已经被加载,
则调整它的速度. spped 的单位为硬件时钟单位, 即 1193181 分之
一秒. 你可以利用以下的宏将其它时间单位转换到这个单位上:
SECS_TO_TIMER(secs) - 给出两次触发间的秒数
MSEC_TO_TIMER(msec) - 给出两次触发间的万分之一秒数
BPS_TO_TIMER(bps) - 给出每秒触发多少次
BPM_TO_TIMER(bpm) - 给出每分钟触发多少次
如果没有空间再增加新的用户时钟程序, install_int_ex() 将返回
一个负值, 否则返回零. 同时只能有 16 个时钟程序在使用, 并且
Allegro 的其它部分 (GUI 代码,鼠标显示例程, rest(), FLI 播放
程序, 和 MIDI 播放程序)需要加载它们自己的处理程序, 因此你要
避免同时使用它过多. 你的函数将被 Allegro 中断处理程序调用而
不是被处理器直接调用, 所以它能够按正常的 C 函数来写而不需要
特别的包装. 然而, 你必须知道,它将在一个中断中被调用, 而这给
你希望在函数中做的事增加了许多约束. 它不能使用大数量的堆栈,
不能调用任何 DOS 例程和使用调用了 DOS 例程的 C 库函数, 而且
它必须被很快的执行.不要在时钟处理程序里写太多的复杂代码: 一
个基本的规则是 你应该设置一些标志然后在你的主控制循环里来回
应它们. 如果你正在用 C++ 编程, 在使用 install_int() 或者
install_int_ex() 的地方你将发现 gcc 的出错信息.为了避免这个,
你必须按变量数目可变的方式说明你的函数, 象这样:
void my_timer_handler(...);
在象 djgpp 这样的保护模式环境里, 内存被虚拟化并可以向磁盘交
换.由于 DOS 的不可重入, 如果磁盘交换发生在中断处理程序内部,
系统将痛苦的死机,所以你需要确认你锁住了所有时钟例程中触及的
所有内存(包括代码和数据). Allegro 将锁住它用的所有东西,但是
你有责任锁住你自己处理程序的. 宏 LOCK_VARIABLE(变量),
END_OF_FUNCTION(函数名),和 LOCK_FUNCTION(函数名) 可以被用来
简化这项任务.例如, 你想用一个中断处理程序来增加一个记数变量,
就应该这样写:
volatile int counter;
void my_timer_handler()
{
counter++;
}
END_OF_FUNCTION(my_timer_handler);
在你的初始化代码里,应该锁住内存:
LOCK_VARIABLE(counter);
LOCK_FUNCTION(my_timer_handler);
很明显,如果你使用了复杂的数据结构并且在这个处理程序中调用了其
它的函数,这就显得很笨拙,所以你应该使你的中断处理程序尽量简洁.
void remove_int(void (*proc)());
从用户中断例程列表中卸载一个函数.在程序的结束处,allegro_exit()
会自动运行它.
extern int i_love_bill;
如果被设为 TRUE, 打开专门的 'windows friendly'(对瘟都死友好)
时钟模式,这将硬件时钟中断锁在 200 次每秒的速度,而不是对它动
态重编程.这个模式减少了时钟的精确性 (例如, rest() 将延时长度
误差在 5 个百万分之一秒左右),并且阻止了垂直回扫模拟器的工作
( 在这个模式下对 timer_simulate_retrace() 的调用被忽略). 然
而, 它带来的好处是, 使得 Allegro 程序可以工作在 windows 3.1
下,而且使在 win95 的 DOS 模式下运行而没有出错信息. 这个标记
应该在你加载始终模块前被设置, 而且在时钟在激活时不能改变它.
缺省状态下, allegro_init() 如果检测到 windows 的存在,将打开
这个模式.
void timer_simulate_retrace(int enable);
时钟处理程序可以被用来模拟垂直回扫中断.回扫中断在处理平滑动
画时极其有用, 而且是三缓冲(triple buffering)所必不可少的,但
不幸的是,VGA 硬件不支持它. EGA 有,一些 SVGA 卡也有,但着不够,
那些方法不够标准,来使其变的有用. Allegro 使这些运作起来依靠
的是对时钟编程使其成为一个普通的中断,当它认为下一次回扫将要
发生时在中断处理程序里轮询(polling) VGA 确认处于显示器刷新
时的 sync(垂直回扫同步)中.这些在一些情况下工作的非常好,但是
它有一大堆限制:
- 在 SVGA 模式下不要在任何时候都用回扫模拟器.它只能在某些芯
片上用,而在其它的芯片上不行, 并且它和所有的 VESA 提供工具
有冲突.回扫模拟器仅仅在 VGA 13h 模式和 mode-X 下可信.
- 回扫模拟器不能工作在 win95 下, 因为 win95 在我试着从 PIT
里读取逝去的时间时返回的是一些垃圾.如果有人知道我应该怎么
做这些,请告诉我!
- 回扫模拟器在时钟处理程序里关掉了中断造成了许多的等待.这将
使你的整个系统慢下来,还可能在用 SB 1.0 声卡播放声音时造成
无声 (因为它们不支持自动初始化 DMA: SB 2.0 及以上版本没有
问题).
由于要忍受这么多的问题, 我强烈建议你不要依赖于回扫模拟器.如
果你在 mode-X 下编程,而且不在乎你的程序能否在 win95 下使用,
它好极了 ,但交给用户一个可以关掉它的开关却是个好主意.回扫模
拟器在你使用三缓冲 request_modex-scroll() 函数前必须被打开.
它也可以被用在简单的回扫检测上, 因为轮询 vsync() 函数在声卡
或时钟中断正好发生在回扫的同时时,偶尔会丢失回扫. 当回扫中断
模拟器打开, vsync() 将检查 retrace_count(回扫计数器) 变量而
不是轮询 VGA, 因此只有在它们被其它中断屏蔽时才会丢失回扫.
extern volatile int retrace_count;
如果回扫模拟器被加载,这个会随着每次垂直回扫而递增, 否则它将
每秒递增 70 次 (忽略回扫). 这提供了一个避开加载用户时钟中断
函数的麻烦而控制你的程序速度的有效方法.回扫变量的速度依赖于
图形模式. 在 13h 模式和 200/400 行的 mode-X 分辨率下是每秒
70 次 回扫,在 240/480 行模式下是 60 次. 它可以被慢到 50 次
(在 376x282 模式下) 也可能高到 92 次 (在 400x300 模式下).
extern void (*retrace_proc)();
如果回扫模拟器被加载, 这个函数将在每次垂直回扫时被调用,否则
将被每秒调用 70 次 (忽略回扫).将其设置为 NULL 可以关掉回叫.
这个函数必须遵守和中断函数相同的规则 (即, 它必须被锁住,不能
调用 DOS 或 libc 函数) 而且更甚的是: 它必须被 _非常_ 快的执
行, 否则回对时钟同步造成混乱.我能想到的唯一作用是用来对调色
板做一些巧妙的处理,而三缓冲能够用 request_modex_scroll() 函
数来实现, 且 retrace_count 变量可以用来对你的代码记时. 如果
你希望在 retrace_proc 里来改变调色板,则应该使用
inline _set_color() 函数而不是常规的 set_color() 或
set_palette(), 而且你不要去尝试在一次回扫中改变二或三个以上
的调色板入口.
void rest(long time);
Allegro 一度接管了时钟, 基本的 delay() 函数将不能再工作, 所
以你必须使用这个例程来代替. 时间的单位是百万分之一秒.
void rest_callback(long time, void (*callback)())
有点象 rest(), 不过它在等待所需的离开时间的同时将不停的调用
指定的函数.
--
http://www.nease.net/~cloudwu
http://computer.igd.edu.cn/~cloud
E-mail: cloudwu@163.net
--
人生得意需尽欢,莫使金樽空对月。
天生我才必有用,千金散尽还复来。
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: hitsat.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:12.927毫秒