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毫秒