Pcgame 版 (精华区)
发信人: bell (花开时是冷冷月光), 信区: Pcgame
标 题: Allegro 中文文档(时钟例程)
发信站: 紫 丁 香 (Tue May 4 14:04:19 1999), 转信
时钟例程
install_timer
remove_timer
install_int
install_int_ex
remove_int
i_love_bill
timer_simulate_retrace
retrace_count
retrace_proc
rest
rest_callback
基本的 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);
时钟处理程序可以被用来模拟垂直回扫中断. 回扫中断在处理平滑动画时极其有用, 但不幸
的是, 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 下使用, 它好极了 ,但交给用户一个可以 关掉它的
开关却是个好主意.
回扫模拟器必须在你在 mode-X 下使用三缓冲函数时打开. 它也可以被用在简单的回扫 检
测上, 因为轮询 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(), 不过它在等待所需的离开时间的同时将 不停的调用指定的函数.
--
--
※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: jxjd.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.773毫秒