Bienvenue sur le wiki de Nuit debout, nous sommes le 2987 mars.
Villes/Montluçon/sciences/FastGraph
Fastgraph (r)
User's Guide � Copyright (c) 1991-1995 by Ted Gruber Software, Inc.
All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted by any means, electronic, mechanical, photocopying, recording, or otherwise, without express written permission from Ted Gruber Software. The software described in this publication is furnished under a license agreement and may be used or copied only in accordance with the terms of that agreement.
This publication and its associated software are sold without warranties, either expressed or implied, regarding their merchantability or fitness for any particular application or purpose. The information in this publication is subject to change without notice and does not represent a commitment on the part of Ted Gruber Software. In no event shall Ted Gruber Software be liable for any loss of profit or any other commercial damage, including but not limited to special, incidental, consequential, or other damages resulting from the use of or the inability to use this product, even if Ted Gruber Software has been notified of the possibility of such damages.
First Printing, August 1994
Fastgraph version 4.0
All brand and product names mentioned in this publication are trademarks or registered trademarks of their respective holders. �
T a b l e o f C o n t e n t s
Chapter 1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 1
What is Fastgraph? . . . . . . . . . . . . . . . . . . . . . . . . . 2 Fastgraph/Light . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Prerequisite Knowledge . . . . . . . . . . . . . . . . . . . . . . . 3 Supported Compilers . . . . . . . . . . . . . . . . . . . . . . . . 3 Real Mode, Protected Mode, and DOS Extenders . . . . . . . . . . . . 4 Memory Models . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Installing Fastgraph . . . . . . . . . . . . . . . . . . . . . . . . 6 The READ.ME File . . . . . . . . . . . . . . . . . . . . . . . . . . 7 The WHATS.NEW File . . . . . . . . . . . . . . . . . . . . . . . . . 7 Fastgraph Naming Conventions . . . . . . . . . . . . . . . . . . . . 7 Compilation and Linking . . . . . . . . . . . . . . . . . . . . . . 7 Borland C++ . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Borland Pascal . . . . . . . . . . . . . . . . . . . . . . . . 12 MetaWare High C/C++ . . . . . . . . . . . . . . . . . . . . . . 13 Microsoft BASIC Professional Development System . . . . . . . . 14 Microsoft C/C++ . . . . . . . . . . . . . . . . . . . . . . . . 15 Microsoft FORTRAN . . . . . . . . . . . . . . . . . . . . . . . 16 Microsoft FORTRAN PowerStation . . . . . . . . . . . . . . . . 17 Microsoft QuickBASIC . . . . . . . . . . . . . . . . . . . . . 18 Microsoft QuickC . . . . . . . . . . . . . . . . . . . . . . . 19 Microsoft Visual Basic for DOS . . . . . . . . . . . . . . . . 20 Microsoft Visual C++ . . . . . . . . . . . . . . . . . . . . . 21 Microsoft Visual C++ 32-bit Edition . . . . . . . . . . . . . . 22 Power C . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Turbo C and Turbo C++ . . . . . . . . . . . . . . . . . . . . . 24 Turbo Pascal . . . . . . . . . . . . . . . . . . . . . . . . . 25 WATCOM C/C++ . . . . . . . . . . . . . . . . . . . . . . . . . 26 WATCOM C32 for DOS . . . . . . . . . . . . . . . . . . . . . . 26 Zortech C++ . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Fastgraph/Light Video Driver . . . . . . . . . . . . . . . . . . . . 28
Chapter 2 PC and PS/2 Video Modes . . . . . . . . . . . . . . . . . . . 29
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Text Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Graphics Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 CGA Graphics Modes . . . . . . . . . . . . . . . . . . . . . . 33 Tandy 1000 and PCjr Graphics Modes . . . . . . . . . . . . . . 34 Hercules Graphics Modes . . . . . . . . . . . . . . . . . . . . 34 EGA Graphics Modes . . . . . . . . . . . . . . . . . . . . . . 35 VGA and MCGA Graphics Modes . . . . . . . . . . . . . . . . . . 36 Extended VGA (XVGA) Graphics Modes . . . . . . . . . . . . . . 37 SuperVGA (SVGA) Graphics Modes . . . . . . . . . . . . . . . . 38
Chapter 3 Initializing the Video Environment . . . . . . . . . . . . . . 41
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Establishing a Text Mode . . . . . . . . . . . . . . . . . . . . . . 42 43-line and 50-line Text Modes . . . . . . . . . . . . . . . . . . . 45 Establishing a Graphics Mode . . . . . . . . . . . . . . . . . . . . 46 SuperVGA Graphics Modes . . . . . . . . . . . . . . . . . . . . . . 50 Summary of Video Initialization Routines . . . . . . . . . . . . . . 55
iii �
Chapter 4 Coordinate Systems . . . . . . . . . . . . . . . . . . . . . . 57
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 Character Space . . . . . . . . . . . . . . . . . . . . . . . . . . 58 Screen Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Viewports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 World Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 Conversion Routines . . . . . . . . . . . . . . . . . . . . . . . . 64 Summary of Coordinate Routines . . . . . . . . . . . . . . . . . . . 64
Chapter 5 The Use of Color . . . . . . . . . . . . . . . . . . . . . . . 67
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Text Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Color Text Modes . . . . . . . . . . . . . . . . . . . . . . . 68 Monochrome Text Mode . . . . . . . . . . . . . . . . . . . . . 69 Graphics Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 CGA Color Modes . . . . . . . . . . . . . . . . . . . . . . . . 70 CGA Two-Color Mode . . . . . . . . . . . . . . . . . . . . . . 72 Tandy and PCjr Modes . . . . . . . . . . . . . . . . . . . . . 73 Hercules Mode . . . . . . . . . . . . . . . . . . . . . . . . . 74 Hercules Low-Resolution Mode . . . . . . . . . . . . . . . . . 75 EGA 200-Line Modes . . . . . . . . . . . . . . . . . . . . . . 76 EGA Monochrome Mode . . . . . . . . . . . . . . . . . . . . . . 78 EGA Enhanced Mode . . . . . . . . . . . . . . . . . . . . . . . 79 VGA and MCGA Two-Color Mode . . . . . . . . . . . . . . . . . . 81 VGA/SVGA 16-Color Modes . . . . . . . . . . . . . . . . . . . . 83 256-Color Modes . . . . . . . . . . . . . . . . . . . . . . . . 83 Using Video DAC Registers in EGA Modes . . . . . . . . . . . . . . . 87 RGB Color Mapping . . . . . . . . . . . . . . . . . . . . . . . . . 89 Defining All Palette Registers . . . . . . . . . . . . . . . . . . . 90 Virtual Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 A Multiple-Mode Example . . . . . . . . . . . . . . . . . . . . . . 92 Summary of Color-Related Routines . . . . . . . . . . . . . . . . . 94
Chapter 6 Graphics Fundamentals . . . . . . . . . . . . . . . . . . . . 97
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Clearing the Screen . . . . . . . . . . . . . . . . . . . . . . . . 98 Clipping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 The Graphics Cursor . . . . . . . . . . . . . . . . . . . . . . . . 100 Solid Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Dashed Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 Polygons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 Circles and Ellipses . . . . . . . . . . . . . . . . . . . . . . . . 107 Solid Rectangles . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Unfilled Rectangles . . . . . . . . . . . . . . . . . . . . . . . . 110 Dithered Rectangles . . . . . . . . . . . . . . . . . . . . . . . . 112 Region Fill . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 Summary of Fundamental Graphics Routines . . . . . . . . . . . . . . 121
Chapter 7 Character Display Routines . . . . . . . . . . . . . . . . . . 125
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Character Space . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Hardware Characters . . . . . . . . . . . . . . . . . . . . . . . . 127 Character Height . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Conversion Routines . . . . . . . . . . . . . . . . . . . . . . . . 137 Software Characters . . . . . . . . . . . . . . . . . . . . . . . . 138
iv � Bitmapped Characters . . . . . . . . . . . . . . . . . . . . . . . . 143 Summary of Character Display Routines . . . . . . . . . . . . . . . 144
Chapter 8 Video Pages and Virtual Buffers . . . . . . . . . . . . . . . 147
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 Physical Pages and Virtual Pages . . . . . . . . . . . . . . . . . . 148 Pages With Special Meanings . . . . . . . . . . . . . . . . . . . . 150 Some Simple Examples . . . . . . . . . . . . . . . . . . . . . . . . 150 Text Cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Obtaining Video Page Information . . . . . . . . . . . . . . . . . . 158 Considerations for Virtual Pages . . . . . . . . . . . . . . . . . . 159 Considerations for SuperVGA Pages . . . . . . . . . . . . . . . . . 160 Logical Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 Extended Video Pages . . . . . . . . . . . . . . . . . . . . . . . . 163 Video Page Resizing . . . . . . . . . . . . . . . . . . . . . . . . 166 Preserving Video Page Contents Across Mode Switches . . . . . . . . 167 Controlling Page Allocation . . . . . . . . . . . . . . . . . . . . 169 Virtual Buffers . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Summary of Video Page and Virtual Buffer Routines . . . . . . . . . 180
Chapter 9 Image Files . . . . . . . . . . . . . . . . . . . . . . . . . 183
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 PCX Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 GIF Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 FLI and FLC files . . . . . . . . . . . . . . . . . . . . . . . . . 192 Pixel Run Files . . . . . . . . . . . . . . . . . . . . . . . . . . 196 Display Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Controlling the Image Buffer Size . . . . . . . . . . . . . . . . . 206 Summary of Image File Routines . . . . . . . . . . . . . . . . . . . 208
Chapter 10 Bitmapped Images . . . . . . . . . . . . . . . . . . . . . . 211
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 Mode-Independent Bitmapped Images . . . . . . . . . . . . . . . . . 212 Mode-Specific Bitmapped Images . . . . . . . . . . . . . . . . . . . 217 Regular Images . . . . . . . . . . . . . . . . . . . . . . . . 217 Clipped Images . . . . . . . . . . . . . . . . . . . . . . . . 225 Reversed Images . . . . . . . . . . . . . . . . . . . . . . . . 225 Reversed Clipped Images . . . . . . . . . . . . . . . . . . . . 226 Images Without Transparent Pixels . . . . . . . . . . . . . . . 226 Some Examples . . . . . . . . . . . . . . . . . . . . . . . . . 226 Retrieving Images . . . . . . . . . . . . . . . . . . . . . . . . . 229 Inverting Bitmaps . . . . . . . . . . . . . . . . . . . . . . . . . 234 Converting Mode-Specific Bitmaps . . . . . . . . . . . . . . . . . . 236 Bitmap Scaling and Shearing . . . . . . . . . . . . . . . . . . . . 239 Pixel Run Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 Masking Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 Summary of Bitmapped Image Display Routines . . . . . . . . . . . . 251
Chapter 11 Block Transfer Routines . . . . . . . . . . . . . . . . . . . 255
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 Full Page Transfer . . . . . . . . . . . . . . . . . . . . . . . . . 256 Byte Boundaries . . . . . . . . . . . . . . . . . . . . . . . . . . 257 Dual SVGA Banks . . . . . . . . . . . . . . . . . . . . . . . . . . 259 The "Hidden" Video Page . . . . . . . . . . . . . . . . . . . . . . 259 Saving and Restoring Blocks . . . . . . . . . . . . . . . . . . . . 259 A More General Block Transfer Routine . . . . . . . . . . . . . . . 262
v � Block Transfer Routines for Virtual Buffers . . . . . . . . . . . . 266 Blocks with Transparent Colors . . . . . . . . . . . . . . . . . . . 267 Transparent Block Transfers for Virtual Buffers . . . . . . . . . . 269 Transferring Blocks to and from Conventional Memory . . . . . . . . 270 Summary of Block Transfer Routines . . . . . . . . . . . . . . . . . 271
Chapter 12 Animation Techniques . . . . . . . . . . . . . . . . . . . . 273
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 Simple Animation . . . . . . . . . . . . . . . . . . . . . . . . . . 274 XOR Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 Static Frame Animation . . . . . . . . . . . . . . . . . . . . . . . 278 Dynamic Frame Animation . . . . . . . . . . . . . . . . . . . . . . 280 Page Flipping . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 An Animation Example: The Fastgraph Fish Tank . . . . . . . . . . . 284 Summary of Animation Techniques . . . . . . . . . . . . . . . . . . 284
Chapter 13 Special Effects . . . . . . . . . . . . . . . . . . . . . . . 287
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 Screen Dissolving . . . . . . . . . . . . . . . . . . . . . . . . . 288 Scrolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 Changing the Screen Origin . . . . . . . . . . . . . . . . . . . . . 293 Panning With Virtual Buffers . . . . . . . . . . . . . . . . . . . . 296 Split Screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 Summary of Special Effects Routines . . . . . . . . . . . . . . . . 300
Chapter 14 Input Device Support . . . . . . . . . . . . . . . . . . . . 301
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 Keyboard Support . . . . . . . . . . . . . . . . . . . . . . . . . . 302 Reading Keystrokes . . . . . . . . . . . . . . . . . . . . . . 304 Testing and Setting Key States . . . . . . . . . . . . . . . . 305 Low-Level Keyboard Handler . . . . . . . . . . . . . . . . . . 307 Mouse Support . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 Initializing the Mouse . . . . . . . . . . . . . . . . . . . . 309 XVGA and SVGA Mouse Considerations . . . . . . . . . . . . . . 310 Controlling the Mouse Cursor . . . . . . . . . . . . . . . . . 311 Reporting the Mouse Status . . . . . . . . . . . . . . . . . . 313 Defining the Mouse Cursor . . . . . . . . . . . . . . . . . . . 315 Joystick Support . . . . . . . . . . . . . . . . . . . . . . . . . . 323 Initializing Joysticks . . . . . . . . . . . . . . . . . . . . 323 Reporting Joystick Status . . . . . . . . . . . . . . . . . . . 324 Keyboard Emulation . . . . . . . . . . . . . . . . . . . . . . 325 Special Joystick Considerations . . . . . . . . . . . . . . . . 326 Summary of Input Routines . . . . . . . . . . . . . . . . . . . . . 326
Chapter 15 Sound Effects . . . . . . . . . . . . . . . . . . . . . . . . 329
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 Sound Sources . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 Synchronous Sound . . . . . . . . . . . . . . . . . . . . . . . . . 330 Asynchronous Sound . . . . . . . . . . . . . . . . . . . . . . . . . 335 Summary of Sound Routines . . . . . . . . . . . . . . . . . . . . . 340
Chapter 16 Program Timing . . . . . . . . . . . . . . . . . . . . . . . 343
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344 Real-Time Routines . . . . . . . . . . . . . . . . . . . . . . . . . 344 Routines Dependent on the System Speed . . . . . . . . . . . . . . . 345 Summary of Timing Routines . . . . . . . . . . . . . . . . . . . . . 347
vi �
Chapter 17 Miscellaneous Routines . . . . . . . . . . . . . . . . . . . 349
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 Determining Available Memory . . . . . . . . . . . . . . . . . . . . 350 Choosing the Video Memory Update Function . . . . . . . . . . . . . 351 Controlling Vertical Retrace Synchronization . . . . . . . . . . . . 352 External SVGA Bank Switching . . . . . . . . . . . . . . . . . . . . 353 Saving and Restoring the Video State . . . . . . . . . . . . . . . . 353 Summary of Miscellaneous Routines . . . . . . . . . . . . . . . . . 354
Appendix A Fastgraph Utilities . . . . . . . . . . . . . . . . . . . . . 355
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 SNAPSHOT Utility . . . . . . . . . . . . . . . . . . . . . . . . . . 356 CLIP Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 CONVERT Utility . . . . . . . . . . . . . . . . . . . . . . . . . . 358 EDITSPR Utility . . . . . . . . . . . . . . . . . . . . . . . . . . 359 GrabRGB Utility . . . . . . . . . . . . . . . . . . . . . . . . . . 359 HERCFIX Utility . . . . . . . . . . . . . . . . . . . . . . . . . . 360 PCXHEAD Utility . . . . . . . . . . . . . . . . . . . . . . . . . . 361
Appendix B Using Fastgraph from Assembly Language . . . . . . . . . . . 363
Appendix C Interrupts and Fastgraph . . . . . . . . . . . . . . . . . . 367
Interrupts Used by Fastgraph . . . . . . . . . . . . . . . . . . . . 368 Extending the Time-of-Day Interrupt . . . . . . . . . . . . . . . . 368
Appendix D Contents of the Compiler-Specific Libraries . . . . . . . . . 373
Appendix E Contents of the Pascal Unit Files . . . . . . . . . . . . . . 375
Appendix F Integrating Fastgraph With Other Graphics Software . . . . . 379
Appendix G Converting Programs to Protected Mode . . . . . . . . . . . . 381
Protected Mode Initialization . . . . . . . . . . . . . . . . . . . 382 Considerations for Logical Pages . . . . . . . . . . . . . . . . . . 382 Considerations for Virtual Buffers . . . . . . . . . . . . . . . . . 382 Mouse Cursor Definition . . . . . . . . . . . . . . . . . . . . . . 382 FORTRAN Data Types . . . . . . . . . . . . . . . . . . . . . . . . . 383 Incompatible Real Mode Behavior . . . . . . . . . . . . . . . . . . 383
Appendix H Image File Header Formats . . . . . . . . . . . . . . . . . . 385
vii �
viii �
Chapter 1
Introduction � 2 Fastgraph User's Guide
What is Fastgraph?
Fastgraph is a library of more than 275 highly-optimized routines that
are callable from high-level and assembly language programs running under the MS-DOS or PC-DOS operating systems. This collection of routines provides a programmer with proven, powerful tools to take command of the PC and PS/2 video environment. In addition to its video support, Fastgraph also includes routines to perform keyboard, mouse, and joystick control, as well as music and sound capabilities. Fastgraph is an ideal development tool for entertainment and educational software, presentation graphics products, scientific and engineering applications, CAD/CAM, animation, or any application that demands robust graphics.
As its name implies, the most notable feature of Fastgraph is its speed.
Virtually all of Fastgraph is written in assembly language, and each routine has been optimized by hand to provide maximum performance. Fastgraph's protected mode libraries take advantage of the features offered by the 80286 and 80386 instruction sets.
Fastgraph supports all the standard text and graphics video modes used by
the IBM PC and compatible systems (PC, PC/XT, and PC/AT, 80386, 80486, and Pentium) and IBM PS/2 family. In addition, Fastgraph provides support for six SuperVGA (SVGA) graphics modes, four extended VGA (XVGA) graphics modes, and a 16-color graphics mode unique to Tandy 1000 series computers and the PCjr. Even though the graphics mode of the Hercules Graphics Card is not an IBM standard, its one-time popularity has made it a de facto standard, and for this reason Fastgraph also supports it. In total, Fastgraph supports 23 graphics modes and 5 text modes. A complete discussion of these video modes appears in the next chapter.
Fastgraph/Light
Fastgraph/Light is a subset of Fastgraph. It includes all of Fastgraph's
features except the GIF file support routines, redefinable world space coordinate system, and the routines pertaining to software characters. Programs created using Fastgraph/Light are 100% source code compatible with Fastgraph.
The most important difference between Fastgraph/Light and Fastgraph is
the method of running a program created with the two products. With Fastgraph, any of its routines used in your program are linked directly into the resulting EXE file. With Fastgraph/Light, however, this is not the case. Instead, the Fastgraph/Light routines provide an interface to an external driver, called the Fastgraph/Light Video Driver, which must be loaded separately before running programs that call any Fastgraph/Light routines. See the last section of this chapter for more information.
Another important difference between Fastgraph and Fastgraph/Light is the
name of the library (LIB) files. All Fastgraph libraries begin with the two characters FG, while the equivalent Fastgraph/Light libraries begin with the three characters FGL. For example, FGS.LIB is the small model Fastgraph library used with most C compilers, but FGLS.LIB is the equivalent Fastgraph/Light library name. Note that the Pascal unit files always begin with FG, whether you're using Fastgraph or Fastgraph/Light. �
Chapter 1: Introduction 3
In the Fastgraph User's Guide and the accompanying Fastgraph Reference
Manual, references to Fastgraph also apply to Fastgraph/Light unless stated otherwise.
Prerequisite Knowledge
Fastgraph is a programming tool, which means programmers are its intended
audience. For this reason, the Fastgraph User's Guide and Fastgraph Reference Manual assume you have a knowledge of programming. Additionally, a knowledge of converting numbers between binary, decimal, and hexadecimal is assumed.
Virtually all the examples in this manual are written in the C
programming language, so a knowledge of C would be especially helpful. The examples intentionally avoid using any of C's features and idioms that might not be readily apparent to a programmer unfamiliar with C. If you're programming in real mode, don't be confused by the fact that all the examples call Fastgraph's fg_initpm routine for protected mode initialization -- in real mode, fg_initpm simply returns to the caller. Finally, we'd like to point out that the examples should be read not by themselves, but as part of the surrounding text.
Supported Compilers
You can use Fastgraph with any compilers or assemblers that use the same
calling and naming conventions as the small, medium, large, or flat memory models of the supported compilers. Mixed language programming is allowed where supported by the language translators, linker, and DOS extender being used. Fastgraph supports the following compilers:
* Borland C++ (version 2.0 or later) * Borland Pascal (version 7.0 or later) * MetaWare High C/C++ (version 3.0 or later) * Microsoft BASIC Professional Development System (version 7.0 or 7.1) * Microsoft C/C++ (version 5.1 or later) * Microsoft FORTRAN (version 4.0 or later) * Microsoft FORTRAN PowerStation (version 1.0 or later) * Microsoft QuickBASIC (version 4.0 or later) * Microsoft QuickC (version 2.0 or later) * Microsoft Visual Basic for DOS (version 1.0 or later) * Microsoft Visual C++ (version 1.0 or later) * Microsoft Visual C++ 32-bit Edition (version 1.0 or later) * Power C (version 2.0 or later) * Turbo C (version 2.0 or later) * Turbo C++ (version 1.0 or later) * Turbo Pascal (version 6.0 or later) * WATCOM C/C++ (version 9.5 or later) * WATCOM C32 for DOS (version 9.5 or later) * Zortech C++ (version 3.0 or later)
The listed version numbers are the compiler versions under which Fastgraph was developed and tested. Fastgraph may or may not work with earlier versions of these compilers. As we constantly add support for new compilers, please check the READ.ME file in the \FG directory for possible additions to the above � 4 Fastgraph User's Guide
list. The use of Fastgraph from assembly language programs is addressed in Appendix B.
Real Mode, Protected Mode, and DOS Extenders
DOS is inherently a real mode operating system. Real mode is the native
(and only) operating mode of the 8086 and 8088 microprocessors, upon which the original IBM PC and PC/XT systems were based. While these processors provided the ability to address one megabyte of memory, IBM reserved the upper 384K of this one megabyte address space for such things as video memory and the ROM BIOS. This left a maximum of 640K for DOS applications.
Intel's later microprocessors (80286, 80386, 80486, and Pentium) provide
a second operating mode called protected mode. Perhaps the most important aspect of protected mode is its ability to use much more memory. When running in protected mode, the 16-bit 80286 processor has a 16 megabyte addressability, while the 32-bit 80386 and later processors can address four gigabytes. Expanded and extended memory services provide limited access to this larger address space, but a program must run in protected mode if it wants to treat this memory like conventional DOS memory. Because DOS is a real mode operating system, DOS applications running on 80286 and later processors are still restricted to DOS's ubiquitous 640K barrier. In this case, these systems function merely as faster 8086 or 8088 systems.
When a DOS-compatible protected mode operating system did not appear, DOS
extenders arrived instead. A DOS extender is a product, a "mini-operating system" if you will, that can run protected mode applications under DOS. The DOS extender accomplishes this by executing a real mode stub program that switches the processor to protected mode and passes control to your program. Your program continues to run in protected mode until it issues a BIOS or DOS service such as a file I/O request. The extender then switches back to real mode to satisfy the request, and upon completion reverts to protected mode. When your program terminates, the DOS extender switches back to real mode and returns control to DOS. This is of course an oversimplification of how a DOS extender works, but these behind the scenes tasks are transparent to your program's end users. From their perspective, an extended DOS application executes just like any ordinary DOS application.
DOS extenders come in two flavors: 16-bit and 32-bit. Programs written
for 16-bit DOS extenders require at least an 80286-based system, while those written for 32-bit extenders require an 80386 or better. Many real mode compilers can create 16-bit extended DOS applications, but you'll need special 32-bit compilers to create 32-bit extended DOS applications. Fastgraph supports the following 16-bit DOS extenders:
* Blinker * Borland Pascal 7 (built in DPMI extender) * Borland PowerPack for DOS * Phar Lap 286|Dos-Extender SDK * Phar Lap 286|Dos-Extender Lite * Rational Systems DOS/16M
Fastgraph supports the following 32-bit DOS extenders:
* Borland PowerPack for DOS * CauseWay Chapter 1: Introduction 5
* DOSXMSF (supplied with Microsoft FORTRAN PowerStation) � * FlashTek X-32 * Phar Lap TNT Dos-Extender SDK (formerly 386|Dos-Extender SDK) * Phar Lap TNT Dos-Extender Lite * Rational Systems DOS/4G * Rational Systems DOS/4GW (supplied with 32-bit WATCOM compilers) * Rational Systems DOS/4GW Professional
Please check the READ.ME file in the \FG directory for possible additions to the above lists.
Note that some DOS extenders require licensing fees or royalty payments
before you can include or bind their components with applications you distribute. We recommend checking your DOS extender manuals or license agreement for details, or if you're not sure, contacting the DOS extender manufacturer directly.
Memory Models
Fastgraph's supported real mode C, C++, and FORTRAN compilers offer
several memory models. A memory model defines how memory is set up for a program's code and data segments. Fastgraph includes real mode libraries for the small, medium, and large memory models and protected mode libraries for 16-bit and 32-bit environments. The 16-bit protected mode libraries use an extension of the large memory model, while the 32-bit libraries use a special flat memory model.
The small memory model allows for one code segment and one data segment.
Programs that use the small model can thus have a maximum of 64K bytes of code and 64K bytes of data. Because the small model implements call instructions and data references through near pointers, it produces the most efficient code of the three supported real mode memory models. The small memory model is specific to real mode compilers.
The medium memory model allows for multiple code segments and one data
segment. Programs that use the medium model thus have no compiler-imposed limit to the code size (although no one segment can exceed 64K bytes) and a maximum of 64K bytes of data. Like the small model, the medium model implements data references through near pointers, but it implements call instructions through far pointers. The use of far pointers adds two bytes of code and 13 clock cycles for each subprogram call. The medium model is a popular choice for real mode programs and is specific to real mode compilers.
The large memory model supports multiple code and data segments. Programs
that use the large model do not have any compiler-imposed limits for code and data sizes. However, no single code or data segment can exceed 64K bytes. Because the large model implements call instructions and data references through far pointers, it produces the least efficient code of the three supported memory models. In real mode, the total size of all code and data segments is limited by the DOS 640K barrier, though in reality the true limit will be somewhat less depending on the target system's configuration and resident programs. In 16-bit protected mode, the total size of all code and data segments can reach 16 megabytes, although no one segment can exceed 64K bytes.
The flat memory model allows for one code segment and one data segment,
just like the small memory model. The flat model differs in that the segment � 6 Fastgraph User's Guide
sizes can be up to four gigabytes instead of 64K. By default, the flat model
implements call instructions and data references through 32-bit near pointers,
virtually eliminating the need for segments. The flat memory model is specific
to 32-bit protected mode compilers.
For more information about memory models, please refer to the user's
guide or reference manual supplied with your compiler.
Installing Fastgraph
This section explains how to use the INSTALL program to load Fastgraph
(or Fastgraph/Light) and its related files on a hard disk. The installation program lets you select the compilers, memory models, and DOS extenders you wish to use with Fastgraph. It also gives you the opportunity to load many example Fastgraph programs specific to the compilers you choose.
Before you start the installation, we recommend using the DOS commands
COPY or DISKCOPY to make working copies of the Fastgraph distribution disks (refer to your DOS reference manual if you are unfamiliar with these commands). Once you have created the working copies, store the original disks in a safe place. Install Fastgraph from the working copies you just created.
For simplicity, we'll assume you are installing Fastgraph from the
diskette drive A: to the hard drive C:, but you of course can use any available drives. The Fastgraph distribution disk labeled Installation and Utilities contains Fastgraph's INSTALL program. Place this disk in the A: drive, make A: your current drive, and enter the command INSTALL, as shown here:
C> A: A> INSTALL
From this point, just follow the directions on each screen. At any time, you can press the Escape key to abort the installation.
The INSTALL program will ask you for the compilers, memory models, and
DOS extenders you'll use with Fastgraph, as well as the directory names for the Fastgraph utilities, libraries, and include files. For the utilities, the default directory is C:\FG. For the include files and libraries, we recommend using directories where the compiler you've chosen normally searches for such files. INSTALL will automatically try to determine these directories and propose them as defaults.
You can install support for additional compilers, memory models, or DOS
extenders at any time. If you choose to do this, you should use the command INSTALL /L to avoid copying the files common to all environments.
The READ.ME File
The READ.ME file contains additions and changes that may have been made
to Fastgraph since the publication of the manuals. We encourage you to examine the READ.ME file immediately after installing Fastgraph. READ.ME is an ASCII text file, suitable for any printer or text editor. The INSTALL program places the READ.ME file in the Fastgraph utilities directory (C:\FG by default). �
Chapter 1: Introduction 7
The WHATS.NEW File
The WHATS.NEW file contains information about new features added in
Fastgraph version 4.0. Programmers who've used earlier versions of Fastgraph may want to examine the WHATS.NEW file to learn about Fastgraph's new functionality and possible changes needed when converting applications to version 4.0. WHATS.NEW is an ASCII text file, suitable for any printer or text editor. The INSTALL program places the WHATS.NEW file in the Fastgraph utilities directory (C:\FG by default).
Fastgraph Naming Conventions
The names of all Fastgraph routines begin with the three characters
"fg_". This prefix helps identify Fastgraph routines within a program, and it also reduces the chance of name conflicts that might otherwise occur between Fastgraph and other third party libraries.
Because BASIC does not permit underscores in identifiers, the BASIC
versions of Fastgraph routines begin with the two characters "FG". For example, the fg_version routine is named FGversion in the BASIC libraries. All future references to Fastgraph routines in the Fastgraph User's Guide and the Fastgraph Reference Manual will use the fg_ naming convention instead of the BASIC names.
Compilation and Linking
To build an executable (EXE) file for a program that uses Fastgraph
routines, first compile or assemble the program using one of the supported memory models. This step produces an object file, which you then link with one or more Fastgraph libraries (or Pascal unit files) and possibly other libraries to produce an executable file. When creating protected mode executables, additional binding steps may be needed as described in your compiler or DOS extender manuals. The Fastgraph libraries or Pascal unit files must reside in a directory where the linker normally searches for such files.
Example 1-1 uses the Fastgraph routine fg_version to display the version
number for your copy of Fastgraph. It also uses one other Fastgraph routine, fg_initpm, to set up Fastgraph's protected mode kernel for the selected DOS extender (when using the real mode Fastgraph libraries, fg_initpm does nothing). Versions of this program are presented for each high-level language Fastgraph supports: C/C++, BASIC, FORTRAN, and Pascal. If you loaded the example programs when you installed Fastgraph, the files \FG\EXAMPLES\01-01.C, 01-01.BAS, 01-01.FOR, and 01-01.PAS contain the source code for these examples. You can use them to test the compilation and linking process for the compilers you'll be using with Fastgraph.
Example 1-1 (C/C++ version).
#include <fastgraf.h> #include <stdio.h> void main(void); �
8 Fastgraph User's Guide
void main() { int major; int minor;
fg_initpm(); fg_version(&major,&minor); printf("This is version %d.%2.2d of Fastgraph.\n",major,minor); }
The header file FASTGRAF.H contains the C and C++ function prototypes for
each Fastgraph routine. It must reside in a directory where the compiler normally searches for other header files. When creating 32-bit protected mode applications, FASTGRAF.H will define the symbol FG32. This symbol is useful for controlling conditional compilation when creating applications that run in both 16-bit and 32-bit environments.
Example 1-1 (BASIC version).
REM $INCLUDE: 'fastgraf.bi'
DEFINT A-Z
FGversion Major, Minor Version! = Major + Minor*0.01
PRINT USING "This is version #.## of Fastgraph."; Version!
END
You must include the DECLARE commands in the file FASTGRAF.BI at the
beginning of each BASIC module. This file should reside in a directory where the compiler normally searches for BI files, or in any of the directories specified by the INCLUDE environment variable. The DECLARE commands in this file automatically provide the calling convention and naming convention for each Fastgraph routine. In addition, they relieve the BASIC programmer of distinguishing arguments passed by value from those passed by reference.
Example 1-1 (FORTRAN version).
$INCLUDE: '\FG\FASTGRAF.FI'
PROGRAM MAIN
INTEGER MAJOR INTEGER MINOR
CALL FG_INITPM CALL FG_VERSION (MAJOR, MINOR)
WRITE (6,10) MAJOR, MINOR 10 FORMAT (' This is version ', I1, '.', I2.2, ' of Fastgraph.')
STOP ' ' � Chapter 1: Introduction 9
END
You must include the INTERFACE statements in the file FASTGRAF.FI at the
beginning of FORTRAN programs (this file should reside in the \FG directory). The INTERFACE statements in this file automatically provide the calling convention and naming convention for each Fastgraph routine. In addition, they relieve the FORTRAN programmer of distinguishing arguments passed by value from those passed by reference.
Example 1-1 (Pascal version).
program main; uses fgmain;
var Major : integer; Minor : integer;
begin fg_initpm; fg_version(Major,Minor); writeln('This is version ',Major,'.',Minor:2,' of Fastgraph.'); end.
Pascal programs that use Fastgraph or Fastgraph/Light must include a uses
statement specifying the names of the unit files (TPU or TPP files) needed in the program. This list must always include the fgmain unit; for protected mode programs that call GlobalAllocPtr, GlobalFreePtr, or other functions in WinAPI, it also must include the WinAPI unit. All unit files must reside in a directory where the compiler normally searches for such files. Appendix E lists the Fastgraph functions in each unit.
The following sections show the simplest procedures for compiling a
program and linking it with Fastgraph. Information is presented for each supported compiler, listed alphabetically by the compiler name. In what follows, items enclosed in angle brackets, such as <source_file>, are placeholders for parameters you must supply (the name of a file in this case). Items enclosed in square brackets, such as [/E], are optional. For simplicity, we'll only show the Fastgraph library names. If you're using Fastgraph/Light, the library names will begin with "FGL" instead of "FG". For example, FGS.LIB is the real mode small model Fastgraph for most C compilers, while FGLS.LIB is the equivalent library for Fastgraph/Light. Note that Fastgraph/Light does not support protected mode environments. � 10 Fastgraph User's Guide
Borland C++
Borland C++ can create real mode, 16-bit protected mode, and 32-bit
protected mode applications (Borland C++ 4.0 or later is required for 32-bit protected mode). You can compile and link programs directly from the DOS command line or from the Borland C++ integrated development environment (IDE). The following Fastgraph libraries are compatible with Borland C++:
FGS.LIB Real mode small model general library FGM.LIB Real mode medium model general library FGL.LIB Real mode large model general library FGTCS.LIB Real mode small model auxiliary library FGTCM.LIB Real mode medium model auxiliary library FGTCL.LIB Real mode large model auxiliary library FG16.LIB 16-bit protected mode general library FG16BC.LIB 16-bit protected mode auxiliary library FG16DPMI.LIB 16-bit DPMI-compliant DOS extender support library FG16PHAR.LIB Phar Lap 286|Dos-Extender support library FG32.LIB 32-bit protected mode general library FG32BC.LIB 32-bit protected mode auxiliary library FG32DPMI.LIB 32-bit DPMI-compliant DOS extender support library FG32PHAR.LIB Phar Lap TNT|Dos-Extender support library
To build real mode Fastgraph applications in the Borland C++ IDE, the
compiler options must match one of Fastgraph's available memory models (small, medium, or large). 16-bit protected mode programs must use the large memory model, while 32-bit protected mode programs must be compiled as console applications. In any case, you also must create a project file that includes the name of each C, CPP, and LIB file required by your application (refer to your Borland C++ manuals for information about project files). For Borland C++ 4.0 and above, the project file also specifies the platform: DOS for real mode applications, DOS (16-bit DPMI) for 16-bit protected mode applications, or DOS (32-bit DPMI) for 32-bit protected mode applications. Project files are only needed when using the IDE.
You can also compile and link programs from the DOS command line using
the BCC or BCC32 commands. Here are example BCC and BCC32 commands for compiling a Borland C++ program and linking it with Fastgraph. The compiler- specific auxiliary library names only need to be included when your program uses any of the Fastgraph routines listed in Appendix D.
Real mode, small memory model: BCC -ms <source_file> FGS.LIB [FGTCS.LIB]
Real mode, medium memory model: BCC -mm <source_file> FGM.LIB [FGTCM.LIB]
Real mode, large memory model: BCC -ml <source_file> FGL.LIB [FGTCL.LIB]
16-bit protected mode, Borland PowerPack DOS extender: BCC -ml -WX <source_file> FG16.LIB FG16DPMI.LIB [FG16BC.LIB]
16-bit protected mode, Phar Lap 286|Dos-Extender: BCC286 <source_file> FG16.LIB FG16PHAR.LIB [FG16BC.LIB] � Chapter 1: Introduction 11
32-bit protected mode, Borland PowerPack DOS extender: BCC32 -WX <source_file> FG32.LIB FG32DPMI.LIB [FG32BC.LIB]
To create Borland C++ 16-bit protected mode programs using the Rational Systems DOS/16M extender, please refer to the DOS/16M User's Guide. To create Borland C++ 32-bit protected mode programs using the Phar Lap TNT|Dos-Extender, please refer to Phar Lap's C/C++ User's Guide to TNT Dos-Extender.
For more information about memory models or other compilation and linking
options, please refer to the Borland C++ User's Guide, Borland PowerPack for DOS User's Guide, Phar Lap's Borland C++ User's Guide to 286 Dos-Extender, or the DOS/16M User's Guide. � 12 Fastgraph User's Guide
Borland Pascal
Borland Pascal can create real mode and 16-bit protected mode
applications. Protected mode applications can be built without a third party DOS extender, as the necessary protected mode extensions are implemented through a DOS Protected Mode Interface (DPMI) server and a run-time manager. You can compile real mode and protected mode programs directly from the DOS command line or from the Borland Pascal integrated development environment (IDE).
To build Fastgraph applications in the Borland Pascal IDE, just start the
IDE as you would for any other Pascal program, making sure the Fastgraph unit files reside in one of the directories listed in the IDE's "Unit Directories" option. If you're creating a protected mode application from the IDE, choose Compile|Target and select "Protected-mode Application" from the Target Platform dialog box.
You can also compile Borland Pascal programs from the DOS command line
using the BPC or TPC commands, as shown here. Real mode programs can use either BPC or TPC, while protected mode programs must use BPC.
Real mode: BPC <source_file> TPC <source_file>
16-bit protected mode: BPC /CP <source_file>
For more information about other compilation and linking options, please
refer to the Borland Pascal With Objects User's Guide.
All remaining example programs in the Fastgraph User's Guide are written
in the C programming language. However, when you install Fastgraph for Borland Pascal, the installation procedure copies Pascal versions of the example programs to the \FG\EXAMPLES directory. �
Chapter 1: Introduction 13
MetaWare High C/C++
MetaWare High C/C++ is strictly a 32-bit protected mode compiler. It
supports the Phar Lap TNT|Dos-Extender SDK and the Rational Systems DOS/4G extender. The following Fastgraph libraries are compatible with MetaWare High C/C++:
FG32.LIB 32-bit protected mode general library FG32HC.LIB 32-bit protected mode auxiliary library FG32DPMI.LIB 32-bit DPMI-compliant DOS extender support library FG32PHAR.LIB Phar Lap TNT|Dos-Extender support library
Programs are compiled and linked from the DOS command line using the
HC386 command. Here are example HC386 commands for compiling a MetaWare High C/C++ program and linking it with Fastgraph. The compiler-specific auxiliary library (FG32HC) only needs to be included when your program uses any of the Fastgraph routines listed in Appendix D.
32-bit protected mode, Phar Lap TNT|Dos-Extender: HC386 <source_file> -lFG32 -lFG32PHAR [-lFG32HC] -nomap -onecase
32-bit protected mode, Rational Systems DOS/4G extender: HC386 <source_file> -Hdos4g -lFG32 -lFG32DPMI [-lFG32HC]
For more information about other compilation and linking options, please
refer to the MetaWare High C/C++ Programmer's Guide, Phar Lap's C/C++ User's Guide to TNT Dos-Extender, or the DOS/4G User's Manual. � 14 Fastgraph User's Guide
Microsoft BASIC Professional Development System
You can compile and link Microsoft BASIC Professional Development System
(PDS) programs directly from the DOS command line or from the PDS programming environment. In either case, BASIC PDS always creates real mode programs. The following Fastgraph libraries are compatible with BASIC PDS:
FGQBX.LIB Stand-alone library for BASIC PDS FGQBX.QLB Quick library for BASIC PDS
To build Fastgraph applications in the PDS programming environment, just
specify the quick library name FGQBX when starting BASIC PDS:
QBX /LFGQBX [<source_file>]
You must use the default "Far Strings" setting within the PDS environment. There are no near string Fastgraph libraries available for BASIC PDS.
To compile a BASIC PDS program from the DOS command line and link it with
Fastgraph, use the BC and LINK commands:
BC /Fs [/O] <source_file>; LINK [/E] <object_file>,,NUL,FGQBX;
The /O option on the BC command is recommended because it creates EXE files that do not require the BASIC PDS run-time module. The /E linker option is not required but will produce a smaller EXE file if specified. For more information about other compilation and linking options, please refer to the Microsoft BASIC Professional Development System Programmer's Guide.
All remaining example programs in the Fastgraph User's Guide are written
in the C programming language. However, when you install Fastgraph for Microsoft BASIC PDS, the installation procedure copies BASIC versions of the example programs to the \FG\EXAMPLES directory. �
Chapter 1: Introduction 15
Microsoft C/C++
Microsoft C/C++ can create real mode and 16-bit protected mode
applications. For protected mode, it supports the Phar Lap 286|Dos-Extender (both SDK and Lite versions) and the Rational Systems DOS/16M extender. The following Fastgraph libraries are compatible with Microsoft C/C++:
FGS.LIB Real mode small model general library FGM.LIB Real mode medium model general library FGL.LIB Real mode large model general library FGMSCS.LIB Real mode small model auxiliary library FGMSCM.LIB Real mode medium model auxiliary library FGMSCL.LIB Real mode large model auxiliary library FG16.LIB 16-bit protected mode general library FG16MSC.LIB 16-bit protected mode auxiliary library FG16DPMI.LIB 16-bit DPMI-compliant DOS extender support library FG16PHAR.LIB Phar Lap 286|Dos-Extender support library
Programs are compiled and linked from the DOS command line using the CL
command. Here are example CL commands for compiling a Microsoft C/C++ program and linking it with Fastgraph. The compiler-specific auxiliary library names only need to be included when your program uses any of the Fastgraph routines listed in Appendix D. In the real mode examples, the /E linker option is not required but will produce a smaller EXE file if specified.
Real mode, small memory model: CL /AS <source_file> /link FGS.LIB [FGMSCS.LIB] [/E]
Real mode, medium memory model: CL /AM <source_file> /link FGM.LIB [FGMSCM.LIB] [/E]
Real mode, large memory model: CL /AL <source_file> /link FGL.LIB [FGMSCL.LIB] [/E]
16-bit protected mode, Phar Lap 286 SDK or Lite extender: CL /AL /Lp <source_file> /link FG16.LIB FG16PHAR.LIB [FG16MSC.LIB]
To create Microsoft C/C++ protected mode programs using the Rational Systems DOS/16M extender, please refer to the DOS/16M User's Guide.
For more information about memory models or other compilation and linking
options, please refer to the Microsoft C Optimizing Compiler User's Guide, Phar Lap's Microsoft C & C++ User's Guide to 286|Dos-Extender, or the DOS/16M User's Guide. � 16 Fastgraph User's Guide
Microsoft FORTRAN
Microsoft FORTRAN creates real mode applications. The following Fastgraph
libraries are compatible with Microsoft FORTRAN:
FGM.LIB Real mode medium model general library FGL.LIB Real mode large model general library FGMSFM.LIB Real mode medium model auxiliary library FGMSFL.LIB Real mode large model auxiliary library
Programs are compiled and linked from the DOS command line using the FL
command. Here are example FL commands for compiling a Microsoft FORTRAN program and linking it with Fastgraph. The compiler-specific auxiliary library names only need to be included when your program uses any of the Fastgraph routines listed in Appendix D. The /E linker option is not required but will produce a smaller EXE file if specified.
Medium memory model: FL /AM /FPi /4I2 /4Nt <source_file> /link FGM.LIB [FGMSFM.LIB] [/E]
Large memory model: FL /AL /FPi /4I2 /4Nt <source_file> /link FGL.LIB [FGMSFL.LIB] [/E]
For more information about memory models or other compilation and linking
options, please refer to the Microsoft FORTRAN Optimizing Compiler User's Guide.
All remaining example programs in the Fastgraph User's Guide are written
in the C programming language. However, when you install Fastgraph for the Microsoft FORTRAN compiler, the installation procedure copies FORTRAN versions of the example programs to the \FG\EXAMPLES directory. �
Chapter 1: Introduction 17
Microsoft FORTRAN PowerStation
Microsoft FORTRAN PowerStation is strictly a 32-bit protected mode
compiler. It supports the DOSXMSF DOS extender included with the compiler and the Phar Lap TNT|Dos-Extender SDK (DOSXMSF is a subset of the TNT|Dos-Extender). The following Fastgraph library is compatible with Microsoft FORTRAN PowerStation:
FG32MSF.LIB 32-bit PM library for Microsoft FORTRAN PowerStation
FG32MSF.LIB includes Fastgraph's Phar Lap support functions normally found in the FG32PHAR.LIB library.
Programs are compiled and linked from the DOS command line using the FL32
command:
FL32 <source_file> FG32MSF.LIB
This command invokes the PowerStation compiler and Microsoft Portable Executable Linker (LINK32) to create a 32-bit protected mode executable.
For more information about other compilation and linking options, please
refer to the Microsoft FORTRAN PowerStation User's Guide or Phar Lap's FORTRAN User's Guide to TNT Dos-Extender. � 18 Fastgraph User's Guide
Microsoft QuickBASIC
You can compile and link Microsoft QuickBASIC programs directly from the
DOS command line or from the QuickBASIC programming environment. In either case, QuickBASIC always creates real mode programs. The following Fastgraph libraries are compatible with QuickBASIC:
FGQB.LIB Stand-alone library for QuickBASIC FGQB.QLB Quick library for QuickBASIC
To build Fastgraph applications in QuickBASIC's programming environment,
just specify the quick library name FGQB when starting QuickBASIC:
QB /LFGQB [<source_file>]
To compile a QuickBASIC program from the DOS command line and link it with Fastgraph, use the BC and LINK commands:
BC [/O] <source_file>; LINK [/E] <object_file>,,NUL,FGQB;
The /O option on the BC command is recommended because it creates EXE files that do not require the QuickBASIC run-time module. The /E linker option is not required but will produce a smaller EXE file if specified. For more information about other compilation and linking options, please refer to the Microsoft QuickBASIC: Programming in BASIC manual.
All remaining example programs in the Fastgraph User's Guide are written
in the C programming language. However, when you install Fastgraph for Microsoft QuickBASIC, the installation procedure copies BASIC versions of the example programs to the \FG\EXAMPLES directory. �
Chapter 1: Introduction 19
Microsoft QuickC
You can compile and link Microsoft QuickC programs directly from the DOS
command line or from the QuickC programming environment. In either case, QuickC always creates real mode programs. The following Fastgraph libraries are compatible with QuickC:
FGS.LIB Real mode small model general library FGM.LIB Real mode medium model general library FGL.LIB Real mode large model general library FGMSCS.LIB Real mode small model auxiliary library FGMSCM.LIB Real mode medium model auxiliary library FGMSCL.LIB Real mode large model auxiliary library
To build Fastgraph applications in the QuickC programming environment,
you must make sure the compiler options match one of Fastgraph's available memory models (small, medium, or large) and then create a make file that includes the corresponding Fastgraph library names.
To compile a QuickC program from the DOS command line and link it with
Fastgraph, use the QCL command. Here are example QCL commands for compiling a QuickC program and linking it with Fastgraph. The compiler-specific auxiliary library names only need to be included when your program uses any of the Fastgraph routines listed in Appendix D. The /E linker option is not required but will produce a smaller EXE file if specified.
Small memory model: QCL /AS <source_file> /link FGS.LIB [FGMSCS.LIB] [/E]
Medium memory model: QCL /AM <source_file> /link FGM.LIB [FGMSCM.LIB] [/E]
Large memory model: QCL /AL <source_file> /link FGL.LIB [FGMSCL.LIB] [/E]
For more information about make files, memory models, or other
compilation and linking options, please refer to the Microsoft QuickC Tool Kit manual. � 20 Fastgraph User's Guide
Microsoft Visual Basic for DOS
You can compile and link Microsoft Visual Basic for DOS programs directly
from the DOS command line or from the Visual Basic programming environment. In either case, Visual Basic always creates real mode programs. The following Fastgraph libraries are compatible with Visual Basic:
FGVBDOS.LIB Stand-alone library for Visual Basic FGVBDOS.QLB Quick library for Visual Basic
To build Fastgraph applications in Visual Basic's programming
environment, just specify the quick library name FGVBDOS when starting Visual Basic:
VBDOS /LFGVBDOS [<source_file>]
When using the programming environment, you may get an "Out of Memory" or "Out of String Space" error message when trying to build an EXE file or run an application within the environment. Should this occur, you must specify the /S option on the VBDOS command line to increase the amount of memory available to your application. If you have EMS or XMS memory installed on your system, it's also useful to specify the /E or /X options to make portions of the programming environment resident in EMS or XMS. For more information about these options, refer to Appendix B of the Microsoft Visual Basic Programmer's Guide.
To compile a Visual Basic program from the DOS command line and link it
with Fastgraph, use the BC and LINK commands:
BC [/O] <source_file>; LINK [/E] <object_file>,,NUL,FGVBDOS;
The /O option on the BC command is recommended because it creates EXE files that do not require the Visual Basic run-time module. The /E linker option is not required but will produce a smaller EXE file if specified. For more information about other compilation and linking options, please refer to the Microsoft Visual Basic Programmer's Guide.
When linking Visual Basic for DOS programs that call Fastgraph's world
space or software character routines (that is, any of the routines listed in Appendix D), you may need to increase the number of segments available to the linker. Use the /SEG:n option on the LINK command to do this. The default value of n is 128 segments; usually a slightly larger value, such as 144, will be enough.
All remaining example programs in the Fastgraph User's Guide are written
in the C programming language. However, when you install Fastgraph for Visual Basic, the installation procedure copies BASIC versions of the example programs to the \FG\EXAMPLES directory. �
Chapter 1: Introduction 21
Microsoft Visual C++
Microsoft Visual C++ can create real mode and 16-bit protected mode
applications. For protected mode, it supports the Phar Lap 286|Dos-Extender (both SDK and Lite versions) and the Rational Systems DOS/16M extender. The following Fastgraph libraries are compatible with Visual C++:
FGS.LIB Real mode small model general library FGM.LIB Real mode medium model general library FGL.LIB Real mode large model general library FGMSCS.LIB Real mode small model auxiliary library FGMSCM.LIB Real mode medium model auxiliary library FGMSCL.LIB Real mode large model auxiliary library FG16.LIB 16-bit protected mode general library FG16MSC.LIB 16-bit protected mode auxiliary library FG16DPMI.LIB 16-bit DPMI-compliant DOS extender support library FG16PHAR.LIB Phar Lap 286|Dos-Extender support library
Programs are compiled and linked from the DOS command line using the CL
command. Here are example CL commands for compiling a Visual C++ program and linking it with Fastgraph. The compiler-specific auxiliary library names only need to be included when your program uses any of the Fastgraph routines listed in Appendix D. In the real mode examples, the /E linker option is not required but will produce a smaller EXE file if specified.
Real mode, small memory model: CL /AS <source_file> /link FGS.LIB [FGMSCS.LIB] [/E]
Real mode, medium memory model: CL /AM <source_file> /link FGM.LIB [FGMSCM.LIB] [/E]
Real mode, large memory model: CL /AL <source_file> /link FGL.LIB [FGMSCL.LIB] [/E]
16-bit protected mode, Phar Lap 286 SDK or Lite extender: CL /AL /Lp <source_file> /link FG16.LIB FG16PHAR.LIB [FG16MSC.LIB]
To create Visual C++ protected mode programs using the Rational Systems DOS/16M extender, please refer to the DOS/16M User's Guide.
For more information about memory models or other compilation and linking
options, please refer to the Visual C++ Command-Line Utilities User's Guide, Phar Lap's Microsoft C & C++ User's Guide to 286|Dos-Extender, or the DOS/16M User's Guide. � 22 Fastgraph User's Guide
Microsoft Visual C++ 32-bit Edition
As its name suggests, Microsoft Visual C++ 32-bit Edition is strictly a
32-bit protected mode compiler. It supports the Phar Lap TNT|Dos-Extender SDK and the Phar Lap TNT|Dos-Extender Lite. The following Fastgraph library is compatible with the 32-bit Edition of Visual C++:
FG32VC.LIB 32-bit PM library for Microsoft Visual C++ 32-bit Edition
FG32VC.LIB includes Fastgraph's Phar Lap support functions normally found in the FG32PHAR.LIB library.
There are two basic methods of creating 32-bit protected mode executables
with Visual C++ 32-bit Edition. The first method compiles and links the program in a single command and uses the Microsoft 32-bit linker:
CL <source_file> /link /stub:\TNT\BIN\GOTNT.EXE FG32VC.LIB
The second method compiles and links the program in separate commands and uses Phar Lap's 386|Link utility:
CL /c <source_file> 386LINK <obj_file> @MSVC32.DOS -lib FG32VC -nomap -onecase
The Phar Lap linker has problems with Fastgraph's world space routines. If your program uses any of the Fastgraph routines listed in Appendix D, you should use the Microsoft 32-bit linker.
For more information about other compilation and linking options, please
refer to Phar Lap's C/C++ User's Guide to TNT Dos-Extender. �
Chapter 1: Introduction 23
Power C
Power C is an inexpensive real mode command-line compiler. The following
Fastgraph libraries are compatible with Power C:
FGS.MIX Small model general library FGM.MIX Medium model general library FGL.MIX Large model general library FGPCS.MIX Small model auxiliary library FGPCM.MIX Medium model auxiliary library FGPCL.MIX Large model auxiliary library
To compile a Power C program from the DOS command line and link it with
Fastgraph, use the PC and PCL commands. Here are example command sequences for compiling a Power C program and linking it with Fastgraph. The compiler- specific auxiliary library names only need to be included when your program uses any of the Fastgraph routines listed in Appendix D.
Small memory model: PC /ms <source_file> PCL <mix_file> ;FGS [;FGPCS]
Medium memory model: PC /mm <source_file> PCL <mix_file> ;FGM [;FGPCM]
Large memory model: PC /ml <source_file> PCL <mix_file> ;FGL [;FGPCL]
For more information about memory models or other compilation and linking options, please refer to the Power C manual, published by Mix Software, Inc. � 24 Fastgraph User's Guide
Turbo C and Turbo C++
Turbo C and Turbo C++ can create real mode and 16-bit protected mode
applications. For protected mode, only the Rational Systems DOS/16M extender is supported. You can compile and link programs directly from the DOS command line or from the Turbo C/C++ integrated development environment (IDE). The following Fastgraph libraries are compatible with Turbo C/C++:
FGS.LIB Real mode small model general library FGM.LIB Real mode medium model general library FGL.LIB Real mode large model general library FGTCS.LIB Real mode small model auxiliary library FGTCM.LIB Real mode medium model auxiliary library FGTCL.LIB Real mode large model auxiliary library FG16.LIB 16-bit protected mode general library FG16BC.LIB 16-bit protected mode auxiliary library FG16DPMI.LIB 16-bit DPMI-compliant DOS extender support library
To build Fastgraph applications in the Turbo C/C++ IDE, the compiler
options must match one of Fastgraph's available memory models (small, medium, or large). You also must create a project file that includes the name of each C, CPP, and LIB file required by your application (refer to your Turbo C or Turbo C++ manuals for information about project files). Project files are only needed when using the IDE.
You can also compile and link programs from the DOS command line using
the TCC command. Here are example TCC commands for compiling a Turbo C or Turbo C++ program and linking it with Fastgraph. The compiler-specific auxiliary library names only need to be included when your program uses any of the Fastgraph routines listed in Appendix D.
Real mode, small memory model: TCC -ms <source_file> FGS.LIB [FGTCS.LIB]
Real mode, medium memory model: TCC -mm <source_file> FGM.LIB [FGTCM.LIB]
Real mode, large memory model: TCC -ml <source_file> FGL.LIB [FGTCL.LIB]
To create Turbo C/C++ protected mode programs using the Rational Systems DOS/16M extender, please refer to the DOS/16M User's Guide.
For more information about memory models or other compilation and linking
options, please refer to the Turbo C User's Guide, Turbo C Reference Guide, or the DOS/16M User's Guide. �
Chapter 1: Introduction 25
Turbo Pascal
Turbo Pascal can build real mode programs directly from the DOS command
line or from the Turbo Pascal integrated development environment (IDE).
To build Fastgraph applications in the Turbo Pascal IDE, just start the
IDE as you would for any other Pascal program, making sure the Fastgraph unit files reside in one of the directories listed in the IDE's "Unit Directories" option.
You also can compile Turbo Pascal programs from the DOS command line
using the TPC command, as shown here:
TPC <source_file>
For more information about other compilation and linking options, please refer to the Turbo Pascal User's Guide.
All remaining example programs in the Fastgraph User's Guide are written
in the C programming language. However, when you install Fastgraph for Turbo Pascal, the installation procedure copies Pascal versions of the example programs to the \FG\EXAMPLES directory. � 26 Fastgraph User's Guide
WATCOM C/C++ WATCOM C32 for DOS
WATCOM C/C++ and WATCOM C32 for DOS both are 16-bit real mode and 32-bit
protected mode compilers (for simplicity, we'll use the term WATCOM C/C++ to refer to either compiler). Both compilers support the DOS/4G, DOS/4GW, and DOS/4GW Professional DOS extenders from Rational Systems (DOS/4GW is supplied with both compilers), as well as the Phar Lap TNT|Dos-Extender SDK. The following Fastgraph libraries are compatible with the WATCOM compilers:
FGS.LIB Real mode small model general library FGM.LIB Real mode medium model general library FGL.LIB Real mode large model general library FGWCS.LIB Real mode small model auxiliary library FGWCM.LIB Real mode medium model auxiliary library FGWCL.LIB Real mode large model auxiliary library FG32.LIB 32-bit protected mode general library FG32WC.LIB 32-bit protected mode auxiliary library FG32DPMI.LIB 32-bit DPMI-compliant DOS extender support library FG32PHAR.LIB Phar Lap TNT|Dos-Extender support library
Programs are compiled and linked from the DOS command line using the WCL
or WCL386 commands. Here are example commands for compiling a WATCOM C/C++ program and linking it with Fastgraph. The compiler-specific auxiliary libraries (FGWCS, FGWCM, FGWCL, and FG32WC) only need to be included when your program uses any of the Fastgraph routines listed in Appendix D.
Real mode, small memory model:
WCL /ms <source_file> FGS.LIB [FGWCS.LIB]
Real mode, medium memory model:
WCL /mm <source_file> FGM.LIB [FGWCM.LIB]
Real mode, large memory model:
WCL /ml <source_file> FGL.LIB [FGWCL.LIB]
32-bit protected mode, any Rational Systems DOS/4G extender:
WCL386 /l=dos4g <source_file> FG32.LIB FG32DPMI.LIB [FG32WC.LIB]
32-bit protected mode, Phar Lap TNT|Dos-Extender:
WCL386 /l=pharlap <source_file> FG32.LIB FG32PHAR.LIB [FG32WC.LIB]
For more information about other compilation and linking options, please
refer to the WATCOM C/C++ User's Guide, Phar Lap's C/C++ User's Guide to TNT Dos-Extender, or the DOS/4G User's Manual. �
Chapter 1: Introduction 27
Zortech C++
Zortech C++ creates real mode applications. The following Fastgraph
libraries are compatible with Zortech C++:
FGS.LIB Real mode small model general library FGM.LIB Real mode medium model general library FGL.LIB Real mode large model general library FGZCS.LIB Real mode small model auxiliary library FGZCM.LIB Real mode medium model auxiliary library FGZCL.LIB Real mode large model auxiliary library
Programs are compiled and linked from the DOS command line using the ZTC
command. Here are example ZTC commands for compiling a Zortech C++ program and linking it with Fastgraph. The compiler-specific auxiliary library names only need to be included when your program uses any of the Fastgraph routines listed in Appendix D.
Small memory model: ZTC -ms <source_file> FGS.LIB [FGZCS.LIB]
Medium memory model: ZTC -mm <source_file> FGM.LIB [FGZCM.LIB]
Large memory model: ZTC -ml <source_file> FGL.LIB [FGZCL.LIB]
For more information about memory models or other compilation and linking options, please refer to the manuals supplied with your Zortech C++ compiler. � 28 Fastgraph User's Guide
Fastgraph/Light Video Driver
As mentioned earlier, running any program created with Fastgraph/Light
requires an external program called the Fastgraph/Light Video Driver. The video driver is a terminate and stay resident program (TSR) that provides an interface between your program and Fastgraph.
To load the video driver, enter the command FGDRIVER at the DOS command
prompt (assuming FGDRIVER.EXE is in the current directory, or the \FG directory is in your DOS path specification). The driver will display a message indicating whether or not it loaded successfully. After you load the driver, just run a program created with Fastgraph/Light as you would any other program. If you try running a program that uses Fastgraph/Light without first loading the video driver, the message "Fastgraph/Light video driver not installed" will appear.
You don't need to load the driver before running each program, just once
per system boot (in fact, the driver will display an "already loaded" message if you try to load it more than once). If you want to unload the video driver, just enter FGDRIVER /U at the DOS command prompt. The unload operation will work completely only if the video driver was the last TSR loaded. If it wasn't the last TSR, the driver will still unload, but the memory it uses will not be released back to DOS.
Chapter 2
PC and PS/2 Video Modes � 30 Fastgraph User's Guide
Overview
In the PC and PS/2 worlds, video modes determine the way information
appears on the computer's display screen. The available video modes have different resolutions, different character or pixel attributes, different video memory structures, and other inherent hardware differences. However, you do not need an in-depth knowledge of these video internals, because Fastgraph handles the necessary details.
The PC and PS/2 video modes may be separated into two major classes: text
modes and graphics modes. In text modes, the display screen is divided into character cells. By default, there are 25 rows and either 40 or 80 columns of cells, and in each cell we can store any of the 256 characters in the IBM PC character set. Each character has an associated attribute that determines such things as its foreground color, its background color, and whether or not the character blinks. In graphics modes, the display screen is divided into picture elements, or pixels. Depending on the video mode, the number of pixel rows ranges between 200 and 768, while the number of columns ranges between 320 and 1,024. Each pixel has an associated value that determines the color of the pixel. The number of character cells or pixels available is called the resolution of the screen.
The display adapter (graphics card) and the video display (monitor)
connected to it determine the video modes available on a given system. The following table summarizes the characteristics of the PC and PS/2 video modes that Fastgraph supports.
Mode No. of Supported Supported No. Type Resolution Colors Adapters Displays
0 T 40x25 16/8 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 1 T 40x25 16/8 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 2 T 80x25 16/8 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 3 T 80x25 16/8 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 4 G 320x200 4 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 5 G 320x200 4 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 6 G 640x200 2/16 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 7 T 80x25 b/w MDA,HGC,EGA,VGA,SVGA Monochrome 9 G 320x200 16 Tandy 1000,PCjr RGB 11 G 720x348 b/w HGC Monochrome 12 G 320x200 b/w HGC Monochrome 13 G 320x200 16 EGA,VGA,SVGA RGB,ECD,VGA,SVGA 14 G 640x200 16 EGA,VGA,SVGA RGB,ECD,VGA,SVGA 15 G 640x350 b/w EGA,VGA,SVGA Mono,VGA,SVGA 16 G 640x350 16/64 EGA,VGA,SVGA ECD,VGA,SVGA 17 G 640x480 2/256K VGA,MCGA,SVGA VGA,SVGA 18 G 640x480 16/256K VGA,SVGA VGA,SVGA 19 G 320x200 256/256K VGA,MCGA,SVGA VGA,SVGA 20 G 320x200 256/256K VGA,SVGA VGA,SVGA 21 G 320x400 256/256K VGA,SVGA VGA,SVGA 22 G 320x240 256/256K VGA,SVGA VGA,SVGA 23 G 320x480 256/256K VGA,SVGA VGA,SVGA 24 G 640x400 256/256K SVGA SVGA 25 G 640x480 256/256K SVGA SVGA 26 G 800x600 256/256K SVGA SVGA � Chapter 2: PC and PS/2 Video Modes 31
27 G 1024x768 256/256K SVGA SVGA 28 G 800x600 16/256K SVGA SVGA 29 G 1024x768 16/256K SVGA SVGA
Some notes about the format and abbreviations used in this table are in
order. In the "type" column, "T" means a text mode and "G" means a graphics mode. A single value in the "number of colors" column refers to the number of colors available in that video mode. In text modes, a pair of numbers such as 16/8 means each displayed character can have one of 16 foreground colors and one of 8 background colors. In graphics modes, a pair of numbers such as 16/64 means 16 colors can be displayed simultaneously from a collection, or palette, of 64. The "b/w" listed in the monochrome modes stands for "black and white". Characters or pixels in these video modes do not really have associated colors but instead have display attributes such as blinking or different intensities.
The meanings of the abbreviations in the "supported adapters" and
"supported displays" columns are:
CGA Color Graphics Adapter ECD Enhanced Color Display EGA Enhanced Graphics Adapter HGC Hercules Graphics Card MCGA Multi-Color Graphics Array MDA Monochrome Display Adapter RGB Red-Green-Blue Color Display SVGA SuperVGA VGA Video Graphics Array
The use of the term "VGA" in the "supported display" column refers to any analog display, such as a VGA or Multisync monitor. The term "SVGA" refers explicitly to a SuperVGA monitor or adapter.
The IBM PS/2 systems do not have a traditional adapter and display
combination. Instead, the video hardware in these systems is called the video subsystem. The Model 25 and Model 30 have an MCGA-based video subsystem, while other models have a VGA-based video subsystem. From Fastgraph's perspective, the PS/2 video subsystem is no different from an ordinary VGA card and monitor.
This rest of this chapter will provide an overview of the most important
features and restrictions of each video mode. The first section will discuss the text modes, while the following section will discuss the graphics modes.
Text Modes
There are five text video modes in the IBM PC and PS/2 family. Four of
these modes (0, 1, 2, and 3) are designed for color displays, while the remaining mode (7) is designed for monochrome displays. All text modes were introduced with the original IBM PC.
In text modes, the screen is divided into character cells. There are two
bytes of video memory associated with each character cell -- one byte for the character's ASCII value, and another for the character's display attribute. The amount of video memory required to store one screen of information (called a video page) is thus � 32 Fastgraph User's Guide
number_of_columns x number_of_rows x 2
All text modes use 25 rows, so for the 40-column modes (0 and 1) the size of a video page is 2,000 bytes, and for the 80-column modes (2, 3, and 7) the size of a video page is 4,000 bytes.
Mode No. of Supported Supported No. Type Resolution Colors Adapters Displays
0 T 40x25 16/8 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 1 T 40x25 16/8 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 2 T 80x25 16/8 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 3 T 80x25 16/8 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 7 T 80x25 b/w MDA,HGC,EGA,VGA,SVGA Monochrome
The remainder of this section will describe the text video modes in more
detail.
Mode 0
Mode 0 is a 40-column by 25-row color text mode. It is often called a
colorless mode since it was designed to be used with composite or television monitors (as opposed to RGB monitors). When used with these types of monitors, the available 16 "colors" appear as distinct shades of gray. When used with an RGB monitor, mode 0 is identical in all respects to mode 1. The use of composite or television monitors as PC video displays has virtually disappeared today. As a result, mode 0 is used infrequently.
Mode 1
Mode 1 is a 40-column by 25-row color text mode. It is supported across
all video adapter and color display combinations in the PC and PS/2 families. Characters displayed in mode 1 have an associated display attribute that defines the character's foreground color, its background color, and whether or not it blinks. Sixteen foreground colors and eight background colors are available.
Mode 2
Mode 2 is an 80-column by 25-row color text mode. Like mode 0, it is
often called a colorless mode since it was designed to be used with composite or television monitors (as opposed to RGB monitors). When used with these types of monitors, the available 16 "colors" appear as distinct shades of gray. When used with an RGB monitor, mode 2 is identical in all respects to mode 3. The use of composite or television monitors as PC video displays has virtually disappeared today. As a result, mode 2 is used infrequently.
Mode 3
Mode 3 is an 80-column by 25-row color text mode. It is the default video
mode for systems that use any type of color display. This mode is supported across all video adapter and color display combinations in the PC and PS/2 families. Characters displayed in mode 3 have an associated display attribute that defines the character's foreground color, its background color, and �
Chapter 2: PC and PS/2 Video Modes 33
whether or not it blinks. Sixteen foreground colors and eight background
colors are available.
Mode 7
Mode 7 is the 80-column by 25-row monochrome text mode. It is the default
video mode for systems that use a monochrome display. To use this mode, you must have a Monochrome Display Adapter (MDA), Hercules Graphics Card (HGC), or an Enhanced Graphics Adapter (EGA) connected to a monochrome display. Most VGA and SVGA display adapters also provide an emulation mode that allows you to use mode 7 with analog displays. Characters displayed in mode 7 have an associated display attribute that defines whether the character is invisible, normal, bold, underlined, reversed, blinking, or a combination of these.
Graphics Modes
There are 13 standard graphics video modes available in the IBM PC and
PS/2 family. Fastgraph provides support for 11 of the 13 modes (modes 8 and 10, specific to the PCjr and Tandy 1000 systems, are not supported). In addition to these 13 modes, Fastgraph supports six SuperVGA graphics modes (modes 24 to 29), four extended VGA modes (modes 20 to 23), and two video modes for the Hercules Graphics Card (modes 11 and 12). The following sections discuss these graphics modes in more detail. The discussions include an overview of video memory organization in each mode, but you don't need a knowledge of this subject to use Fastgraph.
CGA Graphics Modes
Modes 4, 5, and 6 are designed to be used with the Color Graphics Adapter
(CGA) and for this reason are called the native CGA modes. They were the only graphics modes available with the original IBM PC. Newer graphics adapters (EGA, VGA, MCGA, and SVGA) can emulate the CGA, which means that the CGA graphics modes are available on any PC or PS/2 system equipped with a color display.
Mode No. of Supported Supported No. Type Resolution Colors Adapters Displays
4 G 320x200 4 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 5 G 320x200 4 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA 6 G 640x200 2/16 CGA,EGA,VGA,MCGA,SVGA RGB,ECD,VGA,SVGA
Mode 4
Mode 4 is a CGA graphics mode with a resolution of 320 horizontal pixels
by 200 vertical pixels. Each pixel can assume one of four colors (the available colors are determined by which one of six palettes has been selected), so each pixel requires two bits of video memory. This means each byte of video memory represents four pixels. � 34 Fastgraph User's Guide
Mode 5
Mode 5 is the colorless analog of mode 4. It was designed to be used with
composite or television monitors (as opposed to RGB monitors). When used with these types of monitors, the four colors appear as distinct shades of gray. When used with an RGB monitor, mode 5 is essentially identical to mode 4. The use of composite or television monitors as PC video displays has virtually disappeared today. As a result, mode 5 is used infrequently.
Mode 6
Mode 6 is a CGA graphics mode with a resolution of 640 horizontal pixels
by 200 vertical pixels. Each pixel can assume two states -- on or off. The color in which the "on" pixels appear can be selected from a palette of 16 available colors. Each pixel thus requires one bit of video memory, which means each byte of video memory represents eight pixels.
Tandy 1000 and PCjr Graphics Modes
Modes 8, 9, and 10 are only available on the PCjr and Tandy 1000 series
computers (these systems also support modes 4, 5, and 6). Modes 8 and 10 are not widely used, and for this reason Fastgraph does not support them.
Mode No. of Supported Supported No. Type Resolution Colors Adapters Displays
8 G 160x200 16 Tandy 1000,PCjr RGB 9 G 320x200 16 Tandy 1000,PCjr RGB 10 G 640x200 4 Tandy 1000,PCjr RGB
Mode 9
Mode 9 is a Tandy 1000 and PCjr graphics mode with a resolution of 320
horizontal pixels by 200 vertical pixels. Each pixel can assume one of 16 colors, so each pixel requires four bits of video memory. This means each byte of video memory represents two pixels. The Tandy 1000 and PCjr use standard random-access memory (RAM) as video memory.
Hercules Graphics Modes
Modes 11 and 12 are used with the Hercules Graphics Card (HGC) and a
monochrome display. As such, they are not true IBM video modes, but because of the popularity of the HGC, Fastgraph provides support for this adapter.
Mode No. of Supported Supported No. Type Resolution Colors Adapters Displays
11 G 720x348 b/w HGC Monochrome 12 G 320x200 b/w HGC Monochrome � Chapter 2: PC and PS/2 Video Modes 35
Mode 11
Mode 11 is a true Hercules graphics mode with a resolution of 720
horizontal pixels by 348 vertical pixels. Each pixel can assume two states -- on or off. Each pixel thus requires one bit of video memory, which means each byte of video memory represents eight pixels.
Mode 12
Mode 12 is a software-simulated Hercules graphics mode with an effective
resolution of 320 horizontal pixels by 200 vertical pixels. Its purpose is to provide a resolution that is available with all other graphics display adapters.
This mode converts all coordinates from the 320x200 space (called virtual
coordinates) into the 720x348 coordinate system (called physical coordinates). It does this by using two physical pixels for each virtual pixel and scan doubling the odd-numbered virtual rows. Finally, offsets are added to the resulting physical coordinates to center the image area on the display. This creates an image area bounded horizontally by the physical coordinates 40 and 679 and vertically by the physical coordinates 24 and 323.
EGA Graphics Modes
Modes 13 through 16 were introduced with the Enhanced Graphics Adapter
(EGA) and for this reason are called the native EGA modes. VGA and SVGA adapters also provide support for these modes, but the MCGA does not. The original IBM EGA only contained 64K bytes of video memory, but memory could be added in 64K increments to fully populate the adapter with 256K bytes of video memory. As other manufacturers developed EGA cards, they generally included 256K bytes of video memory as a standard feature.
Mode No. of Supported Supported No. Type Resolution Colors Adapters Displays
13 G 320x200 16 EGA,VGA,SVGA RGB,ECD,VGA,SVGA 14 G 640x200 16 EGA,VGA,SVGA RGB,ECD,VGA,SVGA 15 G 640x350 b/w EGA,VGA,SVGA Mono,VGA,SVGA 16 G 640x350 16/64 EGA,VGA,SVGA ECD,VGA,SVGA
Mode 13
Mode 13 is an EGA graphics mode with a resolution of 320 horizontal
pixels by 200 vertical pixels. Each pixel can assume one of 16 colors, so each pixel requires four bits of video memory. In this mode, video memory is organized as four bit planes. Each video memory address actually references four bytes, one in each plane. Put another way, each video memory byte references eight pixels, stored one bit per plane.
Mode 14
Mode 14 is an EGA graphics mode with a resolution of 640 horizontal
pixels by 200 vertical pixels. Each pixel can assume one of 16 colors, so each pixel requires four bits of video memory. In this mode, video memory is organized as four bit planes. Each video memory address actually references � 36 Fastgraph User's Guide
four bytes, one in each plane. Put another way, each video memory byte
references eight pixels, stored one bit per plane.
Mode 15
Mode 15 is an EGA monochrome graphics mode with a resolution of 640
horizontal pixels by 350 vertical pixels. Each pixel can assume one of 4 display attributes, so each pixel requires two bits of video memory. In this mode, video memory is organized as four bit planes, two of which are disabled. Each video memory address actually references two bytes, one in each enabled plane. Put another way, each video memory byte references eight pixels, stored one bit per plane.
Mode 16
Mode 16 is an EGA graphics mode with a resolution of 640 horizontal
pixels by 350 vertical pixels.1 Each pixel can assume one of 16 colors (the 16 colors can be selected from a palette of 64 colors), so each pixel requires four bits of video memory. In this mode, video memory is organized as four bit planes. Each video memory address actually references four bytes, one in each plane. Put another way, each video memory byte references eight pixels, stored one bit per plane.
VGA and MCGA Graphics Modes
Modes 17, 18, and 19 were introduced with the MCGA and VGA video
subsystems of the IBM PS/2 computers. Since the introduction of the PS/2, other manufacturers have developed VGA cards that can be used with the PC family. VGA and SVGA adapters support all three of these modes, but the MCGA does not support mode 18. Modes 17 and 18 are called native VGA modes.
Mode No. of Supported Supported No. Type Resolution Colors Adapters Displays
17 G 640x480 2/256K VGA,MCGA,SVGA VGA,SVGA 18 G 640x480 16/256K VGA,SVGA VGA,SVGA 19 G 320x200 256/256K VGA,MCGA,SVGA VGA,SVGA
Mode 17
Mode 17 is a VGA and MCGA graphics mode with a resolution of 640
horizontal pixels by 480 vertical pixels. Each pixel can assume two states -- on or off. The color in which the "on" and "off" pixels appear can be selected from a palette of 262,144 available colors. Each pixel thus requires one bit of video memory, which means each byte of video memory represents eight pixels. On VGA and SVGA systems, video memory is organized as four bit planes, and mode 17 is implemented by enabling one of these planes.
____________________
(1) In mode 16, the video page size actually is 640 by 400 pixels, though
the screen resolution is 640 by 350. The final 50 pixel rows (350 to 399) on each video page are not displayed but are available for off-screen storage. �
Chapter 2: PC and PS/2 Video Modes 37
Mode 18
Mode 18 is a native VGA graphics mode with a resolution of 640 horizontal
pixels by 480 vertical pixels. Each pixel can assume one of 16 colors (the 16 colors can be selected from a palette of 262,144 colors), so each pixel requires four bits of video memory. In this mode, video memory is organized as four bit planes. Each video memory address actually references four bytes, one in each plane. Put another way, each video memory byte references eight pixels, stored one bit per plane.
Mode 19
Mode 19 is a VGA and MCGA graphics mode with a resolution of 320
horizontal pixels by 200 vertical pixels. Each pixel can assume one of 256 colors (the 256 colors can be selected from a palette of 262,144 colors), so each pixel requires eight bits of video memory. This means each byte of video memory represents one pixel.
Extended VGA (XVGA) Graphics Modes
Modes 20 through 23 are the extended VGA or XVGA graphics modes. Although
these video modes are not standard VGA modes, they will work on any register- compatible VGA or SVGA adapter. These video modes are especially popular for game development because they offer video page resizing, whereas the standard 256-color mode does not. Mode 20 is the XVGA version of mode 19, while mode 21 uses scan doubling to achieve a 400-line display. Mode 22 is the so-called "mode X" and is appealing because it has a 1:1 aspect ratio. Mode 23 is identical to mode 22, but it uses scan doubling to achieve a 480-line display.
Mode No. of Supported Supported No. Type Resolution Colors Adapters Displays
20 G 320x200 256/256K VGA,SVGA VGA,SVGA 21 G 320x400 256/256K VGA,SVGA VGA,SVGA 22 G 320x240 256/256K VGA,SVGA VGA,SVGA 23 G 320x480 256/256K VGA,SVGA VGA,SVGA
Mode 20
Mode 20 is an XVGA graphics mode with a resolution of 320 horizontal
pixels by 200 vertical pixels. Each pixel can assume one of 256 colors (the 256 colors can be selected from a palette of 262,144 colors), so each pixel requires eight bits of video memory. This means each byte of video memory represents one pixel. This mode offers the same resolution and number of colors as mode 19, but its video memory is organized as a series of four bit planes. Every fourth pixel is stored in the same plane (that is, a pixel whose horizontal coordinate is x resides in plane x modulo 4).
Mode 21
Mode 21 is an XVGA color graphics mode with a resolution of 320
horizontal pixels by 400 vertical pixels. Except for the resolution, its video memory organization is identical to mode 20. � 38 Fastgraph User's Guide
Mode 22
Mode 22 is an XVGA color graphics mode with a resolution of 320
horizontal pixels by 240 vertical pixels. This is the so-called "mode X" made famous by Michael Abrash in Dr. Dobb's Journal. Except for the resolution, its video memory organization is identical to mode 20.
Mode 23
Mode 23 is an XVGA color graphics mode with a resolution of 320
horizontal pixels by 480 vertical pixels. Except for the resolution, its video memory organization is identical to mode 20.
SuperVGA (SVGA) Graphics Modes
Modes 24 through 29 are the SuperVGA or SVGA graphics modes. If you've
done any work with SVGA cards, you probably know that different manufacturers use different numbers to reference the SVGA video modes. For example, the 640x480 256-color graphics mode number is 62 hex on ATI cards, 5D hex on Trident cards, and 2E hex on Tseng Labs cards. Fastgraph's SVGA kernel, described in detail in the next chapter, handles the details of mapping Fastgraph's general SVGA video mode numbers (24 to 29) to the chipset-specific video mode numbers of the supported SVGA cards.
Mode No. of Supported Supported No. Type Resolution Colors Adapters Displays
24 G 640x400 256/256K SVGA SVGA 25 G 640x480 256/256K SVGA SVGA 26 G 800x600 256/256K SVGA SVGA 27 G 1024x768 256/256K SVGA SVGA 28 G 800x600 16/256K SVGA SVGA 29 G 1024x768 16/256K SVGA SVGA
Mode 24
Mode 24 is a SuperVGA graphics mode with a resolution of 640 horizontal
pixels by 400 vertical pixels. Each pixel can assume one of 256 colors (the 256 colors can be selected from a palette of 262,144 colors), so each pixel requires eight bits of video memory. This means each byte of video memory represents one pixel, so at least 256K of video memory is needed for this mode. Note that a fair number of SVGA cards do not support this video mode.
Mode 25
Mode 25 is a SuperVGA graphics mode with a resolution of 640 horizontal
pixels by 480 vertical pixels. It is probably the most popular SVGA graphics mode. Each pixel can assume one of 256 colors (the 256 colors can be selected from a palette of 262,144 colors), so each pixel requires eight bits of video memory. This means each byte of video memory represents one pixel, so at least 512K of video memory is needed for this mode. �
Chapter 2: PC and PS/2 Video Modes 39
Mode 26
Mode 26 is a SuperVGA graphics mode with a resolution of 800 horizontal
pixels by 600 vertical pixels. Each pixel can assume one of 256 colors (the 256 colors can be selected from a palette of 262,144 colors), so each pixel requires eight bits of video memory. This means each byte of video memory represents one pixel, so at least 512K of video memory is needed for this mode.
Mode 27
Mode 27 is a SuperVGA graphics mode with a resolution of 1024 horizontal
pixels by 768 vertical pixels. Each pixel can assume one of 256 colors (the 256 colors can be selected from a palette of 262,144 colors), so each pixel requires eight bits of video memory. This means each byte of video memory represents one pixel, so at least 768K of video memory is needed for this mode.
Mode 28
Mode 28 is a SuperVGA graphics mode with a resolution of 800 horizontal
pixels by 600 vertical pixels. Each pixel can assume one of 16 colors (the 16 colors can be selected from a palette of 262,144 colors), so each pixel requires four bits of video memory. In this mode, video memory is organized as four bit planes. Each video memory address actually references four bytes, one in each plane. Put another way, each video memory byte references eight pixels, stored one bit per plane. At least 256K of video memory is needed to use this mode.
Mode 29
Mode 29 is a SuperVGA graphics mode with a resolution of 1024 horizontal
pixels by 768 vertical pixels. Each pixel can assume one of 16 colors (the 16 colors can be selected from a palette of 262,144 colors), so each pixel requires four bits of video memory. In this mode, video memory is organized as four bit planes. Each video memory address actually references four bytes, one in each plane. Put another way, each video memory byte references eight pixels, stored one bit per plane. At least 512K of video memory is needed to use this mode. � 40 Fastgraph User's Guide
Chapter 3
Initializing the Video Environment � 42 Fastgraph User's Guide
Overview
Before Fastgraph can perform any text or graphics video operations, you
must select a video mode in which your program will run. An important part of this selection depends on whether your program will run in a text mode, a graphics mode, or both. The first two sections in this chapter discuss the necessary video initialization for standard text and graphics modes, while the last section addresses the additional setup needed for SuperVGA (SVGA) graphics modes.
Establishing a Text Mode
When you write a program that only uses text modes, you must determine if
the program will run on monochrome systems, color systems, or both. In general, there is no reason to exclude one type of system, because the additional programming required to support both is rather trivial.
The Fastgraph routine fg_setmode establishes a video mode and initializes
Fastgraph's internal parameters for that mode. This routine has a single integer argument whose value is a video mode number between 0 and 29. Its value can also be -1, which tells Fastgraph to use the current video mode. Specifying an fg_setmode argument of -1 is often useful in programs that only use text video modes.
When you establish a text video mode, the ROM BIOS text cursor is made
visible, and this is often undesirable. The Fastgraph routine fg_cursor controls the visibility of the text cursor. The fg_cursor routine has a single integer argument that specifies the cursor visibility. If its value is 0, the cursor is made invisible; if its value is 1, the cursor is made visible.
At this point, an example may help clarify things. We'll start with a
variation of Kernighan and Ritchie's famous "Hello, world" program that shows how to initialize Fastgraph for the 80-column color text mode (mode 3) and turn off the text mode cursor. It uses two Fastgraph routines that we have not yet discussed, fg_setcolor and fg_text. For now, it should suffice to know that fg_setcolor(15) makes subsequent text appear in white, and fg_text displays the characters passed to it.
Example 3-1.
#include <fastgraf.h> void main(void);
void main() { fg_initpm(); fg_setmode(3); fg_cursor(0);
fg_setcolor(15); fg_text("Hello, world.",13); } � Chapter 3: Initializing the Video Environment 43
If you run example 3-1, notice the text displayed by the program appears
in the upper left corner of the screen. On the line below this, the DOS prompt appears, waiting for your next DOS command. Furthermore, if your system uses the ANSI.SYS driver to set screen attributes (such as with Norton's SA program), you should also notice only the DOS prompt appears in the colors defined by the screen attributes -- the rest of the screen is blank.
A more graceful return to DOS is needed. In example 3-2, we'll use the
Fastgraph routine fg_reset. This routine erases the screen, and if the ANSI.SYS driver is loaded, fg_reset also restores any previously set screen attributes. We've also included a call to the Fastgraph routine fg_waitkey to wait for a keystroke before exiting. If we didn't do this, we would never see the program's output.
Example 3-2.
#include <fastgraf.h> void main(void);
void main() { fg_initpm(); fg_setmode(3); fg_cursor(0);
fg_setcolor(15); fg_text("Hello, world.",13); fg_waitkey();
fg_reset(); }
Since examples 3-1 and 3-2 specifically use video mode 3, they would not
work on a monochrome system. Ideally, we'd like to use fg_setmode(3) for color systems and fg_setmode(7) for monochrome systems. To do this, we need a way to determine whether the program is being run on a color system or on a monochrome system. The next example illustrates an easy way to do this.
Example 3-3 uses the Fastgraph routine fg_testmode to determine if the
user's system will support the video mode number specified as its first argument (the second argument is the number of video pages required, which will be 1 for all examples in this section). The fg_testmode routine returns a value of 1 (as its function value) if the requested video mode can be used, and it returns 0 if not. The program first sees if an 80-column color text mode is available (mode 3), and if so, it selects that mode. If the color mode is not available, it checks if the monochrome text mode is available (mode 7), and if so, it chooses the monochrome mode. If neither mode is available, then the program assumes the user's system has a 40-column display, issues a message stating the program requires an 80-column display, and then exits.
Example 3-3.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> �
44 Fastgraph User's Guide
void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode();
if (fg_testmode(3,1)) fg_setmode(3); else if (fg_testmode(7,1)) fg_setmode(7); else { printf("This program requires\n"); printf("an 80-column display.\n"); exit(1); } fg_cursor(0);
fg_setcolor(15); fg_text("Hello, world.",13); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Example 3-3 also illustrates another useful procedure. It is recommended,
especially in graphics modes, to restore the original video mode and screen attributes before a program returns to DOS. We've already seen how the fg_reset routine restores the screen attributes, but how do we restore the original video mode? The Fastgraph routine fg_getmode returns the current video mode as its function value. If we call fg_getmode before calling fg_setmode, we can save the fg_getmode return value and pass it to fg_setmode just before the program exits.
You also can use another Fastgraph routine, fg_bestmode, to determine if
a video mode with a specific resolution is available on the user's system. The fg_bestmode routine requires three integer arguments: a horizontal resolution, a vertical resolution, and the number of video pages required. As its function value, fg_bestmode returns the video mode number that offers the most capabilities for the resolution and number of pages requested. It returns a value of -1 if no available video mode offers the requested criteria.
For example, if we require an 80x25 text mode, we can use the function
call fg_bestmode(80,25,1) to pick the "best" video mode available that offers this capability. In text modes, the term best means to give preference to a color text mode over a monochrome text mode. Example 3-4 performs the same function as example 3-3, but it uses fg_bestmode rather than fg_testmode.
Example 3-4.
#include <fastgraf.h> #include <stdio.h> � Chapter 3: Initializing the Video Environment 45
#include <stdlib.h> void main(void);
void main() { int old_mode; int new_mode;
fg_initpm(); old_mode = fg_getmode(); new_mode = fg_bestmode(80,25,1);
if (new_mode < 0) { printf("This program requires\n"); printf("an 80-column display.\n"); exit(1); }
fg_setmode(new_mode); fg_cursor(0);
fg_setcolor(15); fg_text("Hello, world.",13); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
43-line and 50-line Text Modes
When using an 80-column text mode on a system equipped with an EGA, VGA,
MCGA, or SVGA video display and adapter, you can extend the screen size from 25 lines to 43 or 50 lines. While all systems offer 25-line text modes, EGA systems also offer 43-line modes, MCGA systems also offer 50-line modes, and VGA and SVGA systems offer both 43-line and 50-line modes. The 43-line mode is not available on EGA systems equipped with an RGB display. If you extend the screen size to 43 or 50 lines, the physical character size is reduced proportionally so all lines appear on the screen.
The fg_setlines routine defines the number of text rows per screen. It
has a single integer argument whose value must be 25, 43, or 50. If you pass any other value to fg_setlines, or pass a value not supported by the host system's video configuration, fg_setlines does nothing. In addition, calling fg_setlines makes the text cursor visible. Another Fastgraph routine, fg_getlines, returns as its function value the number of text rows currently in effect. You also can use fg_getlines in graphics video modes.
Example 3-5 illustrates the use of the fg_setlines and fg_getlines
routines. The program first establishes the 80-column color text mode (this sets the screen size to its 25-line default) and makes the text cursor invisible. It then displays the words "first line" in the upper left corner of the screen. Next, the program checks if an EGA with enhanced display is available, and if so, changes the screen to 43 lines (video mode 16 is only � 46 Fastgraph User's Guide
available on EGA systems equipped with an enhanced display). Next, the program
checks if a VGA, MCGA, or SVGA is available, and if so changes the screen to
50 lines (video mode 17 is only available on these systems). Finally, the
program restores the original video mode, restores the number of lines per
screen to its original setting, and restores the original screen attributes
before exiting.
Example 3-5.
#include <fastgraf.h> void main(void);
void main() { int lines; int old_lines; int old_mode;
fg_initpm(); old_lines = fg_getlines(); old_mode = fg_getmode(); fg_setmode(3); fg_cursor(0);
fg_setcolor(15); fg_text("first line",10); fg_waitkey();
if (fg_testmode(16,0)) { fg_setlines(43); fg_cursor(0); fg_waitkey(); }
if (fg_testmode(17,0)) { fg_setlines(50); fg_cursor(0); fg_waitkey(); }
fg_setmode(old_mode); fg_setlines(old_lines); fg_reset(); }
Establishing a Graphics Mode
The steps for establishing a graphics mode are similar to establishing a
text mode. However, there are more restrictions since some systems may not support all the graphics video modes. For example, a program could not run in mode 13 on a CGA system, nor could a program run in mode 9 on anything except a Tandy 1000 or PCjr system. �
Chapter 3: Initializing the Video Environment 47
For graphics programs, it may suffice to write a program to run in a
specific video mode, but it is often more desirable to write a program that will run in any of several video modes. This is especially true for commercial products, since they should ideally run on as many different video configurations as possible.
Fastgraph includes a routine named fg_automode that determines the
graphics video mode that offers the most functionality for the user's video hardware configuration. For example, the Tandy 1000 series computers support all three CGA modes (4, 5, and 6) and the 320x200 16-color Tandy 1000 mode (9). Of these modes, mode 9 offers the most features from a graphics standpoint, so fg_automode will return a value of 9 when run on a Tandy 1000 computer. The following table summarizes the video mode numbers returned by fg_automode for given adapter-display combinations. To maintain compatibility with earlier versions of Fastgraph, fg_automode does not consider the extended VGA graphics modes (modes 20 to 23) or SVGA graphics modes (modes 24 to 29) when selecting a video mode.
display adapter mono RGB ECD VGA
MDA 7 0 7 7 HGC 11 0 0 11 CGA 0 4 0 0 EGA 15 13 16 0 VGA 17 17 17 18 MCGA 17 17 17 19 Tandy 7 9 0 0 PCjr 7 9 0 0
Example 3-6 shows how to use fg_automode to determine the "best" graphics
mode for the user's video hardware. In graphics modes, the term best means the highest resolution, followed by the number of available colors. The program displays a message that includes the selected video mode number.
Example 3-6.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int old_mode; int new_mode; char string[4];
fg_initpm(); old_mode = fg_getmode(); new_mode = fg_automode(); fg_setmode(new_mode);
fg_setcolor(15); fg_text("I'm running in mode ",20); �
48 Fastgraph User's Guide
sprintf(string,"%d.",new_mode); fg_text(string,3); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
For simple programs such as example 3-6, different screen resolutions may
not be an issue. However, in more complex graphics programs it is often desirable to write a program for a fixed screen resolution. A common practice is to develop graphics programs to run in modes 4 (for CGA), 9 (Tandy 1000 or PCjr), 12 (Hercules), 13 (EGA, VGA, or SVGA), and 19 or 20 (MCGA, VGA, or SVGA). The reason for selecting these five modes is they all use the same 320x200 resolution and will run on any IBM PC or PS/2 with graphics capabilities.
Example 3-7 performs the same function as example 3-6, but it uses
fg_bestmode instead of fg_automode to restrict the program to 320x200 graphics modes. For this resolution, the fg_bestmode routine will first check the availability of mode 20, followed by modes 19, 13, 9, 4, and 12. If fg_bestmode determines no 320x200 graphics mode is available (indicated by a return value of -1), the program prints an informational message and exits. Otherwise it selects the video mode fg_bestmode proposes and continues.
Example 3-7.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode; int new_mode; char string[4];
fg_initpm(); old_mode = fg_getmode(); new_mode = fg_bestmode(320,200,1);
if (new_mode < 0) { printf("This program requires a 320 by 200 graphics mode.\n"); exit(1); }
fg_setmode(new_mode);
fg_setcolor(15); fg_text("I'm running in mode ",20); sprintf(string,"%d.",new_mode); fg_text(string,3); fg_waitkey(); � Chapter 3: Initializing the Video Environment 49
fg_setmode(old_mode); fg_reset(); }
If a program will run in specific video modes, you may want to consider
using the fg_testmode routine instead of fg_bestmode to check for availability of these video modes. You also may want to use fg_testmode to change the video mode precedence used by fg_bestmode. For example, mode 13 (EGA) is faster than mode 19 (MCGA), so you may want to consider giving EGA precedence over MCGA, especially if your program does not use more than 16 colors.
Example 3-8 is similar to example 3-7, but it will only run in the
320x200 EGA, MCGA, and CGA graphics modes (video modes 13, 19, and 4, respectively). The program uses fg_testmode to select its video mode. Note the order of calls to fg_testmode gives EGA precedence over MCGA, and MCGA precedence over CGA.
Example 3-8.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode; char string[4];
fg_initpm(); old_mode = fg_getmode();
if (fg_testmode(13,1)) fg_setmode(13); else if (fg_testmode(19,1)) fg_setmode(19); else if (fg_testmode(4,1)) fg_setmode(4); else { printf("This program requires an EGA, MCGA, or CGA.\n"); exit(1); }
fg_setcolor(15); fg_text("I'm running in mode ",20); sprintf(string,"%d.",getmode()); fg_text(string,3); fg_waitkey();
fg_setmode(old_mode); fg_reset(); } �
50 Fastgraph User's Guide
SuperVGA Graphics Modes
Unlike previous generations of graphics cards, there was no video
standard in place when different companies began developing SVGA cards. As a result, they implemented enhanced SVGA features according to their own specifications based upon different video controller chips. Each such implementation is called a chipset. While each chipset generally offers the same video memory organization and common screen resolutions, the SVGA- specific features such as mode initialization, bank switching, and setting the display start address differ radically between chipsets. In other words, code written for one specific SVGA chipset will not run on another chipset, even at the same resolution. This is why many software vendors provide different SVGA drivers for their products.
Fastgraph's integrated SVGA kernel makes these obscure differences
between SVGA chipsets transparent, without the need for external drivers. This means, for instance, if you write an application for the 1024 by 768 256-color SVGA graphics mode, it will run without changes on any supported SVGA chipset which offers that resolution. The SVGA kernel supports the chipsets listed in the table below. A "Y" entry means the chipset supports the video mode, and an "N" means it doesn't. The last two rows of the table show the minimum amount of video memory required to support each mode and Fastgraph's corresponding video mode numbers.
-------- 256 colors -------- -- 16 colors --
SVGA chipset 640x400 640x480 800x6001024x768 800x6001024x768 Ahead "A" type Y Y Y N Y Y Ahead "B" type Y Y Y Y Y Y ARK Logic 1000/2000 series Y Y Y Y Y Y ATI 18800 Y Y Y N Y N ATI 18800-1 Y Y Y N Y Y ATI 28800/mach32/mach64 Y Y Y Y Y Y Avance Logic 2000 series Y Y Y Y Y Y Chips & Technologies 82c451 Y N N N Y N Chips & Technologies 82c452 Y Y N N Y Y Chips & Technologies 82c453 Y Y Y Y Y Y Chips & Tech 64xxx/655xx Y Y Y Y Y Y Cirrus Logic 5400/6200/7540 N Y Y Y Y Y Cirrus Logic 6400 series Y Y Y Y Y Y Genoa 6000 series Y Y Y N Y Y Matrox MGA-2064W (Millennium) Y Y Y Y Y N NCR 77C22/77C32 Y Y Y Y Y Y Oak OTI-067 N Y Y N Y Y Oak OTI-077 N Y Y Y Y Y Oak OTI-087 Y Y Y N Y Y Paradise PVGA1a Y Y N N Y N Paradise WD90C00/10/24 Y Y N N Y Y Paradise WD90C11/30/31/33 Y Y Y Y Y Y Realtek 3100 series Y Y Y Y Y Y S3 N Y Y Y Y Y SiS Y Y Y Y Y Y Trident 8800 Y Y Y N Y Y Trident 8900/9000 Y Y Y Y Y Y Tseng ET3000 N Y Y N Y Y Tseng ET4000 Y Y Y Y Y Y Video7 Y Y Y Y Y Y minimum video RAM needed 256K 512K 512K 1MB 256K 512K Fastgraph mode number 24 25 26 27 28 29 �
Chapter 3: Initializing the Video Environment 51
The SVGA kernel maps Fastgraph's video mode numbers (24 to 29) to the chipset-
specific mode numbers. For example, the 640x480 256-color SVGA mode is 62 hex
on an ATI card, 5D hex on a Trident card, and 2E hex on a Tseng card, but it's
always mode 25 from Fastgraph's perspective. As we constantly add support for
new SVGA chipsets, please refer to Fastgraph's READ.ME file for the current
chipset list. The READ.ME file also lists known problems and limitations with
the various chipsets.
The Video Electronics Standards Association (VESA) has assumed the
complex task of improving software compatibility of SVGA cards from different companies. Most SVGA cards sold today include VESA compatibility, either directly in ROM or through loadable software drivers supplied with the card. Besides supporting specific chipsets, Fastgraph's SVGA kernel supports any SVGA card with VESA compatibility. Note that VESA is not a chipset, but a BIOS-level interface between an application (the SVGA kernel in this case) and chipset-specific functions. While the current VESA standard covers all six SVGA graphics modes that Fastgraph supports, these modes are only available if the underlying chipset also supports them.
When using VESA compatibility, the VESA BIOS handles all chipset-specific
functions such as bank switching. The overhead imposed by the BIOS usually makes the VESA modes slower than using chipset-specific functions directly. For this reason, you can specify if you want to give precedence to the chipset-specific code or to the VESA BIOS. Chipset-specific precedence means the SVGA kernel will only use the VESA BIOS if no supported SVGA chipset is found. Conversely, VESA precedence means the kernel will only use the chipset- specific functions if no VESA BIOS is found.
Before you use any SVGA graphics mode, you must use the fg_svgainit
routine to initialize the SVGA kernel (fg_svgainit must be called before fg_setmode, fg_bestmode, or fg_testmode). There are three ways to initialize the SVGA kernel with fg_svgainit:
* autodetect the SVGA chipset, precedence to chipset-specific code * autodetect the SVGA chipset, precedence to the VESA BIOS * use a designated SVGA chipset
The fg_svgainit routine's argument is an integer value between 0 and 34 that specifies which initialization method to use. Passing 0 to fg_svgainit uses the first method, in which the SVGA kernel searches for all supported chipsets before checking if a VESA BIOS is present. This means the SVGA kernel will only use VESA functions if fg_svgainit doesn't find one of the supported chipsets. Passing 1 to fg_svgainit also performs a chipset autodetect, but in this case the SVGA kernel first searches for a VESA BIOS, then through the list of supported chipsets. This means chipset-specific code will be used only when no VESA BIOS is found. You can also initialize the SVGA kernel for a specific chipset by passing a value between 2 and 34 to fg_svgainit. The following table summarizes the fg_svgainit initialization codes.
code chipset 0 autodetect (with chipset-specific precedence) 1 autodetect (with VESA precedence) 2 Ahead "A" type � 3 Ahead "B" type
52 Fastgraph User's Guide
4 ATI 18800 5 ATI 18800-1 6 ATI 28800/38800 7 Chips & Technologies 82c451/455/456/457 8 Chips & Technologies 82c452 9 Chips & Technologies 82c450/453 10 Genoa 6000 series 11 Oak OTI-067 12 Paradise PVGA1a 13 Paradise WD90C00/WD90C10/WD90C24 14 Paradise WD90C11/WD90C30/WD90C31/WD90C33 15 Trident 8800 16 Trident 8900/9000 17 Tseng ET3000 18 Tseng ET4000 19 Video7 20 Cirrus Logic 5400/6200/7540 series 21 S3 22 NCR 77C22/77C32 23 Oak OTI-077 24 Oak OTI-087 25 Oak OTI-087 (Diamond Viper BIOS) 26 Cirrus Logic 6400 series 27 Avance Logic 2000 series 28 ARK Logic 1000/2000 29 ATI 68800 (mach32) 30 ATI 88800 (mach64) 31 Chips & Technologies 64000/65500 series 32 Realtek 3100 series 33 Matrox MGA-2064W (Millennium) 34 SiS
For autodetect requests, fg_svgainit returns a value between 1 and 32
corresponding to the SVGA chipset found. If the return value is 1, it means a VESA BIOS will be used. A value between 2 and 32 means a specific SVGA chipset (as listed in the preceding table) will be used. If no VESA BIOS or supported SVGA chipset is found, fg_svgainit returns zero. In this case, Fastgraph's SVGA graphics modes are not available.
When you request initialization for a specific chipset, fg_svgainit
always returns the value passed to it. It does not check if that chipset is actually present, so this feature should be used judiciously.
Example 3-9 is a simple program that checks if an SVGA card is present,
and if so, displays the name of the SVGA chipset. It also displays how much video memory is present on the SVGA card and the version number of Fastgraph's SVGA kernel.
Example 3-9. #include <fastgraf.h> #include <stdio.h> void main(void); char *description[] = { "cannot be determined", "VESA", "Ahead A", "Ahead B", "ATI 18800", � "ATI 18800-1", Chapter 3: Initializing the Video Environment 53 "ATI 28800/38800", "Chips & Technologies 82c451/455/456/457", "Chips & Technologies 82c452", "Chips & Technologies 82c450/453", "Genoa 6000 series", "Oak OTI-067", "Paradise PVGA1a", "Paradise WD90C00/WD90C10", "Paradise WD90C11/WD90C30/WD90C31/WD90C33", "Trident 8800", "Trident 8900/9000", "Tseng ET3000", "Tseng ET4000", "Video7", "Cirrus Logic 5400/6200/7540 series", "S3", "NCR 77C22/77C32", "Oak OTI-077", "Oak OTI-087", "Oak OTI-087 (Diamond Viper BIOS)", "Cirrus Logic 6400 series", "Avance Logic 2000 series", "ARK Logic 1000/2000", "ATI 68800 (mach32)", "ATI 88800 (mach64)", "Chips & Technologies 64000/65500 series", "Realtek 3100 series", "Matrox MGA-2064W (Millennium)", "SiS" }; void main() { int id, major, minor; fg_initpm(); id = fg_svgainit(0); printf("SVGA chipset: %s\n",description[id]); printf("video memory: %d kilobytes\n",fg_memory()); fg_svgaver(&major,&minor); printf("SVGA version: %d.%2.2d\n",major,minor); }
This example uses fg_svgainit to detect the user's SVGA chipset automatically. It initializes the SVGA kernel so chipset-specific code is given precedence over VESA (passing 1 instead of 0 to fg_svgainit would give VESA precedence). Note that the program does not establish an SVGA graphics mode -- it just uses the fg_svgainit return value to identify which chipset is present.
Example 3-9 also includes two other Fastgraph routines relevant to the
SVGA kernel. The fg_memory function returns the amount of video memory (in kilobytes) resident on the user's video card. For example, the fg_memory return value is 1,024 for a 1MB SVGA card. Another routine, fg_svgaver, returns the major and minor numbers for the SVGA kernel, similar to the fg_version routine mentioned in Chapter 1. Note that the SVGA kernel version number is not the same as the Fastgraph version number.
Another useful function is fg_svgastat, which returns information about
the current state of Fastgraph's SVGA kernel. The function returns a bit mask in which bit 0 will be set if the SVGA kernel has been successfully initialized, and bit 1 will be set if the kernel is using the VESA BIOS. Other � 54 Fastgraph User's Guide
fg_svgastat bits provide information about the availability of extended video
pages and whether or not the active chipset supports separate read and write
banks. We'll discuss these features in later chapters.
Our next example, 3-10, is an SVGA version of example 3-8. This program
initializes the SVGA kernel so that VESA will have precedence over chipset- specific code. It then calls fg_testmode to find a supported 256-color SVGA graphics mode, first trying mode 27 (1024 by 768), then mode 26 (800x600), and finally mode 25 (640x480). Checking the modes in this sequence insures the program will use the highest resolution available, given the user's SVGA chipset (not all chipsets support all resolutions) and the amount of video memory present (mode 27 requires 1MB video RAM; modes 26 and 25 need 512K).
If all three fg_testmode calls fail in example 3-10, the program displays
an appropriate message and exits. This would happen if the program were run on a non-SVGA system, run on an unsupported SVGA chipset without VESA compatibility, or if the SVGA card does not have at least 512K video memory (modes 25, 26, and 27 all require at least 512K). In the first two cases, the fg_svgainit function wouldn't have initialized the SVGA kernel, so fg_testmode would fail when checking the availability of any SVGA graphics mode. That's why it's not necessary to check the fg_svgainit return value in this case.
Example 3-10.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode; char string[4];
fg_initpm(); old_mode = fg_getmode(); fg_svgainit(1);
if (fg_testmode(27,1)) fg_setmode(27); else if (fg_testmode(26,1)) fg_setmode(26); else if (fg_testmode(25,1)) fg_setmode(25); else { printf("This program requires an SVGA "); printf("with at least 512K video memory.\n"); exit(1); }
fg_setcolor(15); fg_text("I'm running in mode ",20); sprintf(string,"%d.",fg_getmode()); fg_text(string,3); fg_waitkey(); � Chapter 3: Initializing the Video Environment 55
fg_setmode(old_mode); fg_reset(); }
While the VESA specification defines a common programming interface for
chipset-specific SVGA functions, we must remember that VESA is just that -- a specification. Some manufacturers provide VESA drivers or BIOS implementations that realize the full VESA specification with only slight performance degradations. Others aren't as good, having problems with anything beyond the rudimentary functions of mode initialization and bank switching, not to mention performance issues.
Other problems can occur with the few SVGA cards that do not completely
follow the chipset manufacturer's predefined video mode numbers and register definitions. While the SVGA kernel allows for these problems when known, it's just not possible to support every problematic SVGA card. To complicate matters, some of these troublesome video cards only exhibit problems in certain revisions, meaning two apparently identical cards will behave differently. Fortunately, such problematic cards are by far the exception.
If you're developing an SVGA product for general distribution, we
recommend using Fastgraph's chipset-specific code by default, but also providing a way to override the chipset-specific code and use VESA support. Most often this is done by recognizing a command line switch or using an application-specific configuration file. Some programmers even take this one step farther by including a way to avoid the SVGA autodetection procedure and initialize Fastgraph's SVGA kernel for a specific chipset. This might be important if your product will run on laptop systems, which sometimes have SVGA video subsystems that don't respond to autodetection requests as reliably as their desktop counterparts.
Another important point to consider when writing SVGA applications is the
compatibility between the video card and monitor. Virtually all SVGA monitors made today have no problems supporting the bandwidth required by any of Fastgraph's SVGA graphics modes. However, some monitors (most notably older multisync monitors) cannot support the higher resolution modes such as 800x600 and 1024 by 768. The SVGA kernel checks if the SVGA card supports the requested resolution, but it does not check if the card/monitor combination does.
Summary of Video Initialization Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_AUTOMODE determines the graphics video mode that offers the most
features for the user's display and adapter configuration. The value it returns helps determine a suitable value to pass to the fg_setmode routine.
FG_BESTMODE is similar to fg_automode, but it excludes video modes that
do not offer the specified resolution and video page requirements. � 56 Fastgraph User's Guide
FG_CURSOR makes the text mode cursor visible or invisible. This routine
has no effect when used in a graphics mode.
FG_GETLINES returns the number of text rows per screen for the current
video mode.
FG_GETMODE returns the current video mode. It is typically one of the
first Fastgraph routines called in a program. The value returned by fg_getmode can be used to restore the original video mode when a program transfers control back to DOS.
FG_MEMORY returns the amount of video memory present (in kilobytes) on
the user's SVGA card. This routine is meaningful only after successfully initializing the SVGA kernel with fg_svgainit.
FG_RESET is generally the last Fastgraph routine called in a program. It
only functions in text video modes. When the ANSI.SYS driver is not loaded, fg_reset merely erases the screen. When ANSI.SYS is loaded, fg_reset also restores any previously set screen attributes.
FG_SETLINES extends an 80-column text mode to 25, 43, or 50 lines per
screen. This routine is only meaningful when running in 80-column text modes on EGA, VGA, or MCGA systems (in other cases it does nothing).
FG_SETMODE establishes a video mode and initializes Fastgraph's internal
parameters for that video mode. It must be called before any Fastgraph routine that performs video output. A program can call fg_setmode as many times as needed to switch between different video modes.
FG_SVGAINIT initializes Fastgraph's SVGA kernel and performs chipset-
specific SVGA initialization. This routine must be called before establishing an SVGA graphics mode with fg_setmode.
FG_SVGASTAT returns information about the current state of Fastgraph's
SVGA kernel.
FG_SVGAVER returns the SVGA kernel's major and minor version numbers.
FG_TESTMODE determines whether or not a specified video mode (with a
given number of video pages) is available on the user's system.
Chapter 4
Coordinate Systems � 58 Fastgraph User's Guide
Overview
Fastgraph uses three coordinate systems to perform text and graphics
output -- character space, screen space, and world space. Character space is used in text modes and optionally for displaying character strings in graphics modes. Screen space is the basic coordinate system for graphics video modes and uses the screen's physical device coordinates. Viewports are an extension of screen space that let you assign an alternate integer-based coordinate system to rectangular subsets of the screen. Finally, world space is a user- definable coordinate system for graphics modes that uses floating point values. The world space coordinate system is not available in Fastgraph/Light.
Character Space
The coordinate system used for displaying characters is called character
space. Fastgraph uses character space for displaying characters in both text and graphics video modes (you can also use screen space to display characters in graphics modes). Character space can be thought of as a grid of rows and columns, with each cell in the grid holding one character. Each cell is identified by its unique (row,column) integer coordinates. The rows and columns are numbered starting at zero; the origin is always the upper left corner of the screen. For example, in the 80-column by 25-row text modes (2, 3, and 7), the default (row,column) coordinates of the screen corners are shown in the following diagram.
(0,0) (0,79)
(24,0) (24,79)
The number of rows and columns depends on the video mode, as shown in the
following table. For graphics modes, the table also includes the width and
height in pixels of a character cell.
Mode No. of No. of Char. Char. Number Columns Rows WidthHeight
0 40 25 1 40 25 2 80 25 3 80 25 4 40 25 8 8 5 40 25 8 8 6 80 25 8 8 7 80 25 9 40 25 8 8 11 80 25 9 14 12 40 25 8 8 13 40 25 8 8 14 80 25 8 8 15 80 25 8 14 � Chapter 4: Coordinate Systems 59
16 80 25 8 14 17 80 30 8 16 18 80 30 8 16 19 40 25 8 8 20 40 25 8 8 21 40 50 8 8 22 40 30 8 8 23 40 60 8 8 24 80 25 8 16 25 80 30 8 16 26 100 37 8 16 27 128 48 8 16 28 100 37 8 16 29 128 48 8 16
Fastgraph includes two routines, fg_getmaxx and fg_getmaxy, that
respectively return the maximum column and row numbers in text modes. Example 4-1 demonstrates these two routines in a text mode. The program uses fg_getmaxx and fg_getmaxy to obtain the maximum column and row numbers in mode 3. It then displays these values (79 and 24).
Example 4-1.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int max_col; int max_row; int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(3);
max_col = fg_getmaxx(); max_row = fg_getmaxy();
fg_setmode(mode); fg_reset();
printf("Last col = %d\n",max_col); printf("Last row = %d\n",max_row); }
Screen Space
Screen space is one of two available coordinate systems in graphics
modes. It uses the physical device coordinates. Screen space can be thought of as a grid of rows and columns, with each unit in the grid holding one pixel. Each pixel is identified by its unique (x,y) integer coordinates. The pixel rows and columns are numbered starting at zero; the origin is always the upper � 60 Fastgraph User's Guide
left corner of the screen. For example, in the 320x200 graphics modes, the
(x,y) coordinates of the screen corners are shown in the following diagram.
(0,0) (319,0)
(0,199) (319,199)
The Fastgraph routines fg_getmaxx and fg_getmaxy return the maximum x and
y screen coordinates when used in graphics modes, as shown in example 4-2. The program uses fg_getmaxx and fg_getmaxy to obtain the maximum x and y coordinates in the standard VGA/MCGA 256-color graphics mode (mode 19). It then displays these values (319 and 199).
Example 4-2.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int maxx; int maxy; int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(19);
maxx = fg_getmaxx(); maxy = fg_getmaxy();
fg_setmode(mode); fg_reset();
printf("(%d,%d)\n",maxx,maxy); }
Viewports
Viewports provide an alternate integer-based coordinate system for
referencing pixels. Fastgraph includes routines to create a viewport, return the viewport limits, and convert viewport coordinates to their screen space values.
A viewport definition consists of its extremes in "viewport space" and
the corresponding limits in screen space. The fg_setview routine defines a viewport. Its first four parameters represent the minimum x, maximum x, minimum y, and maximum y viewport coordinates, and its last four parameters represent the corresponding screen space pixel values defining the viewport's physical size and location. For example, the call �
Chapter 4: Coordinate Systems 61
fg_setview(100,739,100,499,0,159,0,99);
would create a 640x400 viewport in the upper left corner of a 320x200 screen. The viewport's coordinates would range from 100 to 739 horizontally and 100 to 499 vertically. In other words, the viewport coordinate (100,100) would map to the screen space pixel (0,0). The following diagram illustrates this viewport. The viewport space coordinates appear in boldface, while the other values are the equivalent screen space coordinates.
(100,100) (739,100)
(0,0) (159,0) (319,0)
(0,99) (159,99)
(100,499) (739,499)
(0,199) (319,199)
Fastgraph's fg_getview routine returns the current viewport limits and
corresponding screen space limits, as defined in the most recent call to
fg_setview.
Once you've defined a viewport, the fg_xview and fg_yview functions
translate viewport coordinates to their screen space equivalents. The translated values can then be passed to any Fastgraph routine that expects screen space coordinates. For example, Fastgraph's fg_rect routine draws a filled rectangle in screen space. If you wanted to fill the viewport defined above with color 10 pixels, you could do this as follows:
fg_setcolor(10); fg_rect(fg_xview(100),fg_xview(739),fg_yview(100),fg_yview(499));
Example 4-3 demonstrates a simple use of viewports in the standard
320x200 VGA/MCGA 256-color graphics mode. After filling the screen with white (color 15) pixels, it sets up a viewport in the upper left quadrant of the screen and uses fg_rect to fill it with light blue (color 9) pixels. It then defines three new viewports in the other screen quadrants, similarly filling the upper right quadrant with light green (color 10) pixels, the lower left quadrant with light cyan (color 11) pixels, and finally the lower right quadrant with light red (color 12) pixels. Note how the same viewport coordinates are used to fill the viewport in each case; only the viewport position changes.
Example 4-3.
#include <fastgraf.h> void main(void);
void main() { int mode; �
62 Fastgraph User's Guide
fg_initpm(); mode = fg_getmode(); fg_setmode(19); fg_setcolor(15); fg_rect(0,319,0,199); fg_waitkey();
fg_setview(0,639,0,399,0,159,0,99); fg_setcolor(9); fg_rect(fg_xview(0),fg_xview(639),fg_yview(0),fg_yview(399)); fg_waitkey();
fg_setview(0,639,0,399,160,319,0,99); fg_setcolor(10); fg_rect(fg_xview(0),fg_xview(639),fg_yview(0),fg_yview(399)); fg_waitkey();
fg_setview(0,639,0,399,0,159,100,199); fg_setcolor(11); fg_rect(fg_xview(0),fg_xview(639),fg_yview(0),fg_yview(399)); fg_waitkey();
fg_setview(0,639,0,399,160,319,100,199); fg_setcolor(12); fg_rect(fg_xview(0),fg_xview(639),fg_yview(0),fg_yview(399)); fg_waitkey();
fg_setmode(mode); fg_reset(); }
To make a viewport a "true" viewport, it is often desirable to establish
clipping limits at the viewport's extremes. This way, Fastgraph's functions that support clipping will only draw within the viewport itself. The following call to fg_setclip will establish the desired clipping limits:
fg_setclip(fg_xview(100),fg_xview(739),fg_yview(100),fg_yview(499));
The fg_setclip routine will be described in more detail in Chapter 6.
World Space
World space is the other available coordinate system in graphics modes.
It utilizes user-defined floating point coordinates. Fastgraph translates world space coordinates into physical device coordinates (screen space), and because of this it is somewhat slower than using screen space. World space can be thought of as a standard cartesian plane extending from the lower left corner of the screen. The world space vertical orientation is thus inverted relative to screen space and viewports.
Any program that uses world space coordinates must first initialize
Fastgraph's internal world space parameters. The Fastgraph routine fg_initw is �
Chapter 4: Coordinate Systems 63
provided for this purpose. The fg_initw routine has no arguments and must be
called before any other routine that uses world space coordinates.
The next step in using world space is to use the Fastgraph routine
fg_setworld to define the world space coordinates of the screen edges. The fg_setworld routine has four floating-point arguments -- the minimum x coordinate (left edge), the maximum x coordinate (right edge), the minimum y coordinate (bottom edge), and the maximum y coordinate (top edge). For example, if you define the world space coordinates with the statement
fg_setworld(-10.0,10.0,0.0,2.5);
the (x,y) coordinates of the screen corners would be defined as shown in the following diagram.
(-10.0,2.5) (10.0,2.5)
(-10.0,0.0) (10.0,0.0)
Fastgraph includes a routine fg_getworld that returns the world space extremes
as defined in the most recent call to fg_setworld.
Example 4-4 uses fg_setworld and fg_getworld to illustrate an interesting
application of world space. This program calls another routine named redraw (not shown) that erases the screen and draws a certain image using world space coordinates. The program draws the image, waits for a keystroke, reduces the world space by a factor of two in each direction, and then draws the image again. This produces a zoom effect in which the image appears twice as large as it was originally.
Example 4-4.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void); void redraw(void);
void main() { int new_mode, old_mode; double xmin, xmax, ymin, ymax;
fg_initpm(); old_mode = fg_getmode(); new_mode = fg_automode();
if (new_mode == 0) { printf("This program requires graphics.\n"); exit(1); } �
64 Fastgraph User's Guide
fg_setmode(new_mode); fg_initw();
fg_setworld(0.0,40.0,0.0,30.0); redraw(); fg_waitkey();
fg_getworld(&xmin,&xmax,&ymin,&ymax); fg_setworld(0.0,xmax*0.5,0.0,ymax*0.5); redraw(); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Conversion Routines
Sometimes it's necessary to convert coordinates between character space,
screen space, and world space. Fastgraph includes eight conversion routines, four for x coordinates and four for y coordinates, to perform such conversions. These routines return the translated coordinate as their function value.
The fg_xalpha and fg_yalpha routines convert screen space coordinates to
character space. The fg_xalpha routine converts a screen space x coordinate to the character space column that contains the coordinate. Similarly, the fg_yalpha routine converts a screen space y coordinate to the character space row that contains the coordinate.
The fg_xconvert and fg_yconvert routines convert character space
coordinates to screen space. The fg_xconvert routine converts a character space column to the screen space coordinate of its leftmost pixel. Similarly, the fg_yconvert routine converts a character space row to the screen space coordinate of its top (lowest-numbered) pixel.
The fg_xscreen and fg_yscreen routines convert world space coordinates to
screen space. The fg_xscreen routine translates x coordinates, while the fg_yscreen routine translates y coordinates. Conversely, the fg_xworld and fg_yworld routines convert screen space coordinates to world space. The fg_xworld routine translates x coordinates, while the fg_yworld routine translates y coordinates.
Summary of Coordinate Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_GETMAXX returns the maximum x coordinate in screen space when used in
a graphics mode. It returns the maximum column number in character space when used in a text mode. �
Chapter 4: Coordinate Systems 65
FG_GETMAXY returns the maximum y coordinate in screen space when used in
a graphics mode. It returns the maximum row number in character space when used in a text mode.
FG_GETVIEW returns the current viewport limits and their screen space
equivalents, as defined in the most recent call to fg_setview.
FG_GETWORLD returns the current world space limits, as defined in the
most recent call to fg_setworld.
FG_INITW initializes Fastgraph's internal parameters for world space.
This routine must be called once, before any other routine that uses world coordinates.
FG_SETVIEW defines a viewport with the specified extremes at the
specified screen space position.
FG_SETWORLD defines the world space coordinates that correspond to the
physical edges of the screen.
FG_XALPHA and FG_YALPHA convert screen space coordinates to character
space.
FG_XCONVERT and FG_YCONVERT convert character space coordinates to screen
space.
FG_XSCREEN and FG_YSCREEN convert world space coordinates to screen
space.
FG_XVIEW and FG_YVIEW convert viewport coordinates to screen space.
FG_XWORLD and FG_YWORLD convert screen space coordinates to world space. �
66 Fastgraph User's Guide
Chapter 5
The Use of Color � 68 Fastgraph User's Guide
Overview
The use of color is an important part of any text or graphics
application. This chapter explains color as it applies to text and graphics modes. It also describes palettes and video DAC registers for the graphics video modes that offer this functionality. Finally, an explanation of Fastgraph's virtual colors is provided.
Text Modes
The term color is not really correct in text modes because each character
cell has an associated attribute that controls the character's appearance in that cell. The meaning of the attribute differs for color and monochrome text modes.
Color Text Modes
In color text modes (modes 0, 1, 2, and 3), the attribute determines a
character's foreground color (the color of the character itself), its background color (the color of that part of the character cell not covered by the character), and whether or not it blinks. Sixteen foreground colors (numbered 0 to 15) are available, but only eight background colors (numbered 0 to 7) are available. The colors assigned to these values are listed in the following table.
number color number color
0 black 8 dark gray 1 blue 9 light blue 2 green 10 light green 3 cyan 11 light cyan 4 red 12 light red 5 magenta 13 light magenta 6 brown 14 yellow 7 gray 15 white
At first it may seem the numbers have been arbitrarily assigned to the colors. Upon further inspection, however, it becomes apparent this is not the case. Each color number is a four bit quantity of the form IRGB, with I representing the intensity, R the red component, G the green component, and B the blue component. If the corresponding bit is 1, it means the intensity or color component is set. For example, normal red would be represented by the IRGB bit pattern 0100, which is 4 decimal, the color number for red.
The fg_setattr routine defines the current text attribute. Once
fg_setattr is called, Fastgraph displays all subsequent text using that attribute. The first argument of fg_setattr defines the foreground color, which must be an integer between 0 and 15. Its second argument defines the background color, which must be between 0 and 7. Its third argument determines if the foreground color blinks (1 means it blinks, 0 means it does not). For example, the statement
fg_setattr(14,1,0); � Chapter 5: The Use of Color 69
specifies subsequent text will be displayed with a yellow foreground (14) on a blue background (1) and will not blink (0).
Another Fastgraph routine, fg_setcolor, also can define text attributes.
The fg_setcolor routine packs the three values passed to fg_setattr into a single argument, as shown here:
bits attribute
0-3 foreground color 4-6 background color 7 blinking
For example, calling fg_setcolor with an argument of 30 (1E hex) is equivalent to calling fg_setattr with arguments of 14, 1, and 0.
The Fastgraph routine fg_getcolor returns the current text attribute, as
defined in the most recent call to fg_setattr or fg_setcolor. The fg_getcolor routine has no arguments and returns the attribute as its function value. The returned value is encoded using the same scheme for passing a text attribute to fg_setcolor.
Monochrome Text Mode
In the monochrome text mode (mode 7), colors are obviously not available.
The attribute instead determines whether a character is invisible, normal, bold, reversed, or certain combinations of these. The following table shows the values assigned to the available display characteristics.
foreground background characteristic
0 0 invisible 0 7 reversed 1 0 underlined 7 0 normal 9 0 underlined bold 15 0 bold
Additionally, you can turn blinking on or off for each of these combinations. Any combination of foreground and background values not listed in the above table produces a normal display characteristic.
As in the color modes, the Fastgraph routines fg_setattr and fg_setcolor
define the current text attribute. For example, the statement
fg_setattr(0,7,1);
specifies subsequent text will be displayed in reverse video (0,7) and will blink (1). The same attribute could be defined by calling fg_setcolor with an argument of 240 (F0 hex). The fg_getcolor routine is also available and works as it does in the color text modes. � 70 Fastgraph User's Guide
Graphics Modes
In graphics modes, each pixel has an associated color value that
determines the color in which the pixel is displayed. The number of available colors depends on the video mode and can be obtained through the fg_colors function. Some graphics modes also have palette registers or video DAC registers to provide additional color capabilities, such as choosing a set of colors from a larger palette of colors. The example programs presented in this section show the use of color in specific graphics video modes.
The following subsections will discuss the use of color in each graphics
video mode. In these discussions, there will be several references to a group of colors called the standard color set. This is a set of 16 colors common to many of the graphics video modes (and to the color text modes). The colors in the standard color set are listed in the following table.
number color number color
0 black 8 dark gray 1 blue 9 light blue 2 green 10 light green 3 cyan 11 light cyan 4 red 12 light red 5 magenta 13 light magenta 6 brown 14 yellow 7 gray 15 white
At this point we must understand the difference between the terms color
number and color value. Color number refers to the number that defines a color in the standard color set (for example, green is color number 2). Color value refers to the actual value of a pixel in video memory, which ultimately determines the color in which that pixel is displayed. The color value is sometimes just called the color.
In each graphics mode, video memory is cleared when the fg_setmode
routine is called. This means all pixels are initially set to color value 0, which by default is black. For this reason, color value 0 is often called the background color in graphics video modes.
Fastgraph's fg_setcolor routine defines the color in which subsequent
graphics operations are performed. This color is called the current color. Depending on the video mode, the current color can reference a color value (in CGA and Hercules graphics modes), a palette register (in Tandy, EGA, and VGA graphics modes), or a video DAC register (in 256-color modes). The fg_setcolor routine takes a single integer argument that specifies the color. When fg_setmode is called, it sets the current color to 0. The Fastgraph routine fg_getcolor returns the current color, as defined in the most recent call to fg_setcolor. The fg_getcolor routine has no arguments and returns the current color as its function value.
CGA Color Modes
The CGA color modes (modes 4 and 5) have six sets of available colors,
called palettes, numbered 0 to 5. Each palette consists of four colors, �
Chapter 5: The Use of Color 71
numbered 0 to 3. In each palette, the background color (color value 0) can be
selected from the standard color set, but the other 3 colors are fixed. The
following table shows the fixed colors assigned to each palette.
palette 0 palette 1 palette 2
color 1 light green light cyan light cyan color 2 light red light magenta light red color 3 yellow white white
palette 3 palette 4 palette 5
color 1 green cyan cyan color 2 red magenta red color 3 brown gray gray
Palette 1, with a black background, is the default palette when you select
mode 4. Palette 2, with a black background, is the default palette when you
select mode 5.
The CGA color modes have a border area called the overscan between the
addressable pixel space and the physical edges of the screen. The overscan area is always displayed in the background color, regardless of which CGA palette is used.
In CGA color modes, fg_setcolor defines the current color by referencing
one of the four color values. The fg_palette routine selects one of the six palettes and defines the background color for that palette. The first argument of fg_palette is an integer between 0 and 5 that specifies the palette number. The second argument is an integer between 0 and 15 that defines the background color, using the color numbers in the standard color set.
Example 5-1 demonstrates the use of fg_palette and fg_setcolor in mode 4.
After establishing the video mode, the program selects palette 0 and makes the background color blue (color number 1). It then makes color 3 in palette 0 (yellow) the current color and displays the word "Hello". Finally, it restores the original video mode and screen attributes before returning to DOS.
Example 5-1.
#include <fastgraf.h> void main(void);
void main() { int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(4);
fg_palette(0,1); fg_setcolor(3); fg_text("Hello",5); �
72 Fastgraph User's Guide
fg_waitkey();
fg_setmode(mode); fg_reset(); }
CGA Two-Color Mode
The CGA two-color mode (mode 6) has a fixed background color (color value
0) and a user-definable foreground color (color value 1). The background color is always black. The foreground color is white by default but can be changed to any of the colors in the standard color set. We should mention that changing the foreground color works on true CGA adapters, but there are very few EGA, VGA, and SVGA adapters that correctly implement changing the foreground color in their mode 6 emulation.
In mode 6, fg_setcolor defines the current color by referencing one of
the two color values. The fg_palette routine defines the actual foreground color (that is, the color of pixels whose color value is 1). For consistency with other graphics modes, fg_palette has two arguments, but the first one is not used. The second argument is an integer between 0 and 15 that defines the foreground color, using the color numbers in the standard color set.
Example 5-2 demonstrates the use of fg_palette and fg_setcolor in mode 6.
After establishing the video mode, the program makes the foreground color yellow (color number 14). It then makes color 1 the current color and displays the word "Hello". Finally, it restores the original video mode and screen attributes before returning to DOS.
Example 5-2.
#include <fastgraf.h> void main(void);
void main() { int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(6);
fg_palette(0,14); fg_setcolor(1); fg_text("Hello",5); fg_waitkey();
fg_setmode(mode); fg_reset(); } � Chapter 5: The Use of Color 73
Tandy and PCjr Modes
The supported Tandy 1000 or PCjr graphics mode (mode 9) has 16 color
values, numbered 0 to 15. Each color value references one of 16 user-definable palette registers, often simply called palettes, also numbered 0 to 15. The values assigned to the palette registers determine the colors in which pixels are displayed. For example, if you assign palette register 2 the value for red, then pixels whose color value is 2 will be red.
Each palette can assume one of the 16 colors in the standard color set.
By default, the values assigned to the 16 palettes correspond to the identically numbered colors in the standard color set. In other words, palette 0 is assigned the value for black, palette 1 is assigned the value for blue, and so forth.
In mode 9, fg_setcolor defines the current color by referencing one of
the 16 palette registers. The fg_palette routine defines the actual color assigned to a specific palette register. The first argument of fg_palette is an integer between 0 and 15 that specifies the palette number. The second argument is an integer between 0 and 15 that defines the palette value (the color assigned to the palette), using the IRGB color numbers in the standard color set.
You also can use the Fastgraph routine fg_setrgb to define the color
assigned to a specific palette register. While fg_palette does this using a color number from the standard color set, fg_setrgb defines a palette register using red, green, and blue color components plus an intensity component. The first argument of fg_setrgb is an integer between 0 and 15 that specifies the palette register number. The remaining three arguments are each integer values between -1 and 1 that respectively specify the red, green, and blue color components for that palette register. The meanings of the color components are:
-1 = color bit and intensity bit are set 0 = color bit is reset 1 = color bit is set
Since there is only one intensity bit in mode 9 color values, specifying -1 for any of the RGB color components produces an intense color. For example, the color light cyan is color number 11 in the standard color set, and it is produced by combining green and blue and setting the intensity bit. This means any of these four statements
fg_palette(1,11); fg_setrgb(1,0,-1,1); fg_setrgb(1,0,1,-1); fg_setrgb(1,0,-1,-1);
could be used to define palette register 1 as light cyan in mode 9.
Example 5-3 demonstrates the use of fg_palette and fg_setcolor in mode 9.
After establishing the video mode, the program defines palette 0 to be blue (1) and palette 1 to be yellow (14). Note that defining palette 0 changes the � 74 Fastgraph User's Guide
background color. It then makes color 1 the current color and displays the
word "Hello". After waiting for a keystroke, the program changes the color of
"Hello" by changing palette 1 to white (15). Finally, it restores the original
video mode and screen attributes before returning to DOS.
Example 5-3.
#include <fastgraf.h> void main(void);
void main() { int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(9);
fg_palette(0,1); fg_palette(1,14);
fg_setcolor(1); fg_text("Hello",5); fg_waitkey();
fg_palette(1,15); fg_waitkey();
fg_setmode(mode); fg_reset(); }
Hercules Mode
The Hercules graphics mode (mode 11) has a fixed background color (color
value 0) and a fixed foreground color (color value 1). The background color is always black, and the foreground color is dependent on the monochrome display being used (typically it is green, amber, or white).
The fg_setcolor routine defines the current color value by referencing
one of the two color values. The fg_palette routine has no effect in mode 11.
Example 5-4 demonstrates the use of fg_setcolor in mode 11. After
establishing the video mode, the program makes color 1 the current color and displays the word "Hello". It then restores the original video mode and screen attributes before returning to DOS.
Example 5-4.
#include <fastgraf.h> void main(void);
void main() { � Chapter 5: The Use of Color 75
int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(11);
fg_setcolor(1); fg_text("Hello",5); fg_waitkey();
fg_setmode(mode); fg_reset(); }
Hercules Low-Resolution Mode
The Hercules low-resolution graphics mode (mode 12) has four color
values, numbered 0 to 3. The background color is always black, colors 1 and 2 are normal intensity, and color 3 is full intensity. Colors 1 and 2 both produce normal intensity colors, but they do so with different pixel patterns -- color 1 turns on the odd-numbered physical pixels, while color 2 turns on the even-numbered physical pixels. The appearance of colors 1 to 3 is dependent on the monochrome display being used (typically it is green, amber, or white).
The fg_setcolor routine defines the current color value by referencing
one of the four color values. The fg_palette routine has no effect in mode 12.
Example 5-5 demonstrates the use of fg_setcolor in mode 12. After
establishing the video mode, the program makes color 3 the current color and displays the word "Hello". It then restores the original video mode and screen attributes before returning to DOS.
Example 5-5.
#include <fastgraf.h> void main(void);
void main() { int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(12);
fg_setcolor(3); fg_text("Hello",5); fg_waitkey();
fg_setmode(mode); fg_reset(); } �
76 Fastgraph User's Guide
EGA 200-Line Modes
The 200-line EGA graphics modes (modes 13 and 14) have 16 color values,
numbered 0 to 15. Each color value references one of 16 user-definable palette registers, often simply called palettes, also numbered 0 to 15. The values assigned to the palette registers determine the colors in which pixels are displayed. For example, if you assign palette register 2 the value for red, then pixels whose color value is 2 will be red.
Each palette can assume one of the 16 colors in the standard color set.
By default, the values assigned to the 16 palettes correspond to the identically numbered colors in the standard color set. In other words, palette 0 is assigned the value for black, palette 1 is assigned the value for blue, and so forth.
In modes 13 and 14, fg_setcolor defines the current color by referencing
one of 16 available palette registers. The fg_palette routine defines the actual color assigned to a specific palette register. The first argument of fg_palette is an integer between 0 and 15 that specifies the palette number. The second argument is an integer that defines the palette value (the color assigned to the palette). Although the actual colors are taken from the standard color set, the binary structure of a palette value is different from the IRGB format used in the standard color set. In modes 13 and 14, the binary structure of a palette value is IxRGB; bit 3 is ignored. The mode 13 and mode 14 palette values that correspond to the standard color set are thus:
value color value color
0 black 16 dark gray 1 blue 17 light blue 2 green 18 light green 3 cyan 19 light cyan 4 red 20 light red 5 magenta 21 light magenta 6 brown 22 yellow 7 gray 23 white
You also can use the Fastgraph routine fg_setrgb to define the color
assigned to a specific palette register. While fg_palette does this using a color number from the standard color set, fg_setrgb defines a palette register using red, green, and blue color components, plus an intensity component. The first argument of fg_setrgb is an integer between 0 and 15 that specifies the palette register number. The remaining three arguments are each integer values between -1 and 1 that respectively specify the red, green, and blue color components for that palette register. The meanings of the color components are:
-1 = color bit and intensity bit are set 0 = color bit is reset 1 = color bit is set
Since there is only one intensity bit in mode 13 and 14 color values, specifying -1 for any of the RGB color components produces an intense color. For example, light cyan is represented by the color value 19, and it is �
Chapter 5: The Use of Color 77
produced by combining green and blue and setting the intensity bit. This means
any of these four statements
fg_palette(1,19); fg_setrgb(1,0,-1,1); fg_setrgb(1,0,1,-1); fg_setrgb(1,0,-1,-1);
could be used to define palette register 1 as light cyan in modes 13 and 14.
The Fastgraph routine fg_setcolor defines the color value (that is, the
palette number) in which subsequent graphics operations are performed. The fg_setcolor routine takes a single integer argument that specifies this color. When fg_setmode is called, it sets the color value to 0. The Fastgraph routine fg_getcolor returns the current color value, as defined in the most recent call to fg_setcolor. The fg_getcolor routine has no arguments and returns the current color as the function value.
Example 5-6 demonstrates the use of fg_palette and fg_setcolor in mode
13. After establishing the video mode, the program defines palette 0 to be blue (1) and palette 1 to be yellow (22). Note that defining palette 0 changes the background color. It then makes color 1 the current color and displays the word "Hello". After waiting for a keystroke, the program changes the color of "Hello" by changing palette 1 to white (23). Finally, it restores the original video mode and screen attributes before returning to DOS.
Example 5-6.
#include <fastgraf.h> void main(void);
void main() { int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(13);
fg_palette(0,1); fg_palette(1,22);
fg_setcolor(1); fg_text("Hello",5); fg_waitkey();
fg_palette(1,23); fg_waitkey();
fg_setmode(mode); fg_reset(); } �
78 Fastgraph User's Guide
EGA Monochrome Mode
The EGA monochrome graphics mode (mode 15) assigns display attributes to
its four color values, numbered 0 to 3. Each color value references one of four user-definable palette registers, often simply called palettes, numbered 0, 1, 4, and 5. This strange numbering results from the disabling of two of the four video memory bit planes in mode 15. The values assigned to the palette registers determine the pixel display attribute. For example, if you assign palette register 1 the value for bold, then pixels whose value is 1 will be bold.
In mode 15, fg_setcolor defines the current color (actually, a display
attribute) by referencing one of the four palette registers. The fg_palette routine defines the actual display attribute assigned to a specific palette register. The first argument of fg_palette is an integer that specifies the palette number. The second argument is an integer that defines the palette value (the display attribute assigned to the palette). For each palette register, the following table shows the default palette value and its associated display attribute.
palette palette display number value attribute
0 0 invisible 1 8 normal 4 24 bold 5 24 bold
Example 5-7 demonstrates the use of fg_palette and fg_setcolor in mode
15. After establishing the video mode, the program makes color 4 (actually, palette 4, which is bold by default) the current color and displays the word "Hello". After waiting for a keystroke, the program changes the display attribute of "Hello" by changing palette 4 to normal intensity (palette value 8). Finally, it restores the original video mode and screen attributes before returning to DOS.
Example 5-7.
#include <fastgraf.h> void main(void);
void main() { int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(15);
fg_setcolor(4); fg_text("Hello",5); fg_waitkey();
fg_palette(4,8); fg_waitkey(); � Chapter 5: The Use of Color 79
fg_setmode(mode); fg_reset(); }
EGA Enhanced Mode
The EGA enhanced graphics mode (mode 16) has 16 color values, numbered 0
to 15. Each color value references one of 16 user-definable palette registers, often simply called palettes, also numbered 0 to 15. The values assigned to the palette registers determine the colors in which pixels are displayed. For example, if you assign palette register 2 the value for red, then pixels whose color value is 2 will be red.
Each palette can assume one of 64 available colors. By default, the
values assigned to the 16 palettes correspond to the identically numbered colors in the standard color set. In other words, palette 0 is assigned the value for black, palette 1 is assigned the value for blue, and so forth. There are a few EGA-compatible adapters that do not properly assign the default colors to the 16 palette registers, so it is a good practice to do this explicitly in mode 16.
In mode 16, fg_setcolor defines the current color value by referencing
one of the 16 palette registers. The fg_palette routine defines the actual color assigned to a specific palette register. The first argument of fg_palette is an integer between 0 and 15 that specifies the palette number. The second argument is an integer that defines the palette value (the color assigned to the palette). The binary structure of a palette value is different from the IRGB format used in the standard color set. In mode 16, the binary structure of a palette value is a 6-bit quantity of the form rgbRGB, where the lower case letters represent the low intensity (1/3 intensity) color components, and the upper case letters represent the normal intensity (2/3 intensity) color components. The mode 16 palette values that correspond to the standard color set are:
value color value color
0 black 56 dark gray 1 blue 57 light blue 2 green 58 light green 3 cyan 59 light cyan 4 red 60 light red 5 magenta 61 light magenta 20 brown 62 yellow 7 gray 63 white
The normal intensity components in mode 16 produce the same normal
intensity colors as in other 16-color graphics modes. Similarly, combining the low and normal intensities in mode 16 produces the high intensity colors of the other modes. The only exception to this is for the default brown, formed from the bit pattern 010100 (20 decimal). This value produces a more true brown than the value 6 decimal, which is really an olive green. � 80 Fastgraph User's Guide
The palette values used in mode 16 are 6-bit quantities, which means
there are 64 different colors available in mode 16. This group of 64 colors consists of the 16 colors in the standard color set plus 48 additional colors that are not available in any other EGA modes. However, because the EGA palette registers hold 4-bit quantities, only 16 of these colors can be displayed at the same time. In other words, the EGA enhanced mode provides the capability of displaying 16 simultaneous colors from a group of 64.
You also can use the Fastgraph routine fg_setrgb to define the color
assigned to a specific palette register. While fg_palette does this using a value between 0 and 63, fg_setrgb defines a palette register using red, green, and blue color components. The first argument of fg_setrgb is an integer between 0 and 15 that specifies the palette register number. The remaining three arguments are each integer values between 0 and 3 that respectively specify the intensities in thirds of the red, green, and blue color components for that palette register. For example, the color cyan is represented by the value 3 in the above table, and it is produced by combining normal intensity (2/3 intensity) green and blue. This means either of the statements
fg_palette(1,3); fg_setrgb(1,0,2,2);
could be used to define palette register 1 as cyan.
Example 5-8 demonstrates the use of fg_palette and fg_setcolor in mode
16. It uses the Fastgraph routine fg_rect (discussed in the next chapter) to draw rectangles of a specified size. After establishing the video mode, the program uses a for loop to draw 16 equal-size rectangles, one in each of the 16 color values. In the same loop, the program uses fg_palette to change each palette to black. The while loop that follows performs four iterations. The first iteration changes palette 0 to 0, palette 1 to 1, and so forth. Hence, the 16 rectangles appear in the palette values 0 to 15. The rectangles remain in these colors until is key is pressed to begin the next iteration. The second iteration changes palette 0 to 16, palette 1 to 17, and so forth. This makes the 16 rectangles appear in the palette values 16 to 31. Iterations three and four are similar, so the overall effect of the program is to display all 64 colors, 16 at a time. Finally, the program restores the original video mode and screen attributes before returning to DOS.
Example 5-8.
#include <fastgraf.h> void main(void);
#define COLORS 16 #define WIDTH 40
void main() { int base; int color; int minx, maxx; int mode; � Chapter 5: The Use of Color 81
fg_initpm(); mode = fg_getmode(); fg_setmode(16);
base = 0; minx = 0; maxx = WIDTH - 1;
for (color = 0; color < COLORS; color++) { fg_palette(color,0); fg_setcolor(color); fg_rect(minx,maxx,0,349); minx = maxx + 1; maxx = maxx + WIDTH; }
while (base < COLORS*4) { for (color = 0; color < COLORS; color++) fg_palette(color,base+color); base += COLORS; fg_waitkey(); }
fg_setmode(mode); fg_reset(); }
VGA and MCGA Two-Color Mode
The VGA and MCGA two-color mode (mode 17) has a background color (color
value 0) and a foreground color (color value 1). Each color value references one of two user-definable palette registers, often simply called palettes, also numbered 0 and 1. Each palette register in turn references one of 16 user-definable 18-bit video DAC registers, numbered 0 to 15. The values assigned to the palette registers and video DAC registers determine the colors in which pixels are displayed. For example, if palette register 1 contains the value 3, and video DAC register 3 contains the color value for red, then pixels whose color value is 1 (that is, the foreground pixels) will be red.
By default, palette register 0 references video DAC register 0, and
palette register 1 references video DAC register 1. In addition, video DAC register 0 initially contains the color value for black, while the other 15 video DAC registers (1 through 15) contain the color value for white. This means background pixels (color value 0) are black by default, while foreground pixels (color value 1) are white.
The 18-bit video DAC values consist of three 6-bit red, green, and blue
color components. Hence, each color component is an integer between 0 and 63; increasing values produce more intense colors. The default color components for DAC register 0 are red=0, blue=0, and green=0, which produces black. The default values for the other DAC registers are red=63, blue=63, and green=63, which produces white. Because the video DAC registers are 18 bits long, each DAC can specify one of 262,144 (2**18) colors. However, because the palette registers hold 1-bit quantities, only two of these colors can be displayed at � 82 Fastgraph User's Guide
the same time. In other words, mode 17 provides the capability of displaying
two simultaneous colors from a group of 262,144.
In mode 17, fg_setcolor defines the current color by referencing one of
the two palette registers. The fg_palette routine defines the value of a palette register by referencing one of the 16 video DAC registers. That is, fg_palette specifies the video DAC register that a palette register references. The first argument of fg_palette is either 0 or 1 and specifies the palette number. The second argument is an integer between 0 and 15 that specifies the video DAC register for that palette.
The Fastgraph routine fg_setrgb defines the value of a video DAC register
in mode 17. The first argument of fg_setrgb is an integer between 0 and 15 that specifies the DAC register number. The remaining three arguments are each integer values between 0 and 63 that respectively specify the red, green, and blue color components for that DAC register.
Example 5-9 demonstrates the use of fg_palette, fg_setrgb, and
fg_setcolor in mode 17. After establishing the video mode, the program defines DAC register 0 to be blue (red=0, green=0, blue=42) and DAC register 1 to be yellow (red=63, green=63, blue=21). Note that defining DAC register 0 changes the background color because palette 0 references DAC register 0. The program then makes color 1 the current color (palette 1 still references DAC register 1) and displays the word "Hello" in yellow. After waiting for a keystroke, the program changes the color of "Hello" by making palette 1 reference DAC register 15 (which still contains its default value, white). Finally, it restores the original video mode and screen attributes before returning to DOS.
Example 5-9.
#include <fastgraf.h> void main(void);
void main() { int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(17);
fg_setrgb(0,0,0,42); fg_setrgb(1,63,63,21);
fg_setcolor(1); fg_text("Hello",5); fg_waitkey();
fg_palette(1,15); fg_waitkey();
fg_setmode(mode); fg_reset(); } � Chapter 5: The Use of Color 83
VGA/SVGA 16-Color Modes
The VGA and SVGA 16-color modes (modes 18, 28, and 29) have 16 color
values, numbered 0 to 15. Each color value references one of 16 user-definable palette registers, often simply called palettes, also numbered 0 to 15. Each palette register in turn references one of 16 user-definable 18-bit video DAC registers, also numbered 0 to 15. The values assigned to the palette registers and video DAC registers determine the colors in which pixels are displayed. For example, if palette register 1 contains the value 3, and video DAC register 3 contains the color value for red, then pixels whose color value is 1 will be red.
By default, each of the 16 palette registers references the video DAC
register of the same number. In addition, the 16 video DAC registers respectively contain the color values for the 16 colors in the standard color set.
The 18-bit video DAC values consist of three 6-bit red, green, and blue
color components. Hence, each color component is an integer between 0 and 63; increasing values produce more intense colors. The default RGB color components for the 16 video DAC registers are:
DAC R G B color DAC R G B color
0 0 0 0 black 8 21 21 21 dark gray 1 0 0 42 blue 9 21 21 63 light blue 2 0 42 0 green 10 21 63 21 light green 3 0 42 42 cyan 11 21 63 63 light cyan 4 42 0 0 red 12 63 21 21 light red 5 42 0 42 magenta 13 63 21 63 light magenta 6 42 21 0 brown 14 63 63 21 yellow 7 42 42 42 gray 15 63 63 63 white
Because the video DAC registers are 18 bits long, each DAC can specify one of 262,144 (2**18) colors. However, because the palette registers hold 4-bit quantities, only 16 of these colors can be displayed at the same time. In other words, mode 18 provides the capability of displaying 16 simultaneous colors from a group of 262,144.
In the 16-color VGA and SVGA modes, fg_setcolor, fg_palette, and
fg_setrgb behave exactly as in mode 17 with one exception: there are 16 palette registers instead of just two. Example 5-9 demonstrates the use of these routines in mode 17, but it also would work in mode 18, 28, or 29 if the call to fg_setmode were changed accordingly.
256-Color Modes
The 256-color modes (modes 19 through 27) have 256 color values, numbered
0 to 255. Each color value directly references one of 256 user-definable 18- bit video DAC registers, also numbered 0 to 255. The values assigned to the video DAC registers determine the colors in which pixels are displayed. For example, if video DAC register 3 contains the color value for red, then pixels whose color value is 3 will be red. � 84 Fastgraph User's Guide
By default, the first 16 video DAC registers (0 to 15) contain the color
values for the standard color set. The next 16 DAC registers (16 to 31) contain the color values for a gray scale of gradually increasing intensity. The next 216 DAC registers (32 to 247) contain three groups of 72 colors each, with the first group (32 to 103) at high intensity, the second group (104 to 175) at moderate intensity, and the third group (176 to 247) at low intensity. Each group consists of three ranges of decreasing saturation (increasing whiteness), with each range varying in hue from blue to red to green. Finally, the last 8 DAC registers (248 to 255) alternate between black and white. This information is summarized in the following table.
DACs default color values
0 to 15 standard color set 16 to 31 gray scale of gradually increasing intensity 32 to 55 high saturation, high intensity colors 56 to 79 moderate saturation, high intensity colors 80 to 103 low saturation, high intensity colors 104 to 127 high saturation, moderate intensity colors 128 to 151 moderate saturation, moderate intensity colors 152 to 175 low saturation, moderate intensity colors 176 to 199 high saturation, low intensity colors 200 to 223 moderate saturation, low intensity colors 224 to 247 low saturation, low intensity colors 248 to 255 alternate between black and white
The 18-bit video DAC values consist of three 6-bit red, green, and blue
color components. Hence, each color component is an integer between 0 and 63; increasing values produce more intense colors. Because the video DAC registers are 18 bits long, each DAC can specify one of 262,144 (2**18) colors. However, because the color values are 8-bit quantities, only 256 of these colors can be displayed at the same time. In other words, modes 19 through 27 provide the capability of displaying 256 simultaneous colors from a group of 262,144.
In the 256-color graphics modes, fg_setcolor defines the current color by
referencing one of the 256 video DAC registers. The fg_setrgb routine defines the actual color of a video DAC register. The first argument of fg_setrgb is an integer between 0 and 255 that specifies the DAC register number. The remaining three arguments are each integer values between 0 and 63 that respectively specify the red, green, and blue color components for that DAC register. Another Fastgraph routine, fg_getrgb, returns the color components for a specified DAC register. Its arguments are the same as for fg_setrgb, except the last three arguments (the return values) are passed by reference rather than by value.
You also can use the Fastgraph routine fg_palette to define the value of
a video DAC register in modes 19 through 27. The first argument of fg_palette is an integer between 0 and 255 that specifies the DAC register number. The second argument is an integer between 0 and 63 that specifies the color value for that video DAC register, using the same 64 values as in the EGA enhanced mode (mode 16).
Example 5-10 demonstrates the use of fg_setcolor in mode 19. The program
uses the Fastgraph routine fg_rect to draw vertical lines. After establishing the video mode, the program uses a for loop to draw 256 vertical lines, one in �
Chapter 5: The Use of Color 85
each of the 256 colors (using the default DAC values). Finally, the program
restores the original video mode and screen attributes before returning to
DOS.
Example 5-10.
#include <fastgraf.h> void main(void);
#define COLORS 256
void main() { int base; int color; int mode; int x;
fg_initpm(); mode = fg_getmode(); fg_setmode(19);
x = 0;
for (color = 0; color < COLORS; color++) { fg_setcolor(color); fg_rect(x,x,0,199); x++; } fg_waitkey();
fg_setmode(mode); fg_reset(); }
Example 5-11 shows an interesting effect available in video modes that
support DAC registers. The program uses the Fastgraph routine fg_waitfor (discussed in Chapter 16) to delay the program's execution. After establishing the video mode, the program displays the word "Hello" in color 103, which by default is a pastel blue. It then uses fg_getrgb to retrieve the color components for this color. The while loop gradually decreases the color components until all three components are zero, which makes the word "Hello" smoothly fade to black. Finally, the program restores the original video mode and screen attributes before returning to DOS.
Example 5-11.
#include <fastgraf.h> void main(void);
void main() { int old_mode; int red, green, blue; �
86 Fastgraph User's Guide
fg_initpm(); old_mode = fg_getmode(); fg_setmode(19);
fg_setcolor(103); fg_text("Hello",5); fg_waitfor(18);
fg_getrgb(103,&red,&green,&blue);
while (red+green+blue > 0) { if (red > 0) red--; if (green > 0) green--; if (blue > 0) blue--; fg_setrgb(103,red,green,blue); fg_waitfor(1); }
fg_setmode(old_mode); fg_reset(); }
The fg_setrgb and fg_getrgb routines work with individual DAC registers.
If you want to define or retrieve a block of consecutive DAC registers, fg_setdacs and fg_getdacs are more efficient. The fg_setdacs routine defines the values of a block of consecutive DAC registers. Its first argument is the index of the first DAC register to define (between 0 and 255), and its second argument is the number of DAC registers to define (between 1 and 256). The third argument is a byte array containing the RGB color components for the DAC registers being defined. The array's first three bytes contain the red, green, and blue components for the first DAC, the next three for the second DAC, and so forth. The size of this array must be at least three times the value of the second argument. The fg_getdacs arguments are the same as those for fg_setdacs, but the RGB array instead receives the current values of the specified DAC registers. Both routines treat the DAC register numbers in a circular fashion (for example, defining four DACs starting with number 254 will define DACs 254, 255, 0, and 1).
Example 5-12 is similar to example 5-11, but it fades many colors
simultaneously. The program displays seven asterisks, one each in colors 9 through 15. It uses fg_getdacs to obtain the current settings of the corresponding DAC registers; these values are stored in the array RGBvalues. The while loop gradually fades the RGB components to zero, using fg_setdacs to update their values, similar to the method of example 5-11. This illustrates an attractive way of turning an image into a blank screen.
Example 5-12.
#include <fastgraf.h> void main(void);
void main() { int decreasing; int i; � Chapter 5: The Use of Color 87
int old_mode; char RGBvalues[21];
fg_initpm(); old_mode = fg_getmode(); fg_setmode(19);
for (i = 9; i <= 15; i++) { fg_setcolor(i); fg_text("*",1); }
fg_getdacs(9,7,RGBvalues); fg_waitfor(18);
do { decreasing = 0; for (i = 0; i < 21; i++) if (RGBvalues[i] > 0) { RGBvalues[i]--; decreasing = 1; } fg_setdacs(9,7,RGBvalues); fg_waitfor(1); } while (decreasing);
fg_setmode(old_mode); fg_reset(); }
Note that examples 5-11 and 5-12 also would work in 16-color VGA and SVGA
video modes as long as you just use the first 16 video DAC registers.
Using Video DAC Registers in EGA Modes
The fg_getdacs and fg_setdacs routines also work in modes 13, 14, and 16
when used on a VGA or SVGA system. This lets you choose 16 colors from a palette of 262,144 colors, as in mode 18. If you try to use these routines on an EGA system, the results are unpredictable. Applications that use these routines should therefore first insure they are running on a VGA or SVGA system by checking if fg_testmode(18,0) returns a nonzero value.
Before trying to use fg_getdacs and fg_setdacs in modes 13, 14, and 16,
you should first be aware of the relationship between VGA palettes and DAC registers. On the EGA, palette values directly determine the color displayed. On the VGA and SVGA, however, there is an added level of indirection. VGA and SVGA palette registers can be thought of as pointers to video DAC registers whose RGB components determine the displayed color.
Each palette register in the VGA 640x480 16-color graphics mode (mode 18)
initially points to the DAC register of the same number. We can thus pretend the indirection does not exist because changing DAC register n affects those pixels whose color value is n (unless, of course, we've changed the value of � 88 Fastgraph User's Guide
palette register n). In modes 13, 14, and 16, we can't ignore the indirection
because the palette registers contain different values. In mode 13, for
instance, palette register 8 contains the value 16 by default, not the value 8
as in mode 18.
The easiest way around this inconsistency is to set the palette and DAC
registers explicitly so they correspond to the default values of mode 18. There are two cases to consider -- one for modes 13 and 14, and the other for mode 16.
In modes 13 and 14, palettes 0 to 7 contain the values 0 to 7, but
palettes 8 to 15 contain the values 16 to 23. Hence, if you want to use fg_getdacs and fg_setdacs in these modes, you should include the following code after calling fg_setmode.
char RGBvalues[3]; int i;
for (i = 8; i < 16; i++) { fg_getdacs(i+8,1,RGBvalues); fg_setdacs(i,1,RGBvalues); fg_palette(i,i); }
This code will set the values of DACs 8 to 15 to the values of DACs 16 to 23.
It also sets palettes 8 to 15 to point to DACs 8 to 15. You can then ignore
the palette-DAC indirection because setting DAC register n affects pixels of
color n.
In mode 16, palette 6 is initially assigned the value 20, and palettes 8
to 15 are assigned the values 56 to 63. All other palettes point to the DAC of the same number. Hence, if you want to use fg_getdacs and fg_setdacs in mode 16, you should include the following code after calling fg_setmode.
char RGBvalues[3]; int i;
fg_getdacs(20,1,RGBvalues); fg_setdacs(6,1,RGBvalues); fg_palette(6,6);
for (i = 8; i < 16; i++) { fg_getdacs(i+48,1,RGBvalues); fg_setdacs(i,1,RGBvalues); fg_palette(i,i); }
This code will set the values of DAC 6 to the values of DAC 20, and also DACs
8 to 15 to the values of DACs 56 to 63. It also sets palettes 6 and 8-15 to
point to the identically-numbered DACs. You can then ignore the palette-DAC
indirection because setting DAC register n affects pixels of color n. �
Chapter 5: The Use of Color 89
While this might all seem complicated at first, it really isn't once you
understand the relationship between palettes and DACs. The ability to select colors from a palette of 256K colors instead of 16 or 64 is usually well worth the extra effort.
RGB Color Mapping
If you're developing an application that runs in 256-color and 16-color
graphics modes, you've probably noticed the inherent differences in defining color values. In fact, the palette register values even use different structures within the various 16-color modes. The Fastgraph routine fg_maprgb helps simplify these differences. It maps three RGB color components (each between 0 and 63) into a 16-color palette value suitable for the current video mode. Of course, the range of available colors is much more restricted in the 16-color modes than in the 256-color modes, so fg_maprgb must map the RGB components to the closest available color.
Example 5-13 runs in any 16-color or 256-color graphics mode and
demonstrates the use of the fg_maprgb routine. In 256-color modes, the program simply uses fg_setrgb to define DAC register 1 to a pastel blue (red=45, green=49, blue=63). In 16-color modes, however, the program calls fg_maprgb to convert the color components into a palette value in IRGB, IxRGB, or rgbRGB format (depending on the current video mode). The fg_maprgb return value is passed to fg_palette to set palette register 1 to the closest available color defined by the specified RGB components.
Example 5-13.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 4 || new_mode == 12) { printf("This program requires a 320 x 200 "); printf("16-color or 256-color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(1); if (new_mode <= 16) fg_palette(1,fg_maprgb(45,49,63)); else fg_setrgb(1,45,49,63); fg_text("Hello",5); fg_waitkey(); �
90 Fastgraph User's Guide
fg_setmode(old_mode); fg_reset(); }
Defining All Palette Registers
Fastgraph includes a routine fg_palettes that defines all 16 palette
registers in 16-color graphics modes. You also can use fg_palettes to define the first 16 video DAC registers in 256-color modes. It has no effect in other video modes.
Using fg_palettes is much faster than calling fg_palette 16 times. The
argument to fg_palettes is a 16-element integer array that contains the color values assigned respectively to palette registers (or video DAC registers) 0 to 15. Example 5-14 demonstrates how to zero the palette registers (that is, change them all to black) in mode 13.
Example 5-14.
#include <fastgraf.h> void main(void);
int zeroes[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void main() { int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(13);
fg_palettes(zeroes);
fg_setmode(mode); fg_reset(); }
Of course, as this example is written, it appears to do nothing more than
blank the screen. Its purpose is to show an example of the fg_palettes
routine.
Virtual Colors
By this time it should be clear the use of color is rather specific to
each graphics video mode. One of the most obvious differences is the number of available colors in each mode; it ranges from 2 to 256. By available colors, we mean the number of colors that can be displayed simultaneously.
To simplify programming in graphics modes, Fastgraph provides 256 virtual
colors. The virtual colors are used in the graphics video modes having fewer than 256 available colors. Virtual colors allow you to use 256 color indices �
Chapter 5: The Use of Color 91
in all graphics modes, even if a particular mode does not have 256 available
colors.
When you establish a video mode with fg_setmode, Fastgraph initializes
all the virtual color indices. It does this by replicating the video mode's color values through the 256 virtual color indices. For example, the CGA color modes (4 and 5) have four color values, numbered 0 through 3. In these modes, fg_setmode initializes color indices 0, 4, 8, ... , 252 to 0; color indices 1, 5, 9, ... , 253 to 1; color indices 2, 6, 10, ... , 254 to 2; and color indices 3, 7, 11, ... , 255 to 3. Similarly, in 16-color graphics modes the color indices 0, 16, 32, ... , 240 are set to 0, and so forth. In the monochrome EGA graphics video mode (mode 15), the color values are numbered 0, 1, 4, and 5, so fg_setmode replicates the color indices in groups of eight, even though there are only four available colors. An analysis of the color value sequences reveals an often useful feature: by default, virtual color 0 is black and virtual colors 15 and 255 are white in all graphics video modes.
It is thus possible to write a multiple-mode program using the same color
indices for each graphics mode. For example, a program that contains the statement fg_setcolor(5) would produce subsequent graphics in color 5 (magenta by default) when running in a 16-color graphics mode. It would produce subsequent graphics in color 1 (light cyan by default) when running in a CGA color mode. This is because 1 is the default value assigned to virtual color index 5 in the CGA color modes.
The fg_setmode routine establishes default values for the 256 virtual
color indices, but it might be desirable to assign other available colors to them. Going back to the discussion in the previous paragraph, color number 2 is light magenta in the default CGA mode 4 palette. It might make more sense if the color value 2 were assigned to virtual color index 5, as this would make the graphics drawn in color 5 the same color in mode 4 as in other color modes. The Fastgraph routine fg_defcolor is provided for this purpose.
The fg_defcolor routine assigns a color value to a virtual color index.
It has two arguments: the first specifies the virtual color index (between 0 and 255), and the second specifies the color value (between 0 and one less than the number of available colors in the current video mode). For example, the statement
fg_defcolor(5,2);
would assign the color value 2 to the color index 5. Another Fastgraph routine, fg_getindex, returns the current value assigned to a specified color index. After executing the above call to fg_defcolor, the statement
color = fg_getindex(5);
would store the value 2 (the current value of color index 5) in the integer variable color.
We must be sure to understand the difference between virtual colors and
palette registers. Modifying the value of a palette register changes the color of all pixels already drawn using that palette. Modifying a virtual color index does not do this; it only specifies any graphics drawn in that color from this point on will appear in the new color. � 92 Fastgraph User's Guide
Example 5-15 demonstrates virtual colors in mode 4. After establishing
the video mode, the program uses fg_defcolor to define virtual color indices 0 and 255 to be 1, which by default is light cyan in mode 4. It then draws characters using color indices 0, 1, and 255, and in each case the characters appear in light cyan. Finally, the program restores the original video mode and screen attributes before returning to DOS.
Example 5-15.
#include <fastgraf.h> void main(void);
void main() { int mode;
fg_initpm(); mode = fg_getmode(); fg_setmode(4);
fg_defcolor(0,1); fg_defcolor(255,1);
fg_setcolor(0); fg_text("0",1); fg_setcolor(1); fg_text(" 1",2); fg_setcolor(255); fg_text(" 255",4); fg_waitkey();
fg_setmode(mode); fg_reset(); }
A Multiple-Mode Example
Although the color capabilities differ between the supported video modes,
Fastgraph makes it easy to write a program that runs in many video modes. This section will present an example of such a program.
Example 5-16 illustrates a program that will run in any of Fastgraph's
supported video modes. The program first asks for the video mode number, checks if the mode number is valid, and then checks if the requested mode is available on the user's system. After doing this, the program establishes the video mode and performs its mode-specific code. It then displays a brief message that includes the video mode number in which the program is running. This information remains on the screen until a key is pressed, at which time the program restores the original video mode and screen attributes before returning to DOS.
Example 5-16.
#include <fastgraf.h> � Chapter 5: The Use of Color 93
#include <stdio.h> #include <stdlib.h> void main(void);
void main() { int mode, old_mode; char string[5];
/* Ask for the video mode number */ printf("Which video mode? "); scanf("%d",&mode);
/* Make sure the entered value is valid */ if (mode < 0 || mode > 29) { printf("%d is not a valid video mode number.\n",mode); exit(1); }
/* Make sure the requested video mode is available */ fg_initpm(); if (mode > 23) fg_svgainit(0); if (fg_testmode(mode,1) == 0) { printf("Mode %d is not available on this system.\n",mode); exit(1); }
/* Establish the video mode */ old_mode = fg_getmode(); fg_setmode(mode);
/* Perform mode-specific initializations */ if (mode <= 3 || mode == 7) /* text modes */ fg_cursor(0);
else if (mode == 4 || mode == 5) { /* CGA color modes */ fg_palette(0,0); fg_defcolor(14,3); }
else if (mode == 6) { /* CGA two-color mode */ fg_palette(0,14); fg_defcolor(14,1); }
else if (mode == 11) /* Hercules mode */ fg_defcolor(14,1);
else if (mode == 12) /* Hercules low-res mode */ fg_defcolor(14,3);
else if (mode == 17) { /* VGA two-color mode */ fg_palette(1,14); fg_setrgb(14,63,63,21); fg_defcolor(14,1); } �
94 Fastgraph User's Guide
/* Display a message that includes the video mode number */ fg_setcolor(14); fg_text("I'm running in mode ",20); sprintf(string,"%d. ",mode); fg_text(string,3);
/* Wait for a keystroke */ fg_waitkey();
/* Restore the original video mode and screen attributes */ fg_setmode(old_mode); fg_reset(); }
Example 5-16 displays its message in yellow for those video modes that
offer color. In monochrome video modes, it displays the message in normal intensity. The program uses virtual color 14, which by default is yellow in many video modes; the mode-specific code in example 5-16 makes color 14 yellow in other video modes. In text video modes (modes 0 to 3 and 7), the program uses fg_cursor to make the cursor invisible. In CGA color modes (modes 4 and 5), the program uses fg_palette to select a CGA palette that contains yellow as color 3 and then uses fg_defcolor to assign color 3 to virtual color 14. In CGA two-color mode (mode 6), the program uses fg_palette to make color 1 yellow and then uses fg_defcolor to assign color 1 to virtual color 14. In the Hercules modes (modes 11 and 12), the program uses fg_defcolor to assign the value for normal intensity pixels to color 14. In VGA two-color mode (mode 17), the program uses fg_palette to assign video DAC register 14 to palette register 1. It then defines video DAC register 14 to be yellow with fg_setrgb and finally uses fg_defcolor to assign color 1 (that is, palette register 1) to virtual color 14. In all other video modes, no color manipulation is needed because color 14 is yellow by default.
Summary of Color-Related Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_COLORS returns the number of simultaneously available colors in the
current video mode. In text video modes, fg_colors returns zero.
FG_DEFCOLOR assigns a color value to a virtual color index. This routine
is only meaningful in graphics video modes that have fewer than 256 available colors.
FG_GETCOLOR returns the current text attribute (in text modes) or color
index (in graphics modes), as specified in the most recent call to fg_setattr or fg_setcolor.
FG_GETDACS retrieves the red, green, and blue color components for a
block of consecutively numbered video DAC registers. This routine is only meaningful modes that use DAC registers. �
Chapter 5: The Use of Color 95
FG_GETINDEX returns the color value assigned to a specified virtual color
index. In text modes and in graphics modes that have 256 available colors, this routine returns the value passed to it.
FG_GETRGB returns the red, green, and blue color components for a
specified video DAC register. This routine is only meaningful in modes that use DAC registers.
FG_MAPRGB maps six-bit red, green, and blue color components into a
suitable palette value for the current video mode. You can then pass this value to fg_palette. This routine is meaningful only in 16-color graphics video modes.
FG_PALETTE has different functions depending on the current graphics
video mode. For the CGA four-color modes, it establishes the current palette (of six available) and defines the background color for that palette. In the CGA two-color mode, it defines the foreground color. For the Tandy/PCjr, EGA, and VGA graphics modes, it defines the value of a single palette register. For 256-color graphics modes, it defines the value of a single video DAC register. The fg_palette routine has no effect in text modes or Hercules graphics modes.
FG_PALETTES defines all 16 palette registers (in 16-color graphics
modes), or the first 16 video DAC registers (in 256-color graphics modes). The fg_palettes routine has no effect in text modes, CGA graphics modes, or Hercules graphics modes.
FG_SETATTR establishes the current text attribute in text video modes.
This routine has no effect in graphics modes.
FG_SETCOLOR establishes the current color index (which may be a virtual
color index in graphics modes). In text modes, fg_setcolor provides an alternate method of establishing the current text attribute.
FG_SETDACS defines the values of a block of consecutively numbered video
DAC registers by specifying their red, green, and blue color components. This routine is only meaningful in modes that use DAC registers.
FG_SETRGB defines the value of a single palette register (in Tandy/PCjr
and EGA graphics modes) or video DAC register (in VGA, MCGA, and SVGA modes) by specifying its red, green, and blue color components. The fg_setrgb routine has no effect in text modes, CGA graphics modes, or Hercules graphics modes. � 96 Fastgraph User's Guide
Chapter 6
Graphics Fundamentals � 98 Fastgraph User's Guide
Overview
This chapter describes Fastgraph's fundamental graphics routines,
sometimes called graphics primitives. These routines perform such functions as clearing the screen, drawing points, drawing solid and dashed lines, drawing closed shapes (polygons, circles, and ellipses), drawing rectangles (solid, hollow, and dithered), and filling arbitrary regions. Most of these routines have no effect in text video modes, but there are a few exceptions, and they will be noted in the descriptions of those routines.
Clearing the Screen
The Fastgraph routine fg_erase clears the entire screen in any video
mode. In text modes, fg_erase stores a space character (ASCII 32) with a gray foreground attribute in each character cell. In graphics modes, fg_erase sets each pixel to zero. This of course causes each pixel to be displayed its background color. The fg_erase routine has no arguments.
The fg_erase routine always sets the entire screen to the background
color. Another routine, fg_fillpage, fills the screen with the current color. In text modes, fg_fillpage stores a solid block character (ASCII 219) with the current display attribute (as defined in the most recent call to fg_setcolor or fg_setattr). In graphics modes, fg_fillpage sets each pixel to the current color (as defined in the most recent call to fg_setcolor). Like fg_erase, fg_fillpage has no arguments.
Clipping
The suppression of graphics outside a pre-defined area is called
clipping. Many of Fastgraph's graphics-oriented routines provide clipping, either automatically or through a special version of the routine.
Fastgraph includes two routines, fg_setclip and fg_setclipw, to define a
rectangular clipping region. The fg_setclip routine defines the clipping region in screen space, while fg_setclipw performs the same function in world space. Each routine takes four arguments: the minimum x, the maximum x, the minimum y, and the maximum y coordinate of the clipping region. The arguments are integer quantities for fg_setclip and floating point quantities for fg_setclipw. For example, the statement
fg_setclip(0,159,0,99);
would define the upper left quadrant of the screen as the clipping region in a 320x200 graphics mode. Fastgraph's fg_getclip routine returns the current clipping limits, as defined in the most recent call to fg_setclip.
An implicit clipping region equal to the entire screen is defined as part
of the fg_setmode routine's initializations. Clipping is not supported for text modes. �
Chapter 6: Graphics Fundamentals 99
Points
The Fastgraph routine fg_point provides the most basic graphics
operation -- setting a pixel to a specified color. The fg_point routine has two integer arguments. The first specifies the pixel's x coordinate, and the second its y coordinate. The pixel is drawn using the current color value, as specified in the most recent call to fg_setcolor. There is also a world space version of this routine, fg_pointw, that uses floating point arguments. Both routines display the pixel only if it falls within the current clipping region.
Another Fastgraph routine is available for reading a pixel's color value.
The fg_getpixel routine has two integer arguments that specify the (x,y) coordinates for the pixel of interest. If the (x,y) coordinates lie outside the clipping region, fg_getpixel returns -1. There is no world space version of fg_getpixel, but you can read a pixel's color value in world space by applying the fg_xscreen and fg_yscreen functions to the world space coordinates and passing the resulting values to fg_getpixel.
Example 6-1 uses fg_point to draw 100 random points in random colors. It
also uses fg_getpixel to insure no two points are adjacent. The program establishes a graphics video mode with fg_automode and fg_setmode. Next, it calls fg_colors to determine the maximum color value for the selected video mode, and then calls fg_getmaxx and fg_getmaxy to obtain the horizontal and vertical resolution. The main part of the program is a while loop that first generates a random pair of (x,y) screen coordinates. It then calls fg_getpixel to check the pixels at (x,y) and the eight adjacent positions. If none of these pixels are set, the program generates a random color value and draws a point in that color. After doing this 100 times, the program waits for a keystroke, restores the original video mode and screen attributes, and then returns to DOS.
Example 6-1.
#include <fastgraf.h> #include <stdlib.h> void main(void);
void main() { int area; int color, colors; int left; int new_mode, old_mode; int x_range, y_range; int x, y;
fg_initpm(); old_mode = fg_getmode(); new_mode = fg_automode(); fg_setmode(new_mode);
colors = fg_colors(); x_range = fg_getmaxx() - 1; y_range = fg_getmaxy() - 1; left = 100; �
100 Fastgraph User's Guide
while (left > 0) { x = (rand() % x_range) + 1; y = (rand() % y_range) + 1;
area = fg_getpixel(x-1,y-1) + fg_getpixel(x,y-1) + fg_getpixel(x+1,y-1) + fg_getpixel(x-1,y) + fg_getpixel(x,y) + fg_getpixel(x+1,y) + fg_getpixel(x-1,y+1) + fg_getpixel(x,y+1) + fg_getpixel(x+1,y+1); if (area == 0) { color = rand() % colors; fg_setcolor(color); fg_point(x,y); left--; } } fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Sometimes you may want to display a pixel using an "exclusive or"
operation (usually called XOR) to guarantee its visibility. The color of a pixel drawn in XOR mode will be c xor p, where c is the current color and p is the color of the pixel already at that position. This means the pixel's new color will be different from the background as long as the current color is not zero. The Fastgraph routine fg_pointx displays a screen space pixel in XOR mode, while fg_pointxw does the same thing in world space. Their respective parameters are the same as for fg_point and fg_pointw.
The Graphics Cursor
Many of Fastgraph's graphics routines depend on the position of the
graphics cursor as a reference point. For example, Fastgraph includes routines to draw lines from the graphics cursor position to a specified position, and the bitmapped image display routines discussed in Chapter 10 display or retrieve an image relative to the graphics cursor position. The graphics cursor is not a cursor in the true sense; it is simply a pair of (x,y) coordinates with a special meaning. The fg_setmode routine sets the graphics cursor position to the screen space coordinates (0,0), and fg_initw sets it to the world space coordinates (0.0,0.0).
Fastgraph includes four routines for changing the graphics cursor
position. The fg_move routine sets it to an absolute screen space position, while fg_movew sets it to an absolute world space position. The fg_moverel routine sets the graphics cursor position to a screen space position relative to its current position. The fg_moverw routine does the same in world space. Each of these routines has two arguments that specify the (x,y) coordinates of the new position. For the screen space routines, the arguments are integer �
Chapter 6: Graphics Fundamentals 101
quantities. For the world space routines, the arguments are floating point
quantities.
You can obtain the screen space coordinates of the graphics cursor
position with the fg_getxpos and fg_getypos routines. These routines have no arguments and respectively return the x and y coordinates of the graphics cursor position as the function value. To obtain the world space coordinates of the graphics cursor position, apply the fg_xworld and fg_yworld functions to the return values of fg_getxpos and fg_getypos.
Solid Lines
Fastgraph includes eight routines for drawing solid lines. All of them
draw lines in the current color value and observe the clipping limits. The fg_draw routine draws a line from the current graphics cursor position to an absolute screen space position, while fg_draww draws a line to an absolute world space position. The fg_drawrel routine draws a line from the current graphics cursor position to a screen space position relative to it. The fg_drawrw routine does the same in world space. You can draw absolute lines in XOR mode with fg_drawx and relative XOR lines with fg_drawrelx, or with their world space counterparts fg_drawxw and fg_drawrxw. XOR lines are often used when drawing cursors (such as cross hairs) or rubberband boxes to insure they are visible against colored backgrounds. Another useful property of XOR lines is that drawing the same line twice restores what was originally beneath the line.
Each of these routines has two arguments that specify the (x,y)
coordinates of the destination position. For the screen space routines, the arguments are integer quantities. For the world space routines, the arguments are floating point quantities. In either case the destination position becomes the new graphics cursor position. This makes it possible to draw connected lines without calling a graphics cursor movement routine between successive calls to a line drawing routine.
Examples 6-2 and 6-3 each draw a pair of crossed lines that divide the
screen into quadrants. Example 6-2 does this using fg_move and fg_draw, while example 6-3 uses fg_moverel and fg_drawrel. Both examples draw the lines in white, the default for color 15 in all graphics video modes.
Example 6-2. Example 6-3.
#include <fastgraf.h> #include <fastgraf.h> void main(void); void main(void);
void main() void main() { { int max_x, max_y; int max_x, max_y; int mid_x, mid_y; int mid_x, mid_y; int new_mode, old_mode; int new_mode, old_mode;
fg_initpm(); fg_initpm(); old_mode = fg_getmode(); old_mode = fg_getmode(); new_mode = fg_automode(); new_mode = fg_automode(); fg_setmode(new_mode); fg_setmode(new_mode); �
102 Fastgraph User's Guide
max_x = fg_getmaxx(); max_x = fg_getmaxx(); max_y = fg_getmaxy(); max_y = fg_getmaxy(); mid_x = max_x / 2; mid_x = max_x / 2; mid_y = max_y / 2; mid_y = max_y / 2;
fg_setcolor(15); fg_setcolor(15); fg_move(mid_x,0); fg_move(mid_x,0); fg_draw(mid_x,max_y); fg_drawrel(0,max_y); fg_move(0,mid_y); fg_moverel(-mid_x,-mid_y); fg_draw(max_x,mid_y); fg_drawrel(max_x,0); fg_waitkey(); fg_waitkey();
fg_setmode(old_mode); fg_setmode(old_mode); fg_reset(); fg_reset(); } }
Examples 6-4 and 6-5 are variations of example 6-2. Example 6-4 uses
world space rather than screen space to draw the crossed lines. Example 6-5 is the same as example 6-2 except it defines a clipping area to restrict drawing to the upper left quadrant of the screen. The clipping suppresses the right half of the horizontal line and the lower half of the vertical line.
Example 6-4. Example 6-5.
#include <fastgraf.h> #include <fastgraf.h> void main(void); void main(void);
void main() void main() { { int new_mode, old_mode; int max_x, max_y; int mid_x, mid_y; fg_initpm(); int new_mode, old_mode; old_mode = fg_getmode(); new_mode = fg_automode(); fg_initpm(); fg_setmode(new_mode); old_mode = fg_getmode(); fg_initw(); new_mode = fg_automode(); fg_setworld(-10.0,10.0,-10.0,10.0); fg_setmode(new_mode);
fg_setcolor(15); max_x = fg_getmaxx(); fg_movew(0.0,10.0); max_y = fg_getmaxy(); fg_draww(0.0,-10.0); mid_x = max_x / 2; fg_movew(-10.0,0.0); mid_y = max_y / 2; fg_draww(10.0,0.0); fg_waitkey(); fg_setclip(0,mid_x,0,mid_y);
fg_setmode(old_mode); fg_setcolor(15); fg_reset(); fg_move(mid_x,0); } fg_draw(mid_x,max_y); fg_move(0,mid_y); fg_draw(max_x,mid_y); fg_waitkey();
fg_setmode(old_mode); fg_reset(); } � Chapter 6: Graphics Fundamentals 103
Dashed Lines
Fastgraph includes four routines for drawing dashed lines. All of them
draw lines in the current color value and observe the clipping limits. The fg_dash routine draws a dashed line from the current graphics cursor position to an absolute screen space position, while fg_dashw draws a dashed line to an absolute world space position. The fg_dashrel routine draws a dashed line from the current graphics cursor position to a screen space position relative to it. The fg_dashrw routine does the same in world space.
Each of these routines has three arguments. The first two specify the
(x,y) coordinates of the destination position. For the screen space routines, these arguments are integer quantities. For the world space routines, these arguments are floating point quantities. The third argument is a 16-bit pattern that defines the appearance of the dashed line. Bits that are set in the pattern produce the visible part of the line, while bits that are zero produce the invisible part. This pattern is repeated as necessary to draw the entire line. For example, the pattern value 3333 hex would produce a dashed line with the first two pixels off, the next two on, the next two off, and so forth. Similarly, the pattern value FFFF hex would produce a solid line.
The destination position passed to any of the dashed line routines
becomes the new graphics cursor position. This makes it possible to draw connected dashed lines without calling a graphics cursor movement routine between successive calls to a line drawing routine.
Example 6-6 draws a pair of crossed dashed lines that divide the screen
into quadrants. It does this using fg_move and fg_dash and draws the lines in white, the default for color 15 in all graphics video modes. The dash pattern for each line is 3333 hex, which alternates two pixels off and on.
Example 6-6.
#include <fastgraf.h> void main(void);
void main() { int max_x, max_y; int mid_x, mid_y; int new_mode, old_mode;
fg_initpm(); old_mode = fg_getmode(); new_mode = fg_automode(); fg_setmode(new_mode);
max_x = fg_getmaxx(); max_y = fg_getmaxy(); mid_x = max_x / 2; mid_y = max_y / 2;
fg_setcolor(15); �
104 Fastgraph User's Guide
fg_move(mid_x,0); fg_dash(mid_x,max_y,0x3333); fg_move(0,mid_y); fg_dash(max_x,mid_y,0x3333); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Polygons
Fastgraph includes routines for drawing filled and unfilled polygons, as
well as a routine for determining if a given point is inside a convex polygon. All the polygon routines observe the clipping limits.
The fg_polygon routine draws an unfilled polygon in screen space. It
requires an array of integer x coordinates as its first argument, and an array of integer y coordinates as its second argument. Each (x,y) coordinate pair from the two arrays is treated as a polygon vertex. In other words, the x coordinate of the first polygon vertex is the first element of the x coordinate array, and the y coordinate of the first vertex is the first element of the y coordinate array. Similarly, the second elements of each array define the second vertex, and so forth. The third argument for fg_polygon is an integer quantity that specifies the number of elements in the two coordinate arrays (that is, the number of polygon vertices).
Another routine, fg_polygonw, draws an unfilled polygon in world space.
The fg_polygonw routine is the same as the fg_polygon routine, except its x and y coordinate arrays must contain floating point values instead of integers.
Polygon drawing begins at the first vertex specified in the coordinate
arrays. The polygon routines then draw a solid line to the second vertex, then to the third vertex, and continue in this manner through the last vertex. If necessary, they then close the polygon by drawing a line connecting the last vertex and the first vertex. Example 6-7 illustrates unfilled polygon drawing using fg_polygon in the EGA monochrome or enhanced modes (modes 15 and 16). The program exits if neither of these video modes are available.
Example 6-7.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define VERTICES 10
int x[] = {200,300,400,400,300,240,160,160,200,210}; int y[] = {100, 80,100,220,320,320,240,200,160,150};
void main() { � Chapter 6: Graphics Fundamentals 105
int old_mode;
fg_initpm(); old_mode = fg_getmode(); if (fg_testmode(16,1)) fg_setmode(16); else if (fg_testmode(15,1)) fg_setmode(15); else { printf("This program requires a 640 x 350 "); printf("EGA graphics mode.\n"); exit(1); }
fg_setcolor(1); fg_polygon(x,y,VERTICES); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
As shown in this example, fg_polygon expects the x and y components
defining the polygon vertices to be in separate arrays. Another routine, fg_polyline, draws an unfilled polygon from polygon vertices in one integer array. With fg_polyline, the first array element is the x component of the first vertex, the second element is the y component of the first vertex, the third element is the x component of the second vertex, and so forth. The first fg_polyline argument is the vertex coordinate array of alternating x and y components, and the second argument specifies the number of vertices. In other respects, fg_polyline is identical to fg_polygon.
An additional feature available with fg_polyline but not fg_polygon is
the ability to specify vertex offsets. The fg_polyoff routine's two integer arguments respectively define offset values that are added to each fg_polyline vertex. This makes it possible to define polygon vertices as relative values, that when combined with the offsets, determine the polygon's absolute position.
Perhaps the most important polygon display routine is fg_polyfill, which
displays a filled convex polygon in screen space (the polygon is filled with pixels of the current color). Its first argument is a vertex array in the same format used by fg_polyline. The next argument is a work array used internally. The size in bytes of the work array must be at least four times the polygon height. The final argument specifies the number of polygon vertices.
Example 6-8 illustrates the use of fg_polyline, fg_polyoff, and
fg_polyfill. The program first draws an unfilled polygon, centered within the left half of the screen. It then draws a filled version of the same polygon, centered within the right half of the screen. In each case, the centering is accomplished by passing appropriate values to fg_polyoff. After waiting for a keystroke, the program establishes a clipping region in the lower right corner and redraws the filled polygon at the same position but in a different color. This of course results in only a portion of the filled polygon being drawn. Like example 6-7, this example requires a 640x350 graphics mode. � 106 Fastgraph User's Guide
Example 6-8.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define VERTICES 10
int xy[] = {200,100, 300, 80, 400,100, 400,220, 300,320, 240,320, 160,240, 160,200, 200,160, 210,150}; int work_array[700];
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); if (fg_testmode(16,1)) fg_setmode(16); else if (fg_testmode(15,1)) fg_setmode(15); else { printf("This program requires a 640 x 350 "); printf("EGA graphics mode.\n"); exit(1); }
fg_setcolor(1); fg_polyoff(-120,-25); fg_polyline(xy,VERTICES); fg_polyoff(200,-25); fg_polyfill(xy,work_array,VERTICES); fg_waitkey();
fg_setcolor(2); fg_setclip(480,639,175,349); fg_polyfill(xy,work_array,VERTICES); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
The fg_polyfill routine fills convex polygons. From Fastgraph's
perspective, a polygon is convex if any horizontal line drawn through the polygon crosses the left edge exactly once and the right edge exactly once (excluding horizontal and zero-length edge segments). Note that this definition includes shapes that are not convex in the traditional sense. In addition, any non-convex polygon can be decomposed into two or more convex polygons. All triangles (that is, three-vertex polygons) are by their nature convex. �
Chapter 6: Graphics Fundamentals 107
The filled convex polygon is a basic tool of three-dimensional computer
graphics. A common practice is to build an image or object from several adjacent or connecting polygons. Such polygons typically overlap at one or more edges. For instance, the coordinates defining the right edge of one polygon may also define the left edge of another polygon immediately to its right. For an overall image to appear correct, its component polygons must fit together correctly. By default, fg_polyfill applies the following rules to handle overlapping polygon edges:
* Points located exactly on non-horizontal edges are drawn only if the polygon's interior is directly to the right.
* Points located exactly on horizontal edges are drawn only if the polygon's interior is directly below them.
* A vertex is drawn only if all lines ending at that point meet the above two conditions.
These three rules insure that no pixel is drawn more than once when filling adjacent polygons. However, this behavior may not be suitable for displaying polygons that are not adjacent, because some or all of the pixels on the polygon's right and bottom edges will be excluded. If this is an issue, you can use fg_polyedge to force fg_polyfill to include all edge pixels. The fg_polyedge routine expects a single integer parameter. If it is zero, fg_polyfill will include all edge pixels when drawing convex polygons. Passing any other value to fg_polyedge restores the default behavior of excluding pixels that meet the criteria described above.
The final Fastgraph routine relating to polygons is fg_inside, which
checks if a specified point lies inside a convex polygon. Its first argument is a vertex array in the same format used by fg_polyline and fg_polyfill. The second argument is the number of vertices in the polygon, while the last two arguments specify the screen space x and y coordinates of the point being tested. The fg_inside routine returns 1 if the point lies inside the polygon and 0 if not. If the vertex array does not define a convex polygon, the return value is undefined. The fg_polyoff offsets are applied to the fg_inside vertex array, but not to the test point.
Circles and Ellipses
Fastgraph includes routines for drawing filled and unfilled circles and
ellipses. Both screen space and world space versions of these routines are available, and all of them observe the clipping limits.
The fg_circle routine draws an unfilled circle in screen space, centered
at the graphics cursor position, using the current color. Its only argument specifies the circle's radius in horizontal screen space units. Another routine, fg_circlew, draws an unfilled circle where the radius is measured in horizontal world space units. The analogous routines for drawing filled circles are fg_circlef and fg_circlefw. All four circle drawing routines leave the graphics cursor position unchanged. � 108 Fastgraph User's Guide
The fg_ellipse routine draws an unfilled ellipse in screen space,
centered at the graphics cursor position, using the current color. The routine requires two arguments that respectively specify the length of its horizontal and vertical semi-axes. In other words, the first argument is the absolute distance from the center of the ellipse to its horizontal extremity, and the second argument is the absolute distance from the center to the vertical extremity. Another routine, fg_ellipsew, draws an unfilled ellipse in world space. The analogous routines for drawing filled ellipses are fg_ellipsef and fg_ellipsfw. All four ellipse drawing routines leave the graphics cursor position unchanged.
Example 6-9 illustrates the use of the fg_circlew and fg_ellipsew
routines. The program first uses fg_automode to propose a graphics video mode and then uses fg_setmode to select that video mode. It then makes color 15 the current color, which by default is white in all color graphics modes and "on" in the monochrome graphics modes. Next, it establishes a 200x200 world space coordinate system. The program then uses fg_ellipsew to draw an ellipse and fg_circlew to draw a circle, both centered at the middle of the screen (which is the origin of our world space coordinate system). The circle has a radius of 1/16 the width of the screen (12.5 horizontal world space units), and the ellipse is horizontally inscribed within the circle.
Example 6-10 illustrates the use of the fg_circle and fg_ellipse
routines. It is functionally identical to example 6-9, but it uses screen space rather than world space coordinates to draw the circle and ellipse. Note the arguments to fg_circle and fg_ellipse are dependent on the maximum x and y coordinates of the selected video mode. If we didn't compute these arguments in this manner, the actual size of the circle and ellipse would be proportional to the pixel resolution of the video mode. No such dependency exists when using world space, but we pay a price for this feature in slightly slower execution speed.
Example 6-9. Example 6-10.
#include <fastgraf.h> #include <fastgraf.h> void main(void); void main(void);
void main() void main() { { int old_mode; int mid_x, mid_y; int old_mode; fg_initpm(); int x, y; old_mode = fg_getmode(); fg_setmode(fg_automode()); fg_initpm(); fg_setcolor(15); old_mode = fg_getmode(); fg_setmode(fg_automode()); fg_initw(); fg_setcolor(15); fg_setworld(-100.0,100.0, -100.0,100.0); mid_x = fg_getmaxx() / 2; mid_y = fg_getmaxy() / 2; fg_movew(0.0,0.0); x = mid_x / 8; fg_ellipsew(12.5,12.5); y = mid_y / 8; fg_circlew(12.5); fg_waitkey(); fg_move(mid_x,mid_y); fg_ellipse(x,y); fg_setmode(old_mode); fg_circle(x); � Chapter 6: Graphics Fundamentals 109
fg_reset(); fg_waitkey(); } fg_setmode(old_mode); fg_reset(); }
Solid Rectangles
Fastgraph includes four routines for drawing solid rectangles, two for
screen space and two for world space, with and without clipping. None of these routines affect the graphics cursor position.
The fg_rect routine draws a solid rectangle in screen space, without
regard to the clipping limits, using the current color. It requires four integer arguments that respectively define the minimum x, maximum x, minimum y, and maximum y screen space coordinates of the rectangle. The minimum coordinates must be less than or equal to the maximum coordinates, or else the results are unpredictable. The fg_clprect routine is identical in all respects to fg_rect, except it observes the clipping limits.
The world space versions of the solid rectangle drawing routines are
fg_rectw and fg_clprectw. Like fg_rect and fg_clprect, they require four arguments that define the extremes of the rectangle, but the arguments are floating point world space coordinates.
You also can use fg_rect in text modes. When used in a text mode, fg_rect
expects its four arguments to be expressed in character space (that is, rows and columns) rather than screen space. This means the four arguments respectively specify the minimum column, maximum column, minimum row, and maximum row of the rectangle. Fastgraph constructs the rectangle by storing the solid block character (ASCII decimal value 219) in each character cell comprising the rectangle. The rectangle is drawn using the current character attribute, but because the solid block character occupies the entire character cell, the background component of the attribute is essentially meaningless.
Example 6-11 demonstrates the use of fg_rect by drawing 200 random-size
rectangles in random colors. The program first uses fg_automode to propose a graphics video mode and then uses the fg_setmode routine to select that video mode. Next, it determines the horizontal and vertical screen resolution for the selected video mode, using fg_getmaxx and fg_getmaxy. The main part of the program is a for loop that generates a random rectangle in each iteration. Inside the loop, the C library function rand is used to generate the extremes of the rectangle. If necessary, the program then exchanges the coordinates to make the minimum coordinates less than or equal to the maximum coordinates. Finally, it again uses rand to generate a random color number between 0 and 15, and then draws the rectangle in that color. After drawing all 200 rectangles, the program restores the original video mode and screen attributes before returning to DOS.
Example 6-11.
#include <fastgraf.h> void main(void); �
110 Fastgraph User's Guide
#define RECTANGLES 200 #define SWAP(a,b,temp) { temp = a; a = b; b = temp; }
void main() { int i; int minx, maxx, miny, maxy; int old_mode; int temp; int xres, yres;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(fg_automode());
xres = fg_getmaxx() + 1; yres = fg_getmaxy() + 1;
for (i = 0; i < RECTANGLES; i++) { minx = rand() % xres; maxx = rand() % xres; miny = rand() % yres; maxy = rand() % yres; if (minx > maxx) SWAP(minx,maxx,temp); if (miny > maxy) SWAP(miny,maxy,temp); fg_setcolor(rand()%16); fg_rect(minx,maxx,miny,maxy); }
fg_setmode(old_mode); fg_reset(); }
Unfilled Rectangles
Fastgraph includes four routines for drawing unfilled rectangles. The
fg_box routine draws an unfilled rectangle in screen space, with regard to the clipping limits, using the current color. The arguments to fg_box are the same as those for fg_rect. The depth of the rectangle's edges is one pixel by default, but you can change the depth by calling fg_boxdepth. The fg_boxdepth routine expects two arguments. The first argument is the width of the rectangle's left and right sides, while the second is the height of its top and bottom sides. Once you call fg_boxdepth, fg_box draws all unfilled rectangles using the depth values specified in the most recent call to fg_boxdepth. The fg_getxbox and fg_getybox functions respectively return the horizontal and vertical box depth settings, as defined in the most recent call to fg_boxdepth. Unlike fg_rect, fg_box has no effect in text video modes. The analogous world space routine is fg_boxw.
Example 6-12 is the same as example 6-11, but it draws unfilled instead
of solid rectangles. The program uses fg_box to draw the each rectangle and fg_boxdepth to define the rectangle depth at three pixels in each direction. �
Chapter 6: Graphics Fundamentals 111
Note that you don't need to call fg_boxdepth for each rectangle if you want
all of them to have the same depth.
Example 6-12.
#include <fastgraf.h> void main(void);
#define RECTANGLES 200 #define SWAP(a,b,temp) { temp = a; a = b; b = temp; }
void main() { int i; int minx, maxx, miny, maxy; int old_mode; int temp; int xres, yres;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(fg_automode()); fg_boxdepth(3,3);
xres = fg_getmaxx() + 1; yres = fg_getmaxy() + 1;
for (i = 0; i < RECTANGLES; i++) { minx = rand() % xres; maxx = rand() % xres; miny = rand() % yres; maxy = rand() % yres; if (minx > maxx) SWAP(minx,maxx,temp); if (miny > maxy) SWAP(miny,maxy,temp); fg_setcolor(rand()%16); fg_box(minx,maxx,miny,maxy); }
fg_setmode(old_mode); fg_reset(); }
The fg_boxx and fg_boxxw routines are screen space and world space
"exclusive or" versions of the box drawing routines. They simplify displaying rubberband boxes (hollow rectangles that move in response to keystrokes or mouse movement) because drawing an object in XOR mode makes it appear, but drawing it again in the same position and in the same color restores what was under the object originally. Given this useful property, here is an outline of what's necessary to draw a rubberband box:
1. Draw the box in its initial position with fg_boxx or fg_boxxw. �
112 Fastgraph User's Guide
2. Wait for a user response that signifies box movement. 3. Use fg_boxx or fg_boxxw to redraw the box in the same position as in step 1. This restores what was there originally. 4. Draw the box in its new position with fg_boxx or fg_boxxw. 5. Repeat steps 2, 3, and 4 until the box is no longer needed.
Example 6-13 shows a simple use of fg_boxx in the 320x200 MCGA/VGA 256-
color mode (mode 19). The program fills the left and right halves of the screen with different colors and then displays an XOR box that overlaps each half. Even though the box is drawn in the same color as the right half, it is still visible because drawing something in an XOR mode (except in color 0) guarantees that it will be visible against its background. After a keystroke, the program redraws the same box, which of course restores what was there in the first place.
Example 6-13.
#include <fastgraf.h> void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(19); fg_setcolor(9); fg_rect(0,159,0,199); fg_setcolor(15); fg_rect(160,319,0,199); fg_waitkey();
fg_boxx(80,239,50,149); fg_waitkey(); fg_boxx(80,239,50,149); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Dithered Rectangles
The process of alternating different color pixels across a region of the
display area is called dithering. This technique is especially useful in the graphics modes with few colors, such as CGA and Hercules modes, because you can simulate additional colors through effective uses of dithering. Fastgraph includes two routines for drawing dithered rectangles, one for screen space �
Chapter 6: Graphics Fundamentals 113
and one for world space. Neither routine observes the clipping limits, nor do
they affect the graphics cursor position.
The fg_drect routine draws a dithered rectangle in screen space. Like the
fg_rect routine, fg_drect requires four integer arguments that respectively define the minimum x, maximum x, minimum y, and maximum y screen space coordinates of the rectangle. The minimum coordinates must be less than or equal to the maximum coordinates, or else the results are unpredictable. However, fg_drect also requires a fifth argument that defines the dithering matrix, which in turn determines the pixel pattern used to build the dithered rectangle. The size and format of the dithering matrix are dependent on the video mode.
The world space version of the dithered rectangle drawing routine is
fg_drectw. Like fg_drect, it requires four arguments that define the extremes of the rectangle, and a fifth argument that defines the dithering matrix.
As mentioned earlier, the size and format of the dithering matrix are
dependent on the video mode. The dithering matrix is a four-byte array in all video modes except the 256 color graphics modes (modes 19 through 27), where it is an eight-byte array. This array contains a pixel pattern that fg_drect or fg_drectw replicates across the rectangle's area. The structure of the dithering matrix closely mimics the structure of video memory in each graphics mode.
The remainder of this section will present some simple mode-specific
examples to illustrate the structure of the dithering matrix in the different graphics modes. Suppose we would like to produce a "checkerboard" of light blue and white pixels. That is, in a given row of a rectangle, consecutive pixels will alternate between these two colors. Additionally, the pattern for adjacent rows will be shifted so there will always be a white pixel above and below a light blue pixel, and vice versa. Hence this pixel pattern would look something like
B W B W W B W B B W B W W B W B
where each B represents a light blue pixel, and each W represents a white pixel. The following examples describe the dithering matrix that could be used to produce such a pixel pattern in each graphics mode.
CGA Four-Color Graphics Modes
The CGA four-color graphics modes (modes 4 and 5) use a four-byte
dithering matrix that Fastgraph treats as a four-row by one-column array. Since each pixel in these modes requires two bits of video memory, each byte of the dithering matrix holds four pixels. Thus, the pixel representation of the dithering matrix would appear as shown on the left; its translation to numeric values appears on the right.
[3] B W B W [3] 01 11 01 11
[2] W B W B [2] 11 01 11 01 �
114 Fastgraph User's Guide
[1] B W B W [1] 01 11 01 11
[0] W B W B [0] 11 01 11 01
Because these modes do not offer a light blue color, we've used light cyan
(color value 1 in palette 1) to approximate light blue. The B pixels thus
translate to color value 1, or 01 binary. White is available as color value 3
in palette 1, so the W pixels translate to color value 3, or 11 binary. The
hexadecimal equivalent of the binary value 11011101 (for array elements [0]
and [2]) is DD, and the hexadecimal equivalent of the binary value 01110111
(for array elements [1] and [3]) is 77. As shown in example 6-12, these are
precisely the values assigned to the elements of the dithering matrix.
Example 6-14 uses mode 4 to display a 50-pixel by 50-pixel dithered
rectangle in the upper left corner of the screen. The dithering matrix represents the blue and white checkerboard pattern discussed in the preceding paragraph.
Example 6-14.
#include <fastgraf.h> void main(void);
void main() { char matrix[4]; int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(4);
matrix[0] = matrix[2] = 0xDD; matrix[1] = matrix[3] = 0x77; fg_drect(0,49,0,49,matrix); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
CGA Two-Color Graphics Mode
The CGA two-color graphics mode (mode 6) uses a four-byte dithering
matrix that Fastgraph treats as a four-row by one-column array, as in the other four-color CGA modes. However, each pixel in this mode only requires one bit of video memory, so each byte of the dithering matrix holds eight pixels. Thus, the pixel representation of the dithering matrix would appear as shown on the left; its translation to numeric values appears on the right.
[3] B W B W B W B W [3] 0 1 0 1 0 1 0 1 � Chapter 6: Graphics Fundamentals 115
[2] W B W B W B W B [2] 1 0 1 0 1 0 1 0
[1] B W B W B W B W [1] 0 1 0 1 0 1 0 1
[0] W B W B W B W B [0] 1 0 1 0 1 0 1 0
Mode 6 obviously does not offer a light blue color, so we've used black (color
value 0) in its place. The B pixels thus translate to color value 0. White is
available as color value 1, so the W pixels translate to color value 1. The
hexadecimal equivalent of the binary value 10101010 (for array elements [0]
and [2]) is AA, and the hexadecimal equivalent of the binary value 01010101
(for array elements [1] and [3]) is 55. Thus, to make example 6-14 run in mode
6, we only need to change the fg_setmode argument from 4 to 6 and change the
dithering matrix values as shown here:
matrix[0] = matrix[2] = 0xAA; matrix[1] = matrix[3] = 0x55;
Tandy/PCjr 16-Color Graphics Mode
The Tandy/PCjr 16-color graphics mode (mode 9) also uses a four-byte
dithering matrix that Fastgraph treats as a four-row by one-column array. Each pixel in this mode requires four bits of video memory, so each byte of the dithering matrix only holds two pixels. Thus, the pixel representation of the dithering matrix would appear as shown on the left; its translation to numeric values appears on the right.
[3] B W [3] 1001 1111
[2] W B [2] 1111 1001
[1] B W [1] 1001 1111
[0] W B [0] 1111 1001
The B pixels translate to color value 9 (light blue), or 1001 binary, and the
W pixels translate to color value 15 (white), or 1111 binary. The hexadecimal
equivalent of the binary value 11111001 (for array elements [0] and [2]) is
F9, and the hexadecimal equivalent of the binary value 10011111 (for array
elements [1] and [3]) is 9F. Thus, to make example 6-14 run in mode 9, we only
need to change the fg_setmode argument from 4 to 9 and change the dithering
matrix values as shown here:
matrix[0] = matrix[2] = 0xF9; matrix[1] = matrix[3] = 0x9F; �
116 Fastgraph User's Guide
Hercules Graphics Mode
The size and format of the dithering matrix in the Hercules graphics mode
(mode 11) are the same as in the CGA two-color mode (mode 6).
Hercules Low-Resolution Graphics Mode
The size and format of the dithering matrix in the Hercules low-
resolution graphics mode (mode 12) are the same as in the CGA four-color modes (modes 4 and 5). As far as our checkerboard example goes, we'll use black (color value 0) in place of light blue, and bold (color value 3) instead of white. Thus, the B pixels translate to 00 binary, while the W pixels translate to 11 binary. The hexadecimal equivalent of the binary value 11001100 (for array elements [0] and [2]) is CC, and the hexadecimal equivalent of the binary value 00110011 (for array elements [1] and [3]) is 33. Thus, to make example 6-14 run in mode 12, we only need to change the fg_setmode argument from 4 to 12 and change the dithering matrix values as shown here:
matrix[0] = matrix[2] = 0xCC; matrix[1] = matrix[3] = 0x33;
EGA/VGA/SVGA 16-Color Graphics Modes
The EGA/VGA/SVGA 16-color graphics modes (modes 13 through 18, 28, and
29) use a four-byte dithering matrix that Fastgraph treats as a four-row by one-column array. Unlike the other graphics modes, which allow you to store pixels of several colors in the dithering matrix, these modes treat the dithering matrix as a bitmap for a specific color. Since each color in the dither pattern must be stored in a separate bitmap (that is, in a separate dithering matrix), you must call fg_drect once for each color. Furthermore, you must use fg_setcolor before each call to fg_drect to define the color used with the dithering matrix.
In all EGA/VGA/SVGA graphics modes, each byte of the dithering matrix is
a bitmap that represents eight pixels. Using our familiar checkerboard example, the pixel representation of the dithering matrix would appear as shown here:
[3] B W B W B W B W
[2] W B W B W B W B
[1] B W B W B W B W
[0] W B W B W B W B
Translating this pattern to numeric values is simple. Just construct one
dithering matrix for each color in the pattern (there are two colors in this
example), where pixels of the current color translate to 1, and other pixels
translate to 0. Following our example, the translation for the B pixels
appears below on the left, while the translation for the W pixels appears on
the right. �
Chapter 6: Graphics Fundamentals 117
[3] 1 0 1 0 1 0 1 0 [3] 0 1 0 1 0 1 0 1
[2] 0 1 0 1 0 1 0 1 [2] 1 0 1 0 1 0 1 0
[1] 1 0 1 0 1 0 1 0 [1] 0 1 0 1 0 1 0 1
[0] 0 1 0 1 0 1 0 1 [0] 1 0 1 0 1 0 1 0
The hexadecimal equivalent of the binary value 01010101 is 55, and the
hexadecimal equivalent of the binary value 10101010 is AA. As shown in example
6-15, these are precisely the values assigned to the elements of the dithering
matrices.
Example 6-15 uses mode 13 to display our light blue and white
checkerboard pattern. Note you must call fg_drect twice -- once for the light blue pixels (color value 9), and again for the white pixels (color value 15). Note also how fg_setcolor is used before each call to fg_drect to define the color of the pixels fg_drect will display.
Example 6-15.
#include <fastgraf.h> void main(void);
void main() { char matrix[4]; int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(13);
matrix[0] = matrix[2] = 0x55; matrix[1] = matrix[3] = 0xAA; fg_setcolor(9); fg_drect(0,49,0,49,matrix);
matrix[0] = matrix[2] = 0xAA; matrix[1] = matrix[3] = 0x55; fg_setcolor(15); fg_drect(0,49,0,49,matrix); fg_waitkey();
fg_setmode(old_mode); fg_reset(); } �
118 Fastgraph User's Guide
256-Color Graphics Modes
The 256-color graphics modes (modes 19 through 27) use an eight-byte
dithering matrix that Fastgraph treats as a four-row by two-column array. Each pixel in these modes requires eight bits of video memory, so each byte of the dithering matrix only holds a single pixel. We therefore need the two column dithering matrix to produce a meaningful dither pattern. The pixel representation of the dithering matrix would appear as shown on the left; its translation to numeric values appears on the right.
[6] B W [7] [6] 9 15 [7]
[4] W B [5] [4] 15 9 [5]
[2] B W [3] [2] 9 15 [3]
[0] W B [1] [0] 15 9 [1]
The B pixels translate to color value 9 (light blue), and the W pixels
translate to color value 15 (white). Example 6-16 uses mode 19 to draw our
light blue and white checkerboard pattern.
Example 6-16.
#include <fastgraf.h> void main(void);
void main() { char matrix[8]; int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(19);
matrix[0] = matrix[3] = matrix[4] = matrix[7] = 15; matrix[1] = matrix[2] = matrix[5] = matrix[6] = 9; fg_drect(0,49,0,49,matrix); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Closing Remarks
There are two other important items pertaining to fg_drect and fg_drectw.
These items apply regardless of which graphics video mode is being used.
First, the dithering matrix may not contain virtual color values. That
is, the pixel color values stored in the dithering matrix must be between 0 and the maximum color value for the current video mode. If any color value is �
Chapter 6: Graphics Fundamentals 119
redefined using fg_defcolor, Fastgraph always ignores the redefinition and
instead uses the actual color value. Note this does not apply to palette
registers or video DAC registers, because in these cases we're redefining the
color associated with a color value and not the color value itself.
Second, Fastgraph aligns the dithering matrix to specific pixel rows.
Fastgraph draws the dithered rectangle starting with the pixel row specified by the rectangle's lower limit (the maximum y coordinate for fg_drect, or the minimum y coordinate for fg_drectw) and proceeds upward until reaching the rectangle's upper limit. In all cases the dithering matrix used by fg_drect and fg_drectw contains four rows. If we let r represent the pixel row corresponding to the rectangle's lower limit, then the first row used in the dithering matrix is r modulo 4 (assuming the dithering matrix rows are numbered 0 to 3). This alignment enables you to use the same dithering matrix in multiple calls to fg_drect and fg_drectw for building an object of adjacent dithered rectangles (for example, an L-shaped area) and still have the dither pattern match where the rectangles intersect.
Region Fill
Fastgraph includes routines for filling arbitrary regions. The fg_flood
and fg_paint routines fill a region with the current color value by specifying a screen space point in the region's interior. The fg_floodw and fg_paintw routine also fill a region, but they require the interior point to be expressed in world space. All region fill routines have two arguments that specify the (x,y) coordinates of the interior point. For fg_flood and fg_paint, the arguments are integer quantities. For fg_floodw and fg_paintw, they are floating point quantities. None of them change the graphics cursor position. The difference between the "flood" and "paint" versions of these routines is simple: fg_flood and fg_floodw will not extend the region fill beyond the clipping limits, while fg_paint and fg_paintw ignore the clipping limits. As a result, fg_paint and fg_paintw are significantly faster.
The region being filled must be a closed polygon whose boundary color is
different from that of the specified interior point. The region may contain holes (interior areas that will not be filled). Fastgraph fills the region by changing every interior pixel whose color is the same as the specified interior point, to the current color. If the interior point is already the current color, the region fill routines do nothing. It is important to note fg_paint and fg_paintw do not treat the screen edges as polygon boundaries. Filling an open polygon will cause these routines to behave unpredictably. This is not the case with fg_flood and fg_floodw as long as the clipping limits are not beyond the screen edges.
Example 6-17 illustrates a simple use of fg_paint in a 320x200 graphics
mode. The program uses fg_bestmode to select an available video mode (if no 320x200 graphics mode is available, the program exits). After establishing the selected video mode, the program uses fg_move and fg_drawrel to draw a hollow rectangle in color 10 and a hollow diamond in color 9. The diamond is drawn in the middle of the rectangle, thus making it a hole with respect to the rectangle. The program leaves these shapes on the screen until a key is pressed. It then calls fg_paint to fill that part of the rectangle outside the diamond with color 10. After waiting for another keystroke, the program again uses fg_paint to fill the interior of the diamond with color 15. Finally, the � 120 Fastgraph User's Guide
program waits for another keystroke, restores the original video mode and
screen attributes, and returns to DOS.
Example 6-17.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0) { printf("This program requires a 320 x 200 "); printf("graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(10); fg_move(100,50); fg_drawrel(120,0); fg_drawrel(0,100); fg_drawrel(-120,0); fg_drawrel(0,-100);
fg_setcolor(9); fg_move(160,80); fg_drawrel(30,20); fg_drawrel(-30,20); fg_drawrel(-30,-20); fg_drawrel(30,-20); fg_waitkey();
fg_setcolor(10); fg_paint(160,70); fg_waitkey();
fg_setcolor(15); fg_paint(160,100); fg_waitkey();
fg_setmode(old_mode); fg_reset(); } � Chapter 6: Graphics Fundamentals 121
Summary of Fundamental Graphics Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_BOX draws an unfilled rectangle in screen space, with respect to the
clipping region. The width of the rectangle's edges is one pixel unless changed with the fg_boxdepth routine.
FG_BOXDEPTH defines the depth of rectangles drawn with the box display
routines. The fg_setmode routine initializes the box depth to one pixel.
FG_BOXW draws an unfilled rectangle in world space, with respect to the
clipping region. The width of the rectangle's edges is one pixel unless changed with the fg_boxdepth routine.
FG_BOXX draws an unfilled rectangle in screen space, with respect to the
clipping region, in "exclusive or" mode. The width of the rectangle's edges is one pixel unless changed with the fg_boxdepth routine.
FG_BOXXW draws an unfilled rectangle in world space, with respect to the
clipping region, in "exclusive or" mode. The width of the rectangle's edges is one pixel unless changed with the fg_boxdepth routine.
FG_CIRCLE draws an unfilled circle in screen space. The circle is
centered at the graphics cursor position.
FG_CIRCLEF draws a filled circle in screen space. The circle is centered
at the graphics cursor position.
FG_CIRCLEFW draws a filled circle in world space. The circle is centered
at the graphics cursor position.
FG_CIRCLEW draws an unfilled circle in world space. The circle is
centered at the graphics cursor position.
FG_CLPRECT draws a solid (filled) rectangle in screen space, with respect
to the clipping region.
FG_CLPRECTW draws a solid (filled) rectangle in world space, with respect
to the clipping region.
FG_DASH draws a dashed line from the graphics cursor position to an
absolute screen space position. It also makes the destination position the new graphics cursor position.
FG_DASHREL draws a dashed line from the graphics cursor position to a
screen space position relative to it. It also makes the destination position the new graphics cursor position.
FG_DASHRW draws a dashed line from the graphics cursor position to a
world space position relative to it. It also makes the destination position the new graphics cursor position. � 122 Fastgraph User's Guide
FG_DASHW draws a dashed line from the graphics cursor position to an
absolute world space position. It also makes the destination position the new graphics cursor position.
FG_DRAW draws a solid line from the graphics cursor position to an
absolute screen space position. It also makes the destination position the new graphics cursor position.
FG_DRAWREL draws a solid line from the graphics cursor position to a
screen space position relative to it. It also makes the destination position the new graphics cursor position.
FG_DRAWRELX draws a solid line in "exclusive or" mode from the graphics
cursor position to a screen space position relative to it. It also makes the destination position the new graphics cursor position.
FG_DRAWRW draws a solid line from the graphics cursor position to a world
space position relative to it. It also makes the destination position the new graphics cursor position.
FG_DRAWRXW draws a solid line in "exclusive or" mode from the graphics
cursor position to a world space position relative to it. It also makes the destination position the new graphics cursor position.
FG_DRAWW draws a solid line from the graphics cursor position to an
absolute world space position. It also makes the destination position the new graphics cursor position.
FG_DRAWX draws a solid line in "exclusive or" mode from the graphics
cursor position to an absolute screen space position. It also makes the destination position the new graphics cursor position.
FG_DRAWXW draws a solid line in "exclusive or" mode from the graphics
cursor position to an absolute world space position. It also makes the destination position the new graphics cursor position.
FG_DRECT draws a dithered rectangle in screen space, without regard to
the clipping region. The rectangle's dither pattern is defined through a dithering matrix whose format is dependent on the video mode being used.
FG_DRECTW draws a dithered rectangle in world space, without regard to
the clipping region. The rectangle's dither pattern is defined through a dithering matrix whose format is dependent on the video mode being used.
FG_ELLIPSE draws an unfilled ellipse in screen space. The ellipse is
centered at the graphics cursor position, and its size is determined by the specified lengths of the semi-axes.
FG_ELLIPSEF draws a filled ellipse in screen space. The ellipse is
centered at the graphics cursor position, and its size is determined by the specified lengths of the semi-axes.
FG_ELLIPSEW draws an unfilled ellipse in world space. The ellipse is
centered at the graphics cursor position, and its size is determined by the specified lengths of the semi-axes. �
Chapter 6: Graphics Fundamentals 123
FG_ELLIPSFW draws a filled ellipse in world space. The ellipse is
centered at the graphics cursor position, and its size is determined by the specified lengths of the semi-axes.
FG_ERASE clears the screen in either text or graphics modes.
FG_FILLPAGE fills the screen with the current color in either text or
graphics modes.
FG_FLOOD fills an arbitrary closed region with the current color value,
with respect to the clipping limits. The region is defined by specifying a screen space point within its interior.
FG_FLOODW fills an arbitrary closed region with the current color value,
with respect to the clipping limits. The region is defined by specifying a world space point within its interior.
FG_GETCLIP returns the current clipping limits, as defined in the most
recent call to fg_setclip.
FG_GETPIXEL returns the color value of a specified pixel.
FG_GETXBOX returns the width in pixels for the left and right edges of
hollow rectangles drawn with Fastgraph's box display routines.
FG_GETXPOS returns the screen space x coordinate of the graphics cursor
position.
FG_GETYBOX returns the width in pixels for the top and bottom edges of
hollow rectangles drawn with Fastgraph's box display routines.
FG_GETYPOS returns the screen space y coordinate of the graphics cursor
position.
FG_INSIDE determines if the specified point is inside a given convex
polygon.
FG_MOVE establishes the graphics cursor position at an absolute screen
space point.
FG_MOVEREL establishes the graphics cursor position at a screen space
point relative to the current position.
FG_MOVERW establishes the graphics cursor position at a world space point
relative to the current position.
FG_MOVEW establishes the graphics cursor position at an absolute world
space point.
FG_PAINT fills an arbitrary closed region with the current color value,
without respect to the clipping limits. The region is defined by specifying a screen space point within its interior. � 124 Fastgraph User's Guide
FG_PAINTW fills an arbitrary closed region with the current color value,
without respect to the clipping limits. The region is defined by specifying a world space point within its interior.
FG_POINT draws a point (that is, displays a pixel) in screen space.
FG_POINTW draws a point in world space.
FG_POINTX draws a point in "exclusive or" mode in screen space.
FG_POINTXW draws a point in "exclusive or" mode in world space.
FG_POLYEDGE defines whether or not fg_polyfill includes all pixels lying
on a polygon's right and bottom edges when drawing filled convex polygons.
FG_POLYFILL draws a filled convex polygon in screen space. The polygon is
closed if necessary. By default, pixels lying on the polygon's right and bottom edges are not included when drawing the polygon. This behavior can be changed with fg_polyedge.
FG_POLYGON draws an unfilled polygon in screen space, using two
coordinate arrays to define the polygon vertices. The polygon is closed if necessary.
FG_POLYGONW draws an unfilled polygon in world space. It is the same as
fg_polygon, except the coordinate arrays contain world space values.
FG_POLYLINE draws an unfilled polygon in screen space, using a single
coordinate array to define the polygon vertices. The polygon is closed if necessary.
FG_POLYOFF defines the screen space offset applied to each vertex for
polygons drawn with fg_polyfill or fg_polyline.
FG_RECT draws a solid (filled) rectangle in screen space or character
space, without regard to the clipping region.
FG_RECTW draws a solid (filled) rectangle in world space, without regard
to the clipping region.
FG_SETCLIP defines the clipping region in screen space. The clipping
region is a rectangular area outside of which certain graphics are suppressed.
FG_SETCLIPW defines the clipping region in world space.
Chapter 7
Character Display Routines � 126 Fastgraph User's Guide
Overview
An important part of any program is the capability to display text or
other characters on the screen. Fastgraph supports two character sets: the hardware or BIOS character set available with each video mode, and Fastgraph's own software character set for graphics video modes. Fastgraph/Light does not support the software character set.
We'll begin this chapter with a review of character space, and then
discuss the specifics about hardware and software characters. At the end of the chapter, we'll briefly explain how to implement bitmapped characters into a program. To simplify matters, the example programs presented in this chapter are mode-specific examples, and no testing is done to check if the video mode is available on the user's system.
Character Space
The coordinate system used for displaying hardware characters is called
character space. It is the only coordinate system available in text video modes, but it is a supplementary coordinate system you can use with either screen space or world space in graphics video modes. Character space can be thought of as a grid of rows and columns, with each cell in the grid holding one character. Each cell is identified by its unique (row,column) integer coordinates. The rows and columns are numbered starting at zero; the origin is always the upper left corner of the screen. For example, in the 80-column by 25-row video modes, the (row,column) coordinates of the screen corners are shown in the following diagram.
(0,0) (0,79)
(24,0) (24,79)
The default number of rows and columns depends on the video mode, as shown in
the following table. For graphics modes, the table also includes the default
width and height in pixels of a character cell.
Mode No. of No. of Char. Char. Number Columns Rows WidthHeight
0 40 25 1 40 25 2 80 25 3 80 25 4 40 25 8 8 5 40 25 8 8 6 80 25 8 8 7 80 25 9 40 25 8 8 11 80 25 9 14 12 40 25 8 8 � Chapter 7: Character Display Routines 127
13 40 25 8 8 14 80 25 8 8 15 80 25 8 14 16 80 25 8 14 17 80 30 8 16 18 80 30 8 16 19 40 25 8 8 20 40 25 8 8 21 40 50 8 8 22 40 30 8 8 23 40 60 8 8 24 80 25 8 16 25 80 30 8 16 26 100 37 8 16 27 128 48 8 16 28 100 37 8 16 29 128 48 8 16
Hardware Characters
Hardware characters are available in all supported video modes. As
explained in Chapter 5, text mode characters have a display attribute that defines their foreground color, their background color, and whether or not they blink. Graphics mode characters appear in a single color, as determined by the current color index. Chapter 5 also explained how Fastgraph's fg_setattr and fg_setcolor routines define the attribute or color index in which subsequent hardware characters appear.
It is obviously important to define the color or attribute for hardware
characters, but it is equally important to define their location on the screen. Fastgraph draws hardware characters at the position defined by the text cursor. Like the graphics cursor, the text cursor is not a cursor in the true sense, but is simply a pair of character space (row,column) coordinates with a special meaning. The fg_setmode routine sets the text cursor position to the character space coordinates (0,0), which of course is the upper left corner of the screen.2
The Fastgraph routine fg_locate changes the text cursor position. It has
two integer arguments that specify the (row,column) character space coordinates of the new position. The row values must be between 0 and one less than the number of character rows available. The column values must be between 0 and one less than the number of character columns available.
The fg_text routine is Fastgraph's basic character display routine. It
displays a string of hardware characters, starting at the text cursor position, using the current color attribute (for text modes) or color index (for graphics modes). If the string reaches the last column in a row, fg_text will wrap the string to the first column of the next row. Additionally, fg_text leaves the cursor one column to the right of the last character displayed (or the first column of the next row if the last character appears ____________________
(2) In reality there are eight text cursors, one for each video page. The
fg_setmode routine initializes each text cursor position to (0,0). The next chapter describes this in more detail. � 128 Fastgraph User's Guide
at the end of a row). This feature makes it possible for successive calls to
fg_text to display adjacent strings. The first argument for the fg_text
routine is a character string of arbitrary length, and the second argument is
an integer value that specifies the number of characters to display from that
string.
Example 7-1 illustrates the use of fg_locate and fg_text in the 80x25
color text mode (mode 3). After establishing the video mode and making the BIOS cursor invisible, the program displays four strings with different attributes. The attributes are selected using fg_setattr, and the strings are displayed by fg_text. The first string appears in yellow (attributes 14,0,0) in the upper left corner of the screen; fg_locate is not necessary because (0,0) is the default text cursor position established by fg_setmode. The second string appears in light green (10,0,0) one space to the right of the first string. Its position relies on the fact fg_text leaves the text cursor positioned one space to the right of the last character displayed (following the "w" of "yellow" in this case). The leading space in " green" leaves a space between the first and second strings. Similarly, the third string appears in blinking light red (12,0,1) one space to the right of the second string.
The program then uses fg_locate to move the text cursor to the lower left
corner of the screen and displays the "Press any key" string. This string is displayed with a light red foreground against a gray background (12,7,0). The extra spaces surrounding the string extend the background color one character position to the left and right and make the string more visually appealing. Finally, once you press any key, the program restores the original video mode and screen attributes before returning to DOS.
Example 7-1.
#include <fastgraf.h> void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(3); fg_cursor(0);
fg_setattr(14,0,0); fg_text("yellow",6);
fg_setattr(10,0,0); fg_text(" green",6);
fg_setattr(12,0,1); fg_text(" blinking",9);
fg_setattr(12,7,0); fg_locate(24,0); fg_text(" Press any key. ",16); fg_waitkey(); � Chapter 7: Character Display Routines 129
fg_setmode(old_mode); fg_reset(); }
The fg_where routine retrieves the text cursor position in its two
integer arguments. This routine is not used as frequently as fg_locate and fg_text because more often than not your program will know the text cursor position implicitly, or you'll know in advance the locations at which text will be displayed. The fg_where routine takes two integer arguments passed by reference, and these two arguments respectively receive the text cursor's current row and column position.
Example 7-2 produces the same results as example 7-1, but it does so a
bit differently. It uses its own routine, put_string, to display a string at a specified row and column. The put_string routine simply calls fg_locate to establish the text cursor position and then calls fg_text to display the string. Note the use of the C library function strlen to determine the string length passed to fg_text. Example 7-2 also uses fg_where to retrieve the new text cursor positions, which are then passed to put_string.
Example 7-2.
#include <fastgraf.h> #include <string.h> void main(void); void put_string(char*,int,int);
void main() { int old_mode; int row, column;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(3); fg_cursor(0);
fg_setattr(14,0,0); put_string("yellow",0,0);
fg_setattr(10,0,0); fg_where(&row,&column); put_string("green",row,column+1);
fg_setattr(12,0,1); fg_where(&row,&column); put_string("blinking",row,column+1);
fg_setattr(12,7,0); put_string(" Press any key. ",24,0); fg_waitkey();
fg_setmode(old_mode); fg_reset(); �
130 Fastgraph User's Guide
}
void put_string(string,row,column) char *string; int row, column; { fg_locate(row,column); fg_text(string,strlen(string)); }
Sometimes you may wish to change the display attribute of existing text,
such as when creating a shadow around the edges of a pop-up window. The Fastgraph routine fg_chgattr performs this function. It applies the current text display attribute (as defined in the most recent call to fg_setattr or fg_setcolor) to a given number of characters, starting at the text cursor position. It leaves the text cursor one column to the right of the last character changed (or the first column of the next row if the last character is at the end of a row). The fg_chgattr routine's argument specifies the number of characters to change. This routine has no effect in graphics video modes.
The Fastgraph routine fg_chgtext performs somewhat the opposite function
of fg_chgattr. It displays new text but uses the display attributes already assigned to the character cells where the text will appear. The fg_chgtext routine takes the same two arguments as fg_text, displays the characters starting at the text cursor position, and leaves the cursor one column to the right of the last character displayed. Like fg_chgattr, fg_chgtext has no effect in graphics video modes.
Example 7-3 illustrates the fg_chgattr and fg_chgtext routines. It runs
in the 80-column color text mode (mode 3), but if we change the fg_setmode argument it also would run in the monochrome text mode (mode 7). The program first displays the word "hello" in the upper left corner of the screen, using a gray foreground and black background attribute. After waiting for a keystroke, the program calls fg_chgattr to make the word "hello" appear in reverse video (that is, a black foreground and gray background attribute). After a second keystroke, the program uses fg_chgtext to change the "h" of "hello" to upper case. Following this, the program returns to DOS.
Example 7-3.
#include <fastgraf.h> void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(3); fg_cursor(0);
fg_setattr(7,0,0); fg_text("hello",5); � Chapter 7: Character Display Routines 131
fg_waitkey();
fg_locate(0,0); fg_setattr(0,7,0); fg_chgattr(5); fg_waitkey();
fg_locate(0,0); fg_chgtext("H",1); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
You also can retrieve the character or attribute stored in a specific
character cell. The Fastgraph routine fg_getchar retrieves character values, while fg_getattr retrieves character attributes. Both routines have two integer arguments that specify the (row,column) coordinates for the character cell of interest. Example 7-4 uses fg_getchar and fg_getattr to read the character and attribute stored at row 24, column 0. Just before the program exits, it displays these values.
Example 7-4.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int attr, value; int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(3); fg_cursor(0);
fg_setattr(9,7,0); fg_locate(24,0); fg_text("Test",4); value = fg_getchar(24,0); attr = fg_getattr(24,0); fg_waitkey();
fg_setmode(old_mode); fg_reset(); printf("%c %2.2X\n",value,attr); }
If you need to retrieve characters and attributes from a rectangular
area, it's more efficient to use the fg_getimage routine (described in Chapter 10) than to call fg_getchar and fg_getattr repeatedly. � 132 Fastgraph User's Guide
Displaying hardware characters in graphics video modes is different from
doing so in text modes. Like text modes, we can still use fg_text to display strings in character space, which of course restricts the places where strings can appear. Graphics modes offer the ability to display strings relative to any pixel, not just character cells. The fg_print and fg_justify routines are provided for this purpose. To compare the two methods of displaying strings in graphics modes, let's begin with an example of doing so with fg_text.
Example 7-5 is similar to example 7-1, but it runs in the EGA enhanced
graphics mode (mode 16) instead of a text mode. In graphics modes, fg_cursor has no effect, so we have omitted it from the program. Furthermore, characters cannot be displayed with a blinking attribute, so we have omitted the blinking characters (we could simulate blinking by repetitively displaying and erasing them, but that is beyond the scope of this example). Because graphics mode characters only have a foreground color, we had to simulate the gray background of the "Press any key" string by first drawing a rectangle where that string appears. The differences between examples 7-5 and 7-1 hold for any graphics video mode, not just mode 16.
Example 7-5.
#include <fastgraf.h> void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(16);
fg_setcolor(14); fg_text("yellow",6);
fg_setcolor(10); fg_text(" green",6);
fg_setcolor(7); fg_rect(0,127,336,349); fg_setcolor(12); fg_locate(24,0); fg_text(" Press any key. ",16); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Now let's show how to display graphics mode strings using the more
flexible screen space coordinate system. The fg_print routine is identical to fg_text, but it displays a string relative to the graphics cursor position (that is, in screen space) rather than the character space position established with fg_locate. By default, fg_print displays strings so their �
Chapter 7: Character Display Routines 133
lower left corner is at the graphics cursor position. The fg_justify routine
lets you change this default justification. Its two parameters, xjust and
yjust, control the string positioning about the current graphics position, as
summarized in the following table:
value of value of horizontal vertical xjust yjust justification justification
-1 -1 left lower -1 0 left center -1 1 left upper 0 -1 center lower 0 0 center center 0 1 center upper 1 -1 right lower 1 0 right center 1 1 right upper
Any other justification values produce undefined results. In the context of vertical justification, lower justification means the bottom of each character will be at the current graphics y position. Upper justification means the top of each character will be at the graphics y position, while center justification means characters will be centered about the graphics y position. The default justification settings (established by fg_setmode) are xjust = -1 and yjust = -1, and you can retrieve the current justification settings with Fastgraph's fg_getxjust and fg_getyjust functions. Like fg_text, fg_print leaves the graphics cursor positioned just beyond the bottom right corner of the last character displayed.
Neither fg_print nor fg_text performs clipping. There may be times,
however, when displaying clipped strings is desirable, such as when displaying text inside a fixed window. When clipping is needed, use fg_printc or fg_textc for displaying strings. These two routines are identical in all respects to fg_print and fg_text, but they do not display characters lying outside the clipping region established by fg_setclip or fg_setclipw. Further, if part of a character is outside the clipping region, fg_printc and fg_textc display only that part of the character that falls within the clipping region. Because clipping is supported only in graphics video modes, fg_textc is equivalent to fg_text when used in text video modes.
Example 7-6 illustrates the use of fg_print and fg_justify to display
justified text in the VGA 640x480 16-color graphics mode (mode 18). The first series of calls to fg_move, fg_justify, and fg_print display the string "Fastgraph" left justified, centered, and right justified against the top row of the screen. The second series of such calls also displays the string in these positions, but each is centered vertically in the middle of the screen. The final series displays the strings against the bottom row of the screen. The nine calls to fg_justify in example 7-6 represent all possible justification settings for strings displayed with fg_print.
Example 7-6.
#include <fastgraf.h> void main(void);
void main() �
134 Fastgraph User's Guide
{ int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(18); fg_setcolor(9); fg_fillpage(); fg_setcolor(14);
fg_move(0,0); fg_justify(-1,1); fg_print("Fastgraph",9); fg_move(320,0); fg_justify(0,1); fg_print("Fastgraph",9); fg_move(639,0); fg_justify(1,1); fg_print("Fastgraph",9);
fg_move(0,240); fg_justify(-1,0); fg_print("Fastgraph",9); fg_move(320,240); fg_justify(0,0); fg_print("Fastgraph",9); fg_move(639,240); fg_justify(1,0); fg_print("Fastgraph",9);
fg_move(0,479); fg_justify(-1,-1); fg_print("Fastgraph",9); fg_move(320,479); fg_justify(0,-1); fg_print("Fastgraph",9); fg_move(639,479); fg_justify(1,-1); fg_print("Fastgraph",9); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Example 7-7 demonstrates a side effect that occurs when displaying
characters in graphics modes. This example uses the MCGA graphics mode (mode 19) and displays two character strings at the same location. If we were to do this in a text mode, the first string would disappear once we displayed the second string (assuming the second string isn't shorter than the first). In graphics modes, however, the portions of the first string not covered by characters from the second string are still visible. The reason for this may not be clear at first, but remember when we display characters in graphics modes, we aren't really displaying characters but merely a pixel representation of the characters. Fastgraph has no way to distinguish such �
Chapter 7: Character Display Routines 135
pixels from any other pixels, no matter what routine we use for string
display.
Example 7-7.
#include <fastgraf.h> void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(19);
fg_setcolor(14); fg_text("yellow",6); fg_locate(0,0); fg_setcolor(10); fg_text(" green",6); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
To avoid this problem, the recommended procedure for displaying
characters in graphics modes is to first erase the area where the text will appear. The easiest way to do this is to use fg_rect to draw a rectangle in the background color. In example 7-7, we could do this by inserting the statements
fg_setcolor(0); fg_rect(0,47,0,7);
immediately before the call to fg_locate. The parameters passed to the fg_rect
routine represent the 48 by 8 pixel region that corresponds to the first six
character cells of row 0 in the 320x200 graphics modes.
Character Height
In VGA and SVGA graphics modes (modes 17 to 29), it's possible to change
the height of characters displayed with fg_print, fg_printc, fg_text, and fg_textc. By default, characters are 16 pixels high in the VGA and SVGA graphics modes (17, 18, 24 to 29) and 8 pixels high in the MCGA and XVGA graphics modes (19 to 23). The fg_fontsize routine lets you display characters from the BIOS 8x8, 8x14, or 8x16 fonts in any of these modes. Its only parameter specifies the character height in pixels; it must be 8, 14, or 16. If the character height is some other value, or if fg_fontsize is used in a video mode numbered 16 or less (that is, in a non-VGA mode), nothing happens. � 136 Fastgraph User's Guide
When we change the character height with fg_fontsize, the number of text
rows on the screen changes accordingly. The following table shows the number of text rows available in each supported video mode when using the different character sizes. The values in boldface represent the default character size and number of rows for that video mode.
Mode No. of rows with Number 8x8 8x14 8x16
17 60 34 30 18 60 34 30 19 25 14 12 20 25 14 12 21 50 28 25 22 30 17 15 23 60 34 30 24 50 28 25 25 60 34 30 26 75 42 37 27 96 54 48 28 75 42 37 29 96 54 48
Example 7-8 shows how to use fg_fontsize to activate the 8x8 character
font in the 16-color 640x480 VGA graphics mode (mode 18). In this mode, characters are normally 16 pixels high, giving 30 character rows per screen. When we use the 8x8 font, this increases to 60 rows because the characters are now half as tall as before. The example program uses fg_text to display the string "8x8 ROM font" 60 times, once in each row.
Example 7-8.
#include <fastgraf.h> void main(void);
void main() { int old_mode; int row;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(18);
fg_setcolor(9); fg_fillpage(); fg_setcolor(15); fg_fontsize(8);
for (row = 0; row < 60; row++) { fg_locate(row,34); fg_text("8x8 ROM font",12); } fg_waitkey();
fg_setmode(old_mode); � Chapter 7: Character Display Routines 137
fg_reset(); }
Conversion Routines
In Chapter 4 we introduced Fastgraph's routines for converting
coordinates between character space and screen space. In this section we'll review these routines and then present an example that uses some of them.
The fg_xalpha and fg_yalpha routines convert screen space coordinates to
character space. The fg_xalpha routine converts a screen space x coordinate to the character space column that contains the coordinate. Similarly, fg_yalpha converts a screen space y coordinate to the character space row that contains the coordinate.
The fg_xconvert and fg_yconvert routines convert character space
coordinates to screen space. The fg_xconvert routine converts a character space column to the screen space coordinate of its leftmost pixel. Similarly, fg_yconvert converts a character space row to the screen space coordinate of its top (lowest-numbered) pixel.
Example 7-5 demonstrated how to display characters in a graphics mode.
Because characters do not have a background color in graphics modes, that example used fg_rect to simulate a background color by drawing a gray rectangle before displaying the text. It was necessary to determine the screen coordinates of the character cells so we could pass the correct parameters to fg_rect. By using fg_xconvert and fg_yconvert, we can let Fastgraph calculate the required screen coordinates. This method has the additional benefit of working in any graphics mode, while the coordinates passed to fg_rect in example 7-5 would only work properly in a 640x350 graphics mode. Example 7-9 shows how we could extend example 7-5 using fg_xconvert and fg_yconvert.
Example 7-9.
#include <fastgraf.h> void main(void);
void main() { int old_mode; int minx, maxx, miny, maxy;
fg_initpm(); fg_old_mode = fg_getmode(); fg_setmode(16);
fg_setcolor(14); fg_text("yellow",6);
fg_setcolor(10); fg_text(" green",6);
fg_setcolor(7); minx = fg_xconvert(0); �
138 Fastgraph User's Guide
maxx = fg_xconvert(16) - 1; miny = fg_yconvert(24); maxy = fg_yconvert(25) - 1; fg_rect(minx,maxx,miny,maxy); fg_setcolor(12); fg_locate(24,0); fg_text(" Press any key. ",16); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Software Characters
Software characters, also called stroke characters or vector characters
in other literature, are only are available in graphics video modes. Unlike the fixed-size hardware characters, you can display software characters in any size, at any angle, and at any position. In addition, software characters are proportionally spaced. However, software characters take longer to draw than hardware characters do.
Fastgraph includes two software character fonts, called the primary font
and the alternate font. The primary font contains upper and lower case letters, numbers, punctuation, and most other printable ASCII characters. The alternate font contains upper and lower case Greek letters and other mathematical and scientific symbols.
The Fastgraph routine fg_swchar displays a string of software characters
in the current color index (as defined by the most recent call to fg_setcolor). The string may contain any characters from the primary font, the alternate font, or both. You can display the characters left justified, centered, or right justified relative to the graphics cursor position. Just as fg_text updates the text cursor position, fg_swchar sets the graphics cursor position just to the right of the last character drawn. The characters are clipped according to the current clipping region. In addition to the characters, the string passed to fg_swchar also may contain operators for switching fonts, underlining, subscripting, or superscripting characters. Because fg_swchar internally uses world space coordinates, you must call the fg_initw routine at some point in your program before the first call to fg_swchar. You also must establish a world space coordinate system with the fg_setworld routine.
The fg_swchar routine has three arguments. The first argument is the
character string to display. The second argument is an integer value that specifies the number of characters in the string, including any characters used as special operators. The third argument is an integer value that determines the position of the string relative to the graphics cursor position. If this value is negative, the lower left corner of the first character will be at the graphics cursor position. If it is positive, the lower right corner of the last character will be at the graphics cursor position. If it is zero, the string will be horizontally centered at the graphics cursor position. �
Chapter 7: Character Display Routines 139
The size of software characters is determined by the values passed to
fg_setsize, fg_setsizew, and fg_setratio. The fg_setsize routine has a single integer argument that defines the height of software characters in screen space units, while fg_setsizew has a single floating point argument that defines the height in world space units. If neither of these routines is called, Fastgraph will use its default character height of one world space unit. The fg_setratio routine has a single floating point argument that defines the aspect ratio for software characters. The aspect ratio is the ratio of character width to character height. For example, an aspect ratio of 2.0 means characters are twice as wide as they are high. If fg_setratio is not called, Fastgraph uses its default aspect ratio of 1.
Example 7-10 displays all characters in both software character fonts.
The program uses the enhanced EGA graphics mode (mode 16), but it could run in any graphics mode by changing the fg_setmode argument. After establishing the video mode, the program calls fg_initw to initialize Fastgraph's world space parameters; this is required since the software character drawing routines internally use world space coordinates. The next statement is a call to fg_setworld that establishes a world space coordinate system with 0.01 world space units per pixel. Following this is a call to fg_setsizew that defines the character height as 0.21 world space units, or 21 pixels. Note we could have instead used fg_setsize here with an integer argument of 21.
The next part of the program draws the characters in the primary font on
the upper half of the screen. After doing this, the program draws the alternate font characters on the lower half. In each case it does this with fg_swchar. By default, the string passed to fg_swchar will produce characters from the primary font. However, you can insert a back slash character (\) in the string to toggle between the two fonts. Don't forget C and C++ apply a special meaning to the back slash character within strings, so you must use two consecutive back slashes to insert a single back slash in the string.
Example 7-10.
#include <fastgraf.h> void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(16); fg_initw(); fg_setworld(0.0,6.39,0.0,3.49); fg_setsizew(0.21);
fg_setcolor(15); fg_locate(0,26); fg_text("Software characters - font 1",28);
fg_setcolor(10); fg_movew(0.0,3.1); fg_swchar("ABCDEFGHIJKLMNOPQRSTUVWXYZ",26,-1); fg_movew(0.0,2.8); �
140 Fastgraph User's Guide
fg_swchar("abcdefghijklmnopqrstuvwxyz",26,-1); fg_movew(0.0,2.5); fg_swchar("0123456789",10,-1); fg_movew(0.0,2.2); fg_swchar("!\"#$%&'()*+,-./:;<=>?[]^`{|}~",29,-1);
fg_setcolor(15); fg_locate(12,26); fg_text("Software characters - font 2",28);
fg_setcolor(10); fg_movew(0.0,1.4); fg_swchar("\\ABCDEFGHIJKLMNOPRSTUWXYZ",25,-1); fg_movew(0.0,1.1); fg_swchar("\\abcdefghijklmnoprstuwxyz",25,-1); fg_movew(0.0,0.4); fg_swchar("\\012345678#$%&()*+/<=>?[]{}",27,-1); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
If you compare the primary font strings with the alternate font strings,
you'll see the alternate font contains fewer characters. For example, the
letters Q and V (either upper or lower case) have no corresponding character
in the alternate font. You might have also noticed the primary font does not
support the full printable ASCII character set. Any character in a string
passed to fg_swchar that does not have a corresponding character in the
current font will display a blank character.
In addition to the font change operator (the back slash character),
fg_swchar recognizes three other operators. The superscript operator is a back slash followed by a caret (\^). It causes the next character to appear as a superscript. Similarly, the subscript operator is a back slash followed by a lower case v (\v); it causes the next character to appear as a subscript. The size of superscripted and subscripted characters is one half the height of the other characters. The underline operator is the underscore character (_). It causes all subsequent characters in the string to be underlined until another underscore character is found, or until the end of the string. When using these operators, be sure to include them as part of the string length count passed to fg_swchar.
Example 7-11 illustrates the use of the font selection, superscript,
subscript, and underline operators with fg_swchar. Again, because the back slash character has a special meaning in C and C++, we must use two consecutive back slashes to represent a single back slash within the string. The program displays four strings:
cos2 + sin2 = 1 H2O U232 One word is underlined. � Chapter 7: Character Display Routines 141
The theta symbol in the first string is produced by displaying the character
"h" in the alternate font. Note another font selection operator (\) appears
immediately after the "h" to revert to the primary font. The first string also
includes superscript operators (\^) to display the exponents in the equation.
The second string includes a single subscripted character, while the third
string shows how to display three consecutive subscripted characters. Finally,
the fourth string illustrates how to underline characters.
Note example 7-11 also uses fg_setratio. The first three strings are
drawn with an aspect ratio of 2, making them twice as wide as they are high. The fourth string is drawn with an aspect ratio of 1 (Fastgraph's default aspect ratio for software characters), so the character height is the same as the character width. Also, the strings are centered instead of left justified as in the previous example.
Example 7-11.
#include <fastgraf.h> void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(16); fg_setcolor(10); fg_initw(); fg_setworld(0.0,6.39,0.0,3.49); fg_setratio(2.0); fg_setsizew(0.21);
fg_movew(3.2,3.0); fg_swchar("cos\\^2\\h\\ + sin\\^2\\h\\ = 1",25,0);
fg_movew(3.2,2.0); fg_swchar("H\\v2O U\\v2\\v3\\v2",18,0);
fg_movew(3.2,1.0); fg_setratio(1.0); fg_swchar("One _word_ is underlined.",25,0); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
The fg_setangle routine defines the angle of rotation at which software
characters are displayed. Its only argument is a floating point value that specifies the angle, measured in degrees counterclockwise from the positive x axis. If a program draws software characters before calling fg_setangle, Fastgraph will use its default angle of zero degrees (that is, the characters will be oriented horizontally). � 142 Fastgraph User's Guide
In most programs, the alternate font is not needed. However, if you use
the fg_swchar routine, Fastgraph will include the definitions of these characters in your program's data segment. To prevent wasting this space, Fastgraph includes the fg_swtext routine. The fg_swtext routine is same as fg_swchar, except it does not include the alternate font. Since the font selection operator does not apply when using fg_swtext, the routine simply ignores it. You should only use fg_swtext if do not use fg_swchar. If you use both routines, your program will still work correctly, but its data segment will contain an extra copy of the primary font definitions.
Example 7-12 demonstrates the use of fg_setangle and fg_swtext. The
program draws a series of strings of the form "nnn degrees", where nnn is a multiple of 15, radiating from the screen center. Each string appears at the specified angle. For example, the string "15 degrees" is drawn at an angle of 15 degrees.
Example 7-12.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { char string[24]; int angle; int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(16); fg_setcolor(10); fg_initw(); fg_setworld(0.0,6.39,0.0,3.49); fg_setsizew(0.21);
for (angle = 0; angle < 360; angle += 15) { fg_movew(3.2,1.75); fg_setangle((double)angle); sprintf(string," %3d degrees",angle); fg_swtext(string,16,-1); } fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
The final routine pertaining to software characters is fg_swlength, which
returns the length of a specified string of software characters in world space units. The length is returned as the routine's floating point function value. The fg_swlength routine has two arguments -- a string of software characters, and an integer value specifying the number of characters in the string. As with fg_swchar and fg_swtext, the count includes any of the special operator characters. �
Chapter 7: Character Display Routines 143
Example 7-13 demonstrates a typical use of the fg_swlength routine. The
program displays the string "hello there." in light green against a gray background in the middle of the screen. As in our previous software character examples, the program uses mode 16 and first performs the necessary initializations to use software characters. Following this, the program uses fg_swlength to compute the length in world space units of the string. Note we have added blank characters to each end of the string passed to fg_swlength; this increases the length of the actual string and will effectively give the gray rectangle an extended border on its left and right sides. The string length returned by fg_swlength is multiplied by 0.5, giving the distance from the middle of the screen to either side of the rectangle. The program then uses this value to compute the minimum and maximum x coordinates passed to fg_rectw. After drawing the gray rectangle, the program uses fg_swtext to draw the string of software characters in the middle of the screen. It then waits for a keystroke before restoring the original video mode and screen attributes and returning to DOS.
Example 7-13.
#include <fastgraf.h> void main(void);
void main() { int old_mode; double half;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(16); fg_initw(); fg_setworld(0.0,6.39,0.0,3.49); fg_setsizew(0.21);
fg_setcolor(7); half = fg_swlength(" Hello there. ",14) * 0.5; fg_rectw(3.2-half,3.2+half,1.6,1.9);
fg_setcolor(10); fg_movew(3.2,1.65); fg_swtext("Hello there.",12,0); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Bitmapped Characters
Bitmapped characters combine the properties of hardware and software
characters. Like hardware characters, they are a fixed size, but they are almost always more visually appealing. Because they are not scalable, they do � 144 Fastgraph User's Guide
not require floating point arithmetic, and therefore they are much faster than
software characters.
Fastgraph makes no special provision for bitmapped characters because it
treats them as if they were any other bitmapped image. For example, to use a five-pixel by five-pixel bitmapped font, you can construct characters as shown here and then store these representations in an image array.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
The image display routines fg_drawmap and fg_drwimage, discussed in Chapter 10, could then be used to display specific characters from the image array. Also, the Fastgraph/Fonts add-on product greatly simplifies adding bitmapped font support to Fastgraph applications.
Summary of Character Display Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_CHGATTR applies the current text display attribute to a given number
of characters, starting at the text cursor position. This routine leaves the text cursor one column to the right of the last character changed (or the first column of the next row if the last character is at the end of a row). It has no effect in graphics video modes.
FG_CHGTEXT displays a string of hardware characters, starting at the text
cursor position, using the existing text display attributes. This routine leaves the text cursor one column to the right of the last character displayed (or the first column of the next row if the last character is at the end of a row). It has no effect in graphics video modes.
FG_FONTSIZE enables the 8x8, 8x14, or 8x16 ROM BIOS character font for
strings displayed with fg_print and fg_text. This routine is meaningful only in VGA and SVGA graphics video modes.
FG_GETATTR returns the character attribute stored at the specified
position on the active video page. It has no effect in graphics video modes.
FG_GETCHAR returns the character value stored at the specified position
on the active video page. It has no effect in graphics video modes.
FG_GETXJUST returns the current horizontal justification setting for
strings displayed with fg_print or fg_printc.
FG_GETYJUST returns the current vertical justification setting for
strings displayed with fg_print or fg_printc. �
Chapter 7: Character Display Routines 145
FG_JUSTIFY defines the horizontal and vertical justification settings for
strings displayed with fg_print or fg_printc.
FG_LOCATE establishes the text cursor position for the active video page.
FG_PRINT displays a string of hardware characters, relative to the
graphics cursor position, using the current color index. By default, strings are displayed such that the bottom row of the first character is at the current graphics position. On return, the graphics cursor is positioned just to the right of the last character displayed.
FG_PRINTC is a version of fg_print that performs clipping.
FG_SETANGLE defines the angle or orientation at which software characters
are displayed. The angle is measured in degrees counterclockwise from the positive x axis.
FG_SETATTR establishes the current text display attribute in text video
modes. This routine has no effect in graphics video modes.
FG_SETCOLOR establishes the current color index (which may be a virtual
color index in graphics modes). In text modes, the fg_setcolor routine provides an alternate method of establishing the current text display attribute.
FG_SETRATIO defines the aspect ratio for software characters. The aspect
ratio is the ratio of character width to character height.
FG_SETSIZE defines the height of software characters in screen space
units.
FG_SETSIZEW defines the height of software characters in world space
units.
FG_SWCHAR displays a string of software characters using the current
color index. The string may be left justified, centered, or right justified relative to the graphics cursor position. The string passed to fg_swchar may contain special operators that allow switching between fonts, underlining, superscripting, or subscripting. This routine has no effect in text video modes.
FG_SWLENGTH returns the length in world space units of a string of
software characters.
FG_SWTEXT is a scaled down version of the fg_swchar routine. It does not
include the alternate font character definitions and thus requires less memory than fg_swchar.
FG_TEXT displays a string of hardware characters, starting at the text
cursor position, using the current color attribute (for text modes) or color index (for graphics modes). This routine leaves the text cursor one column to the right of the last character displayed (or the first column of the next row if the last character is at the end of a row).
FG_TEXTC is a version of fg_text that performs clipping when run in
graphics video modes. In text modes, fg_textc is equivalent to fg_text. � 146 Fastgraph User's Guide
FG_WHERE retrieves the row and column numbers of the text cursor
position.
FG_XALPHA and FG_YALPHA convert screen space coordinates to character
space.
FG_XCONVERT and FG_YCONVERT convert character space coordinates to screen
space.
Chapter 8
Video Pages and Virtual Buffers � 148 Fastgraph User's Guide
Overview
The amount of memory required to store one full screen of information is
called a video page (or sometimes simply a page). Fastgraph offers a variety of page types, including physical pages, virtual pages, extended pages, and logical pages. In addition, virtual buffers let you define arbitrary blocks of conventional memory and treat them as if they were video memory. This chapter will discuss video pages and virtual buffers in detail, along with the Fastgraph routines to manage them.
Physical Pages and Virtual Pages
Pages that use the memory that resides on the video adapter are called
physical pages or true pages. The number of physical pages available depends on the video mode and the amount of memory resident on the user's video adapter. All video modes have at least one physical page. In certain video modes, Fastgraph can allocate available random-access memory (RAM) and treat this memory as a video page. Pages that use standard RAM in this sense are called virtual pages. From a programmer's perspective, virtual pages are essentially identical to physical pages.
The following table shows the number of physical pages in each video
mode. It also indicates whether or not specific video modes support virtual pages.
Mode Page Size Physical Virtual Number Description in Bytes Pages Pages
0 40 column color text 2,000 8 no 1 40 column color text 2,000 8 no 2 80 column color text 4,000 4 no 3 80 column color text 4,000 4 no 4 320x200x4 CGA graphics 16,000 1 yes 5 320x200x4 CGA graphics 16,000 1 yes 6 640x200x2 CGA graphics 16,000 1 yes 7 80 column monochrome text 4,000 1 yes 9 320x200x16 Tandy graphics 32,000 1 yes 11 720x348 Hercules graphics 31,320 2 yes 12 320x200 Hercules graphics 31,320 2 yes 13 320x200x16 EGA graphics 32,000 8 no 14 640x200x16 EGA graphics 64,000 4 no 15 640x350 EGA mono graphics 56,000 2 no 16 640x350x16 EGA graphics 112,000 2 no 17 640x480x2 MCGA/VGA graphics 38,400 1+ no 18 640x480x16 VGA graphics 153,600 1+ no 19 320x200x256 MCGA graphics 64,000 1 yes 20 320x200x256 XVGA graphics 64,000 4 no 21 320x400x256 XVGA graphics 128,000 2 no 22 320x240x256 XVGA graphics 76,800 3+ no 23 320x480x256 XVGA graphics 153,600 1+ no 24 640x400x256 SVGA graphics 256,000 4 no 25 640x480x256 SVGA graphics 307,200 2 no 26 800x600x256 SVGA graphics 480,000 2 no 27 1024x768x256 SVGA graphics 786,432 1+ no � Chapter 8: Video Pages and Virtual Buffers 149
28 800x600x16 SVGA graphics 240,000 4 no 29 1024x768x16 SVGA graphics 393,216 2 no
This table assumes the video adapter has 256K of video memory installed for EGA and VGA modes, and 1MB of video memory for SVGA modes. For adapters with less video memory, the number of physical pages is reduced proportionately. In other words, a 64K EGA has two video pages available instead of eight in mode 13. Similarly, a 512K SVGA has one page instead of two in modes 25 and 26, and wouldn't support mode 27. The next table summarizes the number of video pages available in SVGA graphics modes for video cards with 256K, 512K, 768K, and 1MB of video memory installed.
Mode Number of pages with... Number Resolution 256K 512K 768K 1MB
24 640x400x256 1+ 2 3 4 25 640x480x256 0 1+ 1+ 2 26 800x600x256 0 1+ 1+ 2 27 1024x768x256 0 0 1 1+ 28 800x600x16 1+ 2 3 4 29 1024x768x16 0 1+ 1+ 2
In the preceding two tables, note that the number of physical pages in
some video modes is followed by a plus symbol. In these modes, there is an additional partial video page available. For modes 17, 18, and 23, there is one full page (page 0) plus one partial page of 320 pixel rows (page 1). For mode 22, there are three full physical pages (numbered 0 to 2) plus one partial page of 80 pixel rows (page 3). For mode 27, there is one full page (page 0) plus one partial page of 256 pixel rows (page 1) on a 1MB SVGA card. You can safely use the partial pages as long as you don't reference pixel rows beyond their last available row. However, you cannot make a partial video page the visual page.
In SVGA graphics modes (modes 24 to 29), video pages must begin on 256K
boundaries to maintain compatibility between different SVGA chipsets. This results in unused video memory at the end of a page. For example, pages in mode 26 require 480,000 bytes of video memory. On a 1MB SVGA card, the two pages will begin at 0 and 524,288 (512K). Thus there are 44,288 (524,288 minus 480,000) unused video memory bytes at the end of each page. With 800 pixels (and hence 800 bytes) per screen row, this means each page has an extra 55 pixel rows per page. The actual page size is therefore 800x655, with the first 600 rows displayed. Similarly, the actual page size in mode 25 is 640x819, with the first 480 rows displayed.
Physical pages are numbered starting at zero. For example, there are four
physical video pages available in mode 3, and they are numbered 0 to 3. Virtual pages are numbered n to 63, where n is the number of physical pages in that mode. For example, there are two physical pages (numbered 0 and 1) and 62 virtual pages (numbered 2 to 63) in mode 11. Note only modes 4 through 12 and mode 19 offer virtual pages, and the amount of conventional memory in the user's system usually limits the number of virtual pages available (this is especially true in mode 19 because of the large page size). � 150 Fastgraph User's Guide
Pages With Special Meanings
There are three video pages that have special meanings to Fastgraph. The
visual page, as one might guess, is the video page visible on the user's display. The active page is the video page to which Fastgraph writes text or graphics information. The hidden page is meaningful only to a few Fastgraph routines and will be discussed specifically within the context of those routines. The fg_setmode routine sets all three of these pages to page 0, and it does not matter if these pages are physical or virtual.
One of the most useful features of multiple video pages (either physical
or virtual) is the ability to build a text or graphics image off screen (that is, on some video page besides the visual page). Then, once the image is ready, we can either transfer it to the visual page, or make the page on which the image resides the visual page. This feature is especially useful in animation, for it displays an image instantaneously instead of visibly updating the screen while producing the image.
Some Simple Examples
In this section, we'll present six variations of a simple program that
uses four video pages. The program fills each video page with a rectangle and then displays text containing the video page number in the center of each page. The first two examples run in a specific text or graphics video mode and only use physical pages. The next two examples also run in a specific text or graphics video mode, but they also use virtual pages. The final two examples are more general and run in several video modes. You could of course write a program that essentially does the same thing as the examples in this section without using multiple video pages. However, to use Fastgraph's image display and animation routines effectively, you must first understand the concept of video pages.
Before proceeding, we must introduce the Fastgraph routines fg_setpage
and fg_setvpage. The fg_setpage routine defines the active video page, which causes Fastgraph to put subsequent text and graphics output on that page. The fg_setvpage routine defines the visual video page displayed on the screen. Both routines take a single integer argument between 0 and 63 that specifies the video page number. It does not matter if the referenced video page is a physical page or a virtual page. As mentioned earlier, fg_setmode makes page 0 the active and visual video page.
Example 8-1 uses four video pages (numbered 0 to 3) in the 40-column
color text mode (mode 1). The program first calls fg_testmode to check the availability of the requested video mode when used with four video pages. If it is available, the program calls fg_setmode to establish that video mode. The first for loop fills each of the four pages with different color rectangles and then displays black text containing the video page number in the center of each page. It does this by calling fg_setpage to define the active video page, fg_setcolor and fg_rect to draw the colored rectangles, and finally fg_setattr, fg_locate, and fg_text to display the text. The program must call fg_locate inside the loop because each video page has its own text cursor position. The second for loop successively makes each video page the visual page; the page remains displayed until you press a key. After �
Chapter 8: Video Pages and Virtual Buffers 151
displaying all four video pages, the program restores the original video mode
and screen attributes before returning to DOS.
Example 8-1.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define PAGES 4
void main() { int color; int old_mode; int page; char string[8];
fg_initpm(); if (fg_testmode(1,PAGES) == 0) { printf("This program requires color.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(1);
for (page = 0; page < PAGES; page++) { fg_setpage(page); color = page + 1; fg_setcolor(color); fg_rect(0,fg_getmaxx(),0,fg_getmaxy()); fg_setattr(0,color,0); fg_locate(12,17); sprintf(string,"page %d",page); fg_text(string,6); }
for (page = 0; page < PAGES; page++) { fg_setvpage(page); fg_waitkey(); }
fg_setmode(old_mode); fg_reset(); }
Example 8-2 is similar to example 8-1, but it uses the 320x200 EGA
graphics mode (mode 13) instead of a text mode. Note the only real difference between this program and the text mode version is the use of fg_setcolor instead of fg_setattr to make the text appear in black.
Example 8-2. �
152 Fastgraph User's Guide
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define PAGES 4
void main() { int color; int old_mode; int page; char string[8];
fg_initpm(); if (fg_testmode(13,PAGES) == 0) { printf("This program requires a "); printf("320 x 200 EGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(13);
for (page = 0; page < PAGES; page++) { fg_setpage(page); color = page + 1; fg_setcolor(color); fg_rect(0,fg_getmaxx(),0,fg_getmaxy()); fg_setcolor(0); fg_locate(12,17); sprintf(string,"page %d",page); fg_text(string,6); }
for (page = 0; page < PAGES; page++) { fg_setvpage(page); fg_waitkey(); }
fg_setmode(old_mode); fg_reset(); }
Virtual video pages are created with Fastgraph's fg_allocate routine. The
fg_allocate routine reserves conventional random-access memory (RAM) which Fastgraph then treats as a video page. The amount of memory required depends on the current video mode. The fg_allocate routine takes a single integer argument that specifies the page number by which the virtual page will be referenced. This value must be between 1 and 63.
If you try to create a virtual page with a page number already assigned
to a physical page, fg_allocate does nothing. For example, in the Hercules graphics modes (modes 11 and 12) there are two physical pages numbered 0 and 1. Virtual pages in the Hercules graphics modes must thus have page numbers �
Chapter 8: Video Pages and Virtual Buffers 153
between 2 and 63. If you tell fg_allocate to create a Hercules virtual page
numbered 0 or 1, it does nothing because those video pages exist as physical
pages. Similarly, if you use fg_allocate in a video mode that does not support
virtual video pages, it simply returns without doing anything.
A possible problem with fg_allocate can occur when there is not enough
memory available for creating a virtual page in the current video mode. The fg_allocate routine returns as its function value a status code indicating whether or not it was successful. The possible values of the status code are:
value meaning
0 virtual page created 1 specified page number is a physical page 7 virtual page created, but memory control blocks were destroyed 8 insufficient memory to create the virtual page
If you use fg_testmode or fg_bestmode to check if the required number of video pages are available when using the requested video mode, you should not need to monitor the status code returned by fg_allocate.
The fg_freepage routine releases the memory for a virtual page created
with fg_allocate. It requires a single integer argument that identifies the virtual page number to release. This value must be between 0 and 63. If you try to release a physical video page, or release a virtual page that was never created, fg_freepage does nothing. It is a good idea to use fg_freepage to release all virtual video pages before a program returns control to DOS, or just before a program selects a new video mode.
Example 8-3 is also similar to example 8-1, but it uses the monochrome
text mode (mode 7). Because the monochrome text mode only has one physical video page, we must use virtual video pages for page numbers 1, 2, and 3. Note how fg_allocate and fg_freepage are used to create and release the virtual video pages in this example.
Example 8-3.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define PAGES 4
void main() { int old_mode; int page; char string[8];
fg_initpm(); if (fg_testmode(7,PAGES) == 0) { printf("This program requires monochrome.\n"); exit(1); } �
154 Fastgraph User's Guide
old_mode = fg_getmode(); fg_setmode(7); fg_cursor(0);
for (page = 0; page < PAGES; page++) { fg_allocate(page); fg_setpage(page); fg_setcolor(7); fg_rect(0,fg_getmaxx(),0,fg_getmaxy()); fg_setattr(0,7,0); fg_locate(12,37); sprintf(string,"page %d",page); fg_text(string,6); }
for (page = 0; page < PAGES; page++) { fg_setvpage(page); fg_waitkey(); fg_freepage(page); }
fg_setmode(old_mode); fg_reset(); }
Example 8-4 is similar to example 8-3, but it uses the standard Hercules
graphics mode (mode 11) instead of the monochrome text mode. Because the Hercules graphics modes have two physical video pages, we must use virtual video pages for page numbers 2 and 3. Note the only real difference between this program and the text mode version is the use of fg_setcolor instead of fg_setattr to make the text appear in black.
Example 8-4.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define PAGES 4
void main() { int old_mode; int page; char string[8];
fg_initpm(); if (fg_testmode(11,PAGES) == 0) { printf("This program requires Hercules "); printf("monochrome graphics.\n"); exit(1); }
old_mode = fg_getmode(); � Chapter 8: Video Pages and Virtual Buffers 155
fg_setmode(11);
for (page = 0; page < PAGES; page++) { fg_allocate(page); fg_setpage(page); fg_setcolor(7); fg_rect(0,fg_getmaxx(),0,fg_getmaxy()); fg_setcolor(0); fg_locate(12,37); sprintf(string,"page %d",page); fg_text(string,6); }
for (page = 0; page < PAGES; page++) { fg_setvpage(page); fg_waitkey(); fg_freepage(page); }
fg_setmode(old_mode); fg_reset(); }
Example 8-5 is a generalized version of examples 8-1 and 8-3 that runs in
any 80-column text video mode. To simplify the program, each video page is filled with rectangles of the same color. Note that fg_allocate and fg_freepage are used to manage the virtual video pages in case fg_bestmode selects the monochrome text mode (mode 7). If fg_bestmode selects one of the 80-column color text modes (which have four physical video pages), fg_allocate and fg_freepage will simply return without doing anything.
Example 8-5.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define PAGES 4
void main() { int old_mode, new_mode; int page; char string[8];
fg_initpm(); new_mode = fg_bestmode(80,25,PAGES); if (new_mode < 0) { printf("This program requires "); printf("an 80-column display.\n"); exit(1); }
old_mode = fg_getmode(); �
156 Fastgraph User's Guide
fg_setmode(new_mode); fg_cursor(0);
for (page = 0; page < PAGES; page++) { fg_allocate(page); fg_setpage(page); fg_setcolor(7); fg_rect(0,fg_getmaxx(),0,fg_getmaxy()); fg_setattr(0,7,0); fg_locate(12,37); sprintf(string,"page %d",page); fg_text(string,6); }
for (page = 0; page < PAGES; page++) { fg_setvpage(page); fg_waitkey(); fg_freepage(page); }
fg_setmode(old_mode); fg_reset(); }
Example 8-6 is a generalized version of examples 8-2 and 8-4 that runs in
any 320x200 graphics video mode. To simplify the program, each video page is filled with rectangles of the same color. As in example 8-5, fg_allocate and fg_freepage are used to manage the virtual video pages in case fg_bestmode selects a video mode with fewer than four physical video pages. Note the only real difference between this program and the text mode version is the use of fg_setcolor instead of fg_setattr to make the text appear in black.
Example 8-6.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define PAGES 4
void main() { int old_mode, new_mode; int page; char string[8];
fg_initpm(); new_mode = fg_bestmode(320,200,PAGES); if (new_mode < 0) { printf("This program requires a "); printf("320 x 200 graphics mode.\n"); exit(1); } � Chapter 8: Video Pages and Virtual Buffers 157
old_mode = fg_getmode(); fg_setmode(new_mode);
for (page = 0; page < PAGES; page++) { fg_allocate(page); fg_setpage(page); fg_setcolor(15); fg_rect(0,fg_getmaxx(),0,fg_getmaxy()); fg_setcolor(0); fg_locate(12,17); sprintf(string,"page %d",page); fg_text(string,6); }
for (page = 0; page < PAGES; page++) { fg_setvpage(page); fg_waitkey(); fg_freepage(page); }
fg_setmode(old_mode); fg_reset(); }
Text Cursors
As mentioned in the previous chapter, Fastgraph draws hardware characters
at the position defined by the text cursor. Like the graphics cursor, the text cursor is not a cursor in the true sense, but is simply a pair of character space (row,column) coordinates with a special meaning. The first 8 video pages (that is, pages 0 through 7) each have their own text cursor. Each subsequent group of 8 video pages (pages 8 through 15, pages 16 to 23, and so forth) respectively share the same text cursor positions as the first 8 pages. This means fg_locate will update one of 8 different text cursors depending on the active video page. Similarly, fg_where returns the text cursor position for the active page. The fg_setmode routine sets all 8 text cursor positions to the character space coordinates (0,0).
Example 8-7 demonstrates the use of different text cursors in an 80-
column color text mode (mode 3). The program first displays the text "Page " on video page 0 (the visible page) and waits for a keystroke. It then makes page 1 the active video page, changes the text cursor location for that page, and displays the text "Page 1" on video page 1. Next, it appends the character "0" to the text originally displayed on page 0. Note that we don't need to restore the text cursor position for page 0 because it is unaffected by changing the text cursor for page 1. After waiting for another keystroke, the program makes video page 1 the visual page and then waits for yet another keystroke before returning to DOS.
Example 8-7.
#include <fastgraf.h> void main(void); �
158 Fastgraph User's Guide
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(3); fg_cursor(0); fg_setattr(10,0,0);
fg_locate(1,0); fg_text("Page ",5); fg_waitkey();
fg_setpage(1); fg_locate(23,0); fg_text("Page 1",6);
fg_setpage(0); fg_text("0",1); fg_waitkey();
fg_setvpage(1); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Obtaining Video Page Information
Fastgraph includes two routines, fg_getpage and fg_getvpage, that
respectively return the active or visual video page number. Each routine returns the video page number as its function value, and neither routine requires any arguments.
When creating virtual or logical pages, you must choose a page number
that does not reference a physical page or a previously created virtual or logical page. While it's of course possible to keep track of which page numbers will be available in a given video mode, Fastgraph's fg_findpage function can make the job easier. It returns an unused page number, which you can then pass to any of Fastgraph's virtual or logical page allocation routines. If there are no more available (that is, all 64 entries in the internal page tables are in use), fg_findpage returns zero.
The fg_getaddr routine is sometimes useful when using virtual pages. It
returns as its function value the segment address (in real mode) or segment selector (in protected mode) for the start of the active video page. It does not require any arguments. Although fg_getaddr is more useful when using virtual video pages, it works equally well with physical video pages.
Example 8-9 illustrates the use of fg_getpage, fg_getvpage, fg_findpage,
and fg_getaddr in the standard VGA/MCGA 256-color graphics mode (mode 19). This video mode offers only one physical page, so the program uses fg_findpage �
Chapter 8: Video Pages and Virtual Buffers 159
to find an unused page number (which will be page 1 in mode 19), and then
calls fg_allocate to create a virtual video page. After creating the virtual
page, the program makes it the active video page; page 0 remains the visual
video page. The fg_getpage routine then returns the active page number,
followed by a call to fg_getvpage to return the visual page number (0). Next,
the program uses fg_getaddr to return the segment address/selector for the two
video pages. Finally, it restores the original video mode and screen
attributes, displays the returned values, and returns to DOS.
Example 8-9.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int old_mode; int active, visual; int page, page0, page1;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(19); page = fg_findpage(); fg_allocate(page); fg_setpage(page);
active = fg_getpage(); visual = fg_getvpage();
fg_setpage(0); page0 = fg_getaddr(); fg_setpage(page); page1 = fg_getaddr();
fg_freepage(page); fg_setmode(old_mode); fg_reset();
printf("Active page is %d.\n",active); printf("Visual page is %d.\n",visual); printf("Page 0 address is %4X\n",page0); printf("Page %d address is %4X\n",page,page1); }
Considerations for Virtual Pages
If you're using Power C, any supported BASIC compiler, Borland Pascal, or
Turbo Pascal and need to create virtual pages, you must reduce the size of the far heap. Normally, these compilers allocate all remaining memory for the heap, which means fg_allocate will not be able to allocate memory for the virtual page. � 160 Fastgraph User's Guide
In BASIC programs, the SETMEM function reduces the size of the far heap.
The BASIC versions of the Fastgraph example programs include the statement
SetMemStatus& = SETMEM(-n)
before calling FGallocate. This reduces the size of the far heap by n bytes. For a given video mode, the actual reduction needed is the number of virtual pages multiplied by the page size in that mode. Page sizes are listed at the beginning of this chapter, or you can use fg_pagesize to determine the page size for the current video mode.
In Borland Pascal and Turbo Pascal, the $M compiler directive defines the
maximum heap size in bytes. The Pascal versions of the Fastgraph example programs include the statement
{$M 16384,0,16384}
at the beginning of the examples that call fg_allocate. The third value in this list defines the maximum heap size at 16K bytes. This is suitable for most applications, but if your program uses the New or GetMem procedures to create dynamic variables that require more heap space, you'll need to increase the size beyond 16K.
The far heap size for Power C programs is defined at link time. You must
override the default heap size by including the option [,,16K] on the PCL command when you link a Power C program that uses fg_allocate. The value 16K is suitable for most applications, but if your program calls the farcalloc or farmalloc functions (or the calloc or malloc functions when using the large memory model), you may need to increase the far heap size beyond 16K.
When you are using virtual pages, you should avoid using the fg_setvpage
routine in sections of the program that require fast screen updates or animation sequences. This is because the PC and PS/2 video BIOS are only capable of displaying physical pages. To compensate for this restriction, Fastgraph exchanges the contents of a physical page with the requested virtual page. In other words, if page 1 is a virtual page and you make it the visual page, Fastgraph will exchange the contents of page 1 with whatever page was previously the visual page. This does not mean Fastgraph's page numbers change because Fastgraph also maintains an internal table containing video page addresses and exchanges the two corresponding table entries. As before, you would make page 1 the active video page if you wanted to write something to the visual page.
About the only other potential problem when using virtual pages is what
happens when you try to write to a non-existent video page (for example, if you write to virtual video page 1 before creating it with fg_allocate). In this case, Fastgraph simply redirects the video output to the visual page.
Considerations for SuperVGA Pages
If a program running in an SVGA graphics mode returns to text mode when
the visual page is not page 0, some SVGA chipsets have problems the next time you try to run an SVGA application. We therefore recommend calling fg_setvpage(0) just before restoring the original video mode if an application performs page flipping in SVGA graphics modes. For example: �
Chapter 8: Video Pages and Virtual Buffers 161
old_mode = fg_getmode(); fg_svgainit(0); fg_setmode(25); . . . fg_setvpage(1); . . . fg_setvpage(0); /* add this line to be safe */ fg_setmode(old_mode);
A few SVGA chipsets cannot set the display start address beyond the 16-
bit capability provided by the CRT Controller, rendering fg_setvpage meaningless. Please refer to the READ.ME file for details.
Logical Pages
In addition to physical and virtual video pages, Fastgraph offers another
class of video pages, called logical pages. You can create logical pages in any video mode. They can exist in conventional memory, expanded memory (EMS), or extended memory (XMS). However, they are not as versatile as physical or virtual pages because the only operations you can perform with logical pages are:
* Copy an entire physical or virtual page to a logical page * Copy an entire logical page to a physical or virtual page * Copy an entire logical page to another logical page
Three Fastgraph routines -- fg_alloccms, fg_allocems, and fg_allocxms -- create logical pages in conventional memory, expanded memory, and extended memory, respectively. All three routines have a single integer argument that specifies the page number by which the logical page will be referenced. The page number must be between 1 and 63 and must not reference a physical or virtual page. Their return value is 0 if the logical page is created, and negative otherwise (refer to the descriptions of these routines in the Fastgraph Reference Manual for a complete list of return values). As with virtual pages, use fg_freepage to release a logical page.
Before you can create logical pages in expanded or extended memory, you
must initialize these resources for use with Fastgraph. The fg_initems routine initializes expanded memory. To use expanded memory, you must have an Expanded Memory Manager (EMM) that conforms to the Lotus/Intel/Microsoft Expanded Memory Specification (LIM-EMS) version 3.2 or later. On 80386 and 80486 systems, the EMM386.EXE device driver supplied with DOS 5.0 can be used to treat some or all of extended memory as expanded memory. The fg_initxms routine initializes extended memory for use with Fastgraph. To use extended memory, you must have an XMS driver that conforms to the Lotus/Intel/Microsoft/AST eXtended Memory Specification version 2.0 or later, such as HIMEM.SYS. XMS drivers require an 80286, 80386, or 80486 system. The fg_initems and fg_initxms routines have no arguments and must be called after fg_setmode. Their return value is 0 if successful, and -1 if the required driver and resources are not present. � 162 Fastgraph User's Guide
In protected mode, the distinction between conventional, expanded, and
extended memory disappears because DOS extenders essentially treat all system memory as conventional memory. For this reason, fg_initems and fg_initxms are not meaningful and thus always return -1 in the protected mode Fastgraph libraries. This effectively disables the fg_allocems and fg_allocxms routines, so you must create logical pages with fg_alloccms in protected mode.
Example 8-10 illustrates the use of logical pages in a 320x200 color
graphics mode. The program first tries to create a logical page in extended memory by calling fg_initxms and fg_allocxms. If the initialization or page creation fails, it then tries to create the page in expanded memory with fg_initems and fg_allocems. Should that fail, the program calls fg_alloccms to try to create the page in conventional memory. If it can't create the logical page at all, the program displays an error message and exits.
Once the logical page is created, example 8-10 displays the word "test"
in the middle of the visual page (page 0) and then uses fg_copypage to transfer the visual page contents to the logical page. Because this program runs in one of several different graphics modes, we use fg_findpage to choose the logical page number. After waiting for a keystroke, the program erases the visual page, waits for another keystroke, and copies the logical page contents back to the visual page. It then releases the logical page and exits.
Example 8-10.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode; int page, status;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode);
page = fg_findpage(); status = fg_initxms(); if (status == 0) status = fg_allocxms(page); if (status < 0) { status = fg_initems(); if (status == 0) status = fg_allocems(page); } if (status < 0) status = fg_alloccms(page);
if (status < 0) { � Chapter 8: Video Pages and Virtual Buffers 163
fg_setmode(old_mode); fg_reset(); printf("Unable to create logical page.\n"); exit(1); }
fg_setcolor(7); fg_rect(0,319,0,199); fg_setcolor(9); fg_locate(12,18); fg_text("test",4); fg_waitkey();
fg_copypage(0,page); fg_erase(); fg_waitkey();
fg_copypage(page,0); fg_waitkey();
fg_freepage(page); fg_setmode(old_mode); fg_reset(); }
As mentioned before, the only functions you can perform with logical
pages are copying physical/virtual pages to logical pages, logical pages to physical/virtual pages, or copying one logical page to another. The fg_copypage routine provides the only way to do this for logical pages. See Chapter 11 for more information about fg_copypage.
Extended Video Pages
One of the more frequent technical support questions we receive is "I
have one megabyte of memory on my video card, why can I only use the first 256K?". The answer is simple: the standard EGA and VGA graphics modes have no way to address video memory beyond 256K. Accessing more memory requires SVGA bank switching techniques. This is analogous to the fact that you might have four megabytes of RAM on your system, but without an EMS/XMS memory manager, a DOS extender, or the like, all that memory won't do much good.
Unfortunately, not all SVGA chipsets allow bank switching in non-SVGA
video modes. For those that do, however, Fastgraph includes a feature called extended video pages. Extended pages provide access to all video memory in modes 13 to 18 and modes 20 to 23 instead of restricting access to the first 256K. This means, for example, that a 1MB SVGA card will allow 32 physical pages in mode 13 rather than the usual 8 pages. Extended pages are available with the following SVGA chipsets:
* Ahead B * Avance Logic 2000 series * ATI 28800/mach32/mach64 * Avance Logic 2000 series * NCR 77C22/77C32 * Oak OTI-067 �
164 Fastgraph User's Guide
* Oak OTI-077 * Oak OTI-087 * Paradise WD90C11/WD90C30/WD90C31/WD90C33 * Tseng ET4000
Although extended pages are used in non-SVGA graphics modes, the method
of accessing video memory above 256K is specific to each SVGA chipset. Thus, you must initialize Fastgraph's SVGA kernel (with fg_svgainit) before you can use extended pages. We haven't yet found a VESA implementation that supports extended pages, so you'll need to initialize the SVGA kernel for chipset- specific support.
When writing applications that use extended video pages, you should make
sure the user's SVGA chipset supports extended pages and that there is enough video memory for the number of pages required. First, make sure fg_svgainit successfully initializes the SVGA kernel. If so, check bit 2 of the fg_svgastat return value to see if the chipset supports extended pages. Finally, use fg_memory to insure that enough video memory is available for the number of video pages needed.
The following table shows the number of video pages available in the
graphics modes that support extended pages.
Number of Pages With Mode 256K 512K 1MB
13 8 16 32 14 4 8 16 15 2 4 8 16 2 4 8 17 2 4 8 18 2 4 8 20 4 8 16 21 2 4 8 22 4 8 16 23 2 4 8
Note that when extended pages are not enabled, the video mode has the number of physical video pages listed in the 256K column.
Some video modes do not provide the listed number of full video pages.
For example, modes 17 and 18 normally have two video pages -- one full 640x480 page (page 0) and one partial 640x320 page (page 1). For extended pages, Fastgraph uses a page numbering scheme that maintains consistency with its standard page numbering. That is, when extended pages are available and mode 17 or 18 is used on a 1MB video card, the page numbers will range from 0 to 7, with the even-numbered pages being full pages and the odd-numbered pages being partial 640x320 pages. Similarly, in mode 22 pages 3, 7, 11, and 15 are partial (320x80); in mode 23 odd-numbered pages are partial (320x320).
When you use Fastgraph's block transfer routines (fg_copypage,
fg_restore, fg_save, fg_tcxfer, and fg_transfer) with extended pages, you must pass the source and destination page numbers to fg_defpages. This is needed because the two pages may reside in different SVGA banks, and bank switching is not performed in Fastgraph's non-SVGA code. The additional overhead of having the block transfer routines determine the bank numbers would impact the �
Chapter 8: Video Pages and Virtual Buffers 165
block transfer routines when extended pages are not being used. The
fg_defpages routine determines the SVGA bank numbers in which the source and
destination pages reside and then enables the corresponding banks for reading
and writing. These banks remain in effect until you define new ones with
fg_defpages or fg_setpage, so you may not need to call fg_defpages before
every call to a block transfer routine. The fg_defpages routine has no effect
unless extended pages are enabled. The following table shows the bank numbers
for each video page in each graphics mode that supports extended pages.
Bank 0 Bank 1 Bank 2 Bank 3 Mode Pages Pages Pages Pages
13 0-7 8-15 16-23 24-31 14 0-3 4-7 8-11 12-15 15 0-1 2-3 4-5 6-7 16 0-1 2-3 4-5 6-7 17 0-1 2-3 4-5 6-7 18 0-1 2-3 4-5 6-7 20 0-3 4-7 8-11 12-15 21 0-1 2-3 4-5 6-7 22 0-3 4-7 8-11 12-15 23 0-1 2-3 4-5 6-7
Next we'll present a short code sequence that calls fg_defpages only when
needed in mode 13, where each group of 8 pages resides in its own SVGA bank. Calling fg_setmode enables bank 0 for reading and writing, so we don't need to call fg_defpages until we reference a page in one of the other banks (that is, a page numbered 8 or above).
fg_svgainit(0); fg_setmode(13); /* enables bank 0 for reading and writing */ fg_copypage(0,1); fg_copypage(0,2); fg_defpages(0,1); /* page 10 is in bank 1 */ fg_copypage(2,10); fg_defpages(1,1); /* page 15 is in bank 1 */ fg_copypage(10,15); fg_setpage(0); /* enables bank 0 for reading and writing */ fg_erase(); fg_copypage(0,3); fg_defpages(1,0); /* page 15 is in bank 1 */ fg_copypage(15,4);
Most mouse drivers know nothing about SVGA bank switching and non-
standard video modes (that's why Fastgraph must hook its own mouse cursor control handlers into the mouse driver in XVGA and SVGA modes). As Fastgraph relies on the mouse driver for cursor control in modes 13 to 18, it's only possible to display the mouse cursor on video pages in the first SVGA bank (bank 0) in these modes. Note that this does not apply to modes 20 to 23, where Fastgraph controls the mouse cursor through its own handler.
Some SVGA chipsets do not reset the read and write bank numbers back to
zero when establishing a non-SVGA video mode. When a mode set operation clears video memory, such chipsets will clear the first video page in the last write bank selected. While fg_setmode does set the read and write banks to zero when extended pages are available, it cannot do this before setting the video mode, � 166 Fastgraph User's Guide
which is what normally would clear the screen. This may result in artifacts on
page 0 after calling fg_setmode. The easiest way around this problem is to
call fg_defpages(0,0) before restoring the original video mode in programs
that use extended pages. Even this, however, does not clear video memory after
a mode set when using extended pages with some SVGA chipsets. We therefore
recommend calling fg_erase immediately after restoring the original video mode
when using extended pages.
Video Page Resizing
Resizing is the process of changing the dimensions of a video page. It is
available only in the native EGA graphics modes (modes 13 to 16), native VGA graphics modes (17 and 18), extended VGA modes (20 to 23), and SVGA modes (24 to 29). Resizing does not change the screen resolution, but instead increases the video page size so only part of the page is visible. For now, we'll just introduce resizing with a simple example, but in Chapter 13 we'll see its real power when we perform smooth panning.
The Fastgraph routine fg_resize changes the dimensions of a video page.
Its two integer arguments define the page width and page height, both in pixels. Example 8-11 runs in the 320x200 EGA graphics mode (mode 13). After establishing the video mode, it displays the word "resize" starting in column 38 of row 0. Because the characters extend beyond the last column of the row, they wrap to the next row. The program continues displaying this until you press a key. Then, it clears the screen and calls fg_resize to make the page size 640x200 pixels. Again the program displays the word "resize" starting in column 38 of row 0, but this time it does not wrap to the next row. This is because the resizing doubled the page width, which increased the number of character cells per row from 40 to 80. The characters that formerly wrapped to the next row now continue on an off-screen portion of the same row.
Example 8-11.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode;
fg_initpm(); if (fg_testmode(13,1) == 0) { printf("This program requires a 320 "); printf("x 200 EGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(13);
fg_setcolor(9); fg_locate(0,38); fg_text("resize",6); � Chapter 8: Video Pages and Virtual Buffers 167
fg_waitkey();
fg_erase(); fg_resize(640,200); fg_setcolor(10); fg_locate(0,38); fg_text("resize",6); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
The size of a video page is constrained only by the amount of video
memory available and the addressability of the video mode. Increasing the video page size reduces the number of physical pages available proportionally. In mode 13, for example, increasing the page size from 320x200 to 640x400 reduces the number of video pages from 8 to 2. When you call fg_resize, the visual page must be page 0. If you have created any logical video pages, you must release them with fg_freepage before calling fg_resize, and then create them again afterward. If you have initialized the mouse (with fg_mouseini), joysticks (with fg_initjoy), expanded memory (with fg_initems), or extended memory (with fg_initxms), you should re-initialize these resources after calling fg_resize. In modes 13 to 18, most mouse drivers expect a fixed video page width, so the mouse cursor may become distorted after resizing video pages in these modes. When you call fg_resize, Fastgraph sets the clipping region to the new page limits. The fg_setmode routine re-establishes the dimensions of a video page to the default screen resolution for the selected video mode. The fg_resize routine has no effect when a virtual buffer is active.
Depending on the dimensions passed to fg_resize, you may end up with a
partial video page. Again, suppose we're using mode 13 and have changed the page size to 960x400 (this is six times the default page size). The original pages 0 to 5 now make up page 0, and original pages 6 and 7 now make up page 1. However, there is not enough video memory left on page 1 for a full 960x400 page. In this case, the number of pixel rows available on page 1 would be one- third the full page size, or 133 rows. This is because the total storage required by original pages 6 and 7 is one-third the total required for original pages 0 through 5.
Extended video pages may be resized in modes 13-18 and 20-23, but the
resulting pages must not cross SVGA bank boundaries. In mode 20, for instance, you normally have four 320x200 pages in each bank. You could change the video page size to 640x400, thereby having four larger pages, one in each bank. You could not, however, resize video memory to two 640x800 pages, as each page would span two banks.
Preserving Video Page Contents Across Mode Switches
Sometimes a graphics program may temporarily need to switch to another
video mode. An example of this might be a graphical user interface (GUI) menuing system that includes "shell to DOS" as one of its options. When the user selects this option, the program must revert to a text video mode so the � 168 Fastgraph User's Guide
user will see the familiar DOS prompt when the shell executes. On leaving the
DOS shell, the program returns to a graphics mode and should ideally restore
the screen to what it was originally.
When you establish a video mode with fg_setmode, Fastgraph clears all
physical video pages and initializes its internal page tables as if no virtual or logical pages have been created. While it's not possible to preserve physical page contents across video mode switches, you can use Fastgraph's fg_getentry and fg_setentry routines to save virtual or logical page contents. The trick, so to speak, is using fg_getentry to save the virtual or logical page address and type before switching video modes. Then, when you return to the same video mode, you can use fg_setentry to restore the internal page tables to their previous state. This effectively makes the virtual or logical page accessible again.
Example 8-12 illustrates this process. This program runs in video mode
18, the 640x480 16-color VGA graphics mode. After establishing this video mode, the program calls fg_alloccms to create a logical page in conventional memory. Next, it calls fg_getentry to save the address and type of the logical page just created. The first argument to fg_getentry specifies the page number (determined by fg_findpage); the next two arguments receive the page address and type. Page type codes used by fg_getentry and fg_setentry are:
0 = unallocated page 1 = physical page 2 = virtual page 3 = logical page in expanded memory (EMS) 4 = logical page in extended memory (XMS) 5 = logical page in conventional memory
After this setup work, example 8-12 fills the screen with light blue
pixels, draws a white box around the edge, and then waits for a keystroke. Before switching back to the original video mode (assumed to be mode 3), the program uses fg_copypage to copy the visual page contents to the logical page. This is necessary because we can only save virtual or logical page contents across video mode changes, not physical pages. In mode 3, the program prompts for a keystroke before returning to mode 18.
Now we're ready to restore the previous contents of the visual page.
Because the example program did not release the logical page, the memory is still allocated; Fastgraph just cannot access it. To solve this, the program calls fg_setentry to restore Fastgraph's internal page table entries for the original logical page number to what they were previously. Note how we use the same page address and type values in the call to fg_setentry that were returned earlier by fg_getentry. Now that the logical page is once again accessible, the program can use fg_copypage to copy its contents back to the visual page. With that explanation behind us, here is example 8-12.
Example 8-12.
#include <fastgraf.h> void main(void);
void main() { int old_mode; � Chapter 8: Video Pages and Virtual Buffers 169
int page, page_addr, page_type;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(18); page = fg_findpage(); fg_alloccms(page); fg_getentry(page,&page_addr,&page_type);
fg_setcolor(9); fg_fillpage(); fg_setcolor(15); fg_box(0,639,0,479); fg_waitkey();
fg_copypage(0,page); fg_setmode(old_mode); fg_cursor(0); fg_setcolor(15); fg_text("Press any key.",14); fg_waitkey();
fg_setmode(18); fg_setentry(page,page_addr,page_type); fg_copypage(page,0); fg_waitkey();
fg_freepage(page); fg_setmode(old_mode); fg_reset(); }
To keep the example as simple as possible, it does not test for
availability of video modes, nor does it check if the logical page creation was successful. In a real application, of course, omitting these checks is not recommended. See example 8-17 for a version of this program that uses virtual buffers instead of logical pages.
Controlling Page Allocation
When Fastgraph creates virtual or logical pages in conventional memory
with fg_allocate or fg_alloccms, it uses the DOS allocate memory service (function 48 hex of interrupt 21 hex). Some compilers allocate all or part of available conventional memory to a data structure called the heap or far heap. Memory allocation functions such as malloc handle their requests through an associated heap manager instead of through DOS services. If the heap manager controls all available memory, the DOS allocate memory service is essentially disabled because there will be no memory available to satisfy allocation requests. If the heap manager controls some but not all available memory, a conflict may arise between the heap manager and the DOS allocate memory service.
To solve this problem, you can use the compiler's allocate far memory
function to reserve memory for the virtual or logical page and then make the � 170 Fastgraph User's Guide
page known to Fastgraph with fg_setentry. The easiest way to determine the
amount of memory to allocate is through the fg_pagesize function, which
returns the page size in bytes (as a long integer) for the current video mode.
To release the page, use fg_setentry with a page type of zero to mark the page
as unallocated before actually freeing the memory. Pages created this way are
not initially cleared because the allocated memory block contents are
undefined. We recommend using fg_erase to set the page contents to the
background color.
Example 8-13 shows how to create a virtual page in real mode programs
using these techniques instead of fg_allocate. It uses the farmalloc and farfree functions from the C run-time library for Borland compilers (the analogous Microsoft functions are _fmalloc and _ffree). Example 8-13 uses fg_pagesize and the Borland run-time library function farmalloc to create a virtual page in the 320x200 VGA/MCGA 256-color graphics mode. After allocating the memory, the program calls fg_setentry, passing it the page number (1), the segment portion of the memory block address (using the FP_SEG macro from the run-time library), and the code for a virtual page (2). Once the virtual page is set up, the program writes some text on the virtual page and then uses fg_copypage to display the virtual page contents on the visual page. Finally, it releases the page by calling fg_setentry (so Fastgraph knows the virtual page is gone) and the farfree run-time library function (to actually free the memory). The call to fg_setentry is not really needed in this instance because no further references are made to page 1.
Example 8-13.
#include <fastgraf.h> #include <dos.h> #ifdef __TURBOC__ #include <alloc.h> #else #include <malloc.h> #define farfree(p) _ffree(p) #define farmalloc(n) _fmalloc(n) #endif
void main(void);
void main() { int old_mode; unsigned page_addr; char far *buffer;
old_mode = fg_getmode(); fg_setmode(19); buffer = farmalloc(fg_pagesize()+16); page_addr = FP_SEG(buffer) + (FP_OFF(buffer)+15)/16; fg_setentry(1,page_addr,2);
fg_setpage(1); fg_erase(); fg_setcolor(9); fg_text("This is page 1.",15); fg_waitkey(); � Chapter 8: Video Pages and Virtual Buffers 171
fg_copypage(1,0); fg_setentry(1,0,0); fg_waitkey();
farfree(buffer); fg_setmode(old_mode); fg_reset(); }
Virtual Buffers
Virtual buffers are blocks of conventional memory that you can treat as
video memory. They are much more general than virtual pages, as they are supported in all graphics video modes and can be smaller or larger than the actual page size. An application may have up to 32 virtual buffers open simultaneously. Each virtual buffer has its own independent clipping limits, which default to the entire virtual buffer. Any program that uses virtual buffers must initialize the virtual buffer environment by calling fg_vbinit once, before it calls any of Fastgraph's other virtual buffer routines. The fg_vbinit routine has no arguments and no return value.
In protected mode, and when using real mode compilers that support huge
arrays (far arrays whose size may exceed 64K), use fg_vbdefine to create virtual buffers. The fg_vbdefine routine defines a block of previously allocated memory as a virtual buffer. Usually this memory is allocated dynamically with the malloc or farmalloc functions in C or C++, the GlobalAllocPtr function in protected mode Pascal, or the ALLOCATE statement in protected mode FORTRAN. The fg_vbdefine routine returns a handle by which the virtual buffer is referenced in other Fastgraph routines. Two related virtual buffer routines are fg_vbundef, which releases a virtual buffer handle, and fg_vbhandle, which returns the active virtual buffer handle (or -1 if no virtual buffer is active).
The number of bytes required for a virtual buffer is simply its width in
pixels multiplied by its height in pixels, regardless of the current video mode. The virtual buffer layout is equally simple. For instance, a 320x200 virtual buffer requires 64,000 bytes. The first 320 bytes represent the first row of the virtual buffer, the next 320 bytes represent the second row, and so forth. Within each of the 200 such rows, each of the 320 bytes represents one pixel. This means, for example, the (0,0) pixel in the virtual buffer would be at offset 0, the (2,0) pixel would be at offset 2, and the (2,1) pixel would be at offset 322. In general, the offset of the (x,y) pixel is given by the formula y*virtual_buffer_width + x.
The method of dynamically allocating memory suitable for virtual buffers
is compiler and environment dependent. When using 32-bit protected mode, the virtual buffer memory resides in the program's default data segment and is referenced through a standard near pointer. In 16-bit environments, the virtual buffer memory is a huge array and is referenced through a far pointer. The following examples illustrate how to allocate memory for a 640x400 virtual buffer for each compiler that supports dynamic allocation of huge memory blocks. � 172 Fastgraph User's Guide
For Borland C++ (16-bit), Turbo C++, Turbo C:
char huge *buffer; buffer = (char huge *)farmalloc(640L*400L);
For Microsoft C/C++, QuickC, Visual C++, 16-bit WATCOM C/C++:
char huge *buffer; buffer = (char huge *)halloc(640L*400L,1);
For 32-bit C/C++ compilers:
char *buffer; buffer = (char *)malloc(640*400);
For Borland Pascal 7 (protected mode):
var buffer : pointer; buffer := GlobalAllocPtr(gmem_Fixed,Longint(640)*Longint(400));
For Microsoft FORTRAN PowerStation:
INTEGER*1 BUFFER[ALLOCATABLE](:) INTEGER STATUS ALLOCATE(BUFFER(640*400),STAT=STATUS)
Real mode BASIC, Pascal, and FORTRAN compilers have limited, if any,
support for huge arrays. In these environments, use fg_vballoc to create virtual buffers. The fg_vballoc routine uses the DOS allocate memory service to reserve virtual buffer memory. The supported BASIC compilers and real mode Turbo Pascal normally assign all unused conventional memory to an area called the far heap. At best, this will cause DOS memory allocation requests to fail, but more often it creates memory conflicts that manifest themselves later in your application. To solve this problem, you must tell the compiler to reduce the size of the far heap.
Real mode Pascal programmers must use the $M directive to reduce the far
heap size by the total space needed for all virtual buffers. If you wanted to use a 640x400 virtual buffer, for example, the following $M directive would reduce the far heap size by 256,000 bytes:
{$M 16384,0,256000}
BASIC programmers must use the SETMEM function to reduce the far heap
size by the total space needed for all virtual buffers, plus 16 bytes per virtual buffer. If you wanted to use a 640x400 virtual buffer in a BASIC program, the following SETMEM call would reduce the far heap size by 256,016 bytes:
SetMemStatus& = SETMEM(-256016)
After you're finished with a virtual buffer, its memory may be released
using fg_vbfree. You should use fg_vbfree only with virtual buffers created with fg_vballoc and not those created with fg_vbdefine, and you cannot use it on the active virtual buffer. As fg_vballoc and fg_vbfree are needed for real mode only, they are not present in the Fastgraph protected mode libraries. For �
Chapter 8: Video Pages and Virtual Buffers 173
virtual buffers created with fg_vbdefine, just use your compiler's standard
method for releasing dynamic memory blocks.
Once a virtual buffer is defined, you can activate it with fg_vbopen.
When a virtual buffer is active, most Fastgraph routines operate on that virtual buffer instead of video memory. This will continue until you call fg_vbclose, which redirects graphics operations back to the active video page. If you later want to activate the virtual buffer again, or if you want to switch to another virtual buffer previously created with fg_vbdefine, you can use fg_vbopen for this purpose.
Two of Fastgraph's more important virtual buffer routines are fg_vbpaste
and fg_vbcut. These routines move rectangular areas between the active virtual buffer and the active video page. The fg_vbcut routine copies an area from the active video page to the active virtual buffer. Similarly, fg_vbpaste copies an area from the active virtual buffer to the active video page. An especially useful property of fg_vbcut and fg_vbpaste is that they each remember the most recent active virtual buffer and video page. This feature makes it possible to move areas back and forth between a virtual buffer and video memory without continuously opening and closing the virtual buffer.
The fg_vbpaste routine performs a simple translation for pixel values
greater than the number of colors available in the current video mode. This could happen, for example, if you used fg_vbcut in a 256-color graphics mode and later used fg_vbpaste to display the virtual buffer contents in a 16-color graphics mode. Should this occur, fg_vbpaste will display pixels of color c in color c modulo n, where n is the number of colors available in the current video mode.
At this point, some example programs should help clarify the use of
virtual buffers. Our first example, 8-14, runs in the standard VGA/MCGA 320x200 256-color graphics mode (mode 19) and creates a virtual buffer twice as high and twice as wide as the screen size. This means we'll create a 640x400 virtual buffer requiring 256,000 bytes of conventional memory (conditional compilation sequences show how to allocate the virtual buffer memory for different compilers). If the virtual buffer was created successfully, the program calls fg_vbopen to activate the virtual buffer and then draws four 320x200 rectangles of different colors, one in each quadrant of the virtual buffer. It then uses fg_vbpaste to copy each rectangle to the active video page, followed by another call to show the center 320x200 portion of the virtual buffer (this will display equal parts of the four rectangles).
Example 8-14.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> #ifdef __TURBOC__ #include <alloc.h> #else #include <malloc.h> #endif
#define WIDTH 640 #define HEIGHT 400 �
174 Fastgraph User's Guide
void main(void);
void main() { int handle; int old_mode; #ifdef FG32 char *buffer; #else char huge *buffer; #endif
/* initialize the video environment */
fg_initpm(); old_mode = fg_getmode(); fg_setmode(19); fg_vbinit();
/* set up a 640x400 virtual buffer */
#ifdef FG32 buffer = (char *)malloc(WIDTH*HEIGHT); #elif defined(__TURBOC__) buffer = (char huge *)farmalloc((long)WIDTH*(long)HEIGHT); #else buffer = (char huge *)halloc((long)WIDTH*(long)HEIGHT,1); #endif if (buffer == NULL) { fg_setmode(old_mode); fg_reset(); printf("Could not create the virtual buffer.\n"); exit(1); } handle = fg_vbdefine(buffer,WIDTH,HEIGHT); fg_vbopen(handle);
/* draw a 320x200 rectangle in each virtual buffer quadrant */
fg_setcolor(9); fg_rect(0,319,0,199); fg_setcolor(10); fg_rect(320,639,0,199); fg_setcolor(11); fg_rect(0,319,200,399); fg_setcolor(12); fg_rect(320,639,200,399);
/* paste each rectangle to the 320x200 active video page */
fg_vbpaste(0,319,0,199,0,199); fg_waitkey(); fg_vbpaste(320,639,0,199,0,199); fg_waitkey(); fg_vbpaste(0,319,200,399,0,199); fg_waitkey(); � Chapter 8: Video Pages and Virtual Buffers 175
fg_vbpaste(320,639,200,399,0,199); fg_waitkey();
/* paste the center 320x200 subset of the virtual buffer */
fg_vbpaste(160,479,100,299,0,199); fg_waitkey();
/* close the virtual buffer */
fg_vbclose();
/* restore original video mode and exit */
fg_setmode(old_mode); fg_reset(); }
Calling fg_vbclose before the final fg_setmode call is necessary because
fg_setmode has no effect when a virtual buffer is active. If we didn't call fg_vbclose, the program would return to DOS in mode 19 instead of the original video mode.
If you instead wanted to allocate the virtual buffer memory with
fg_vballoc in example 8-14, the steps to create the virtual buffer would change as follows:
/* set up a 640x400 virtual buffer */
handle = fg_vballoc(WIDTH,HEIGHT); if (handle < 0) { fg_setmode(old_mode); fg_reset(); printf("Could not create the virtual buffer.\n"); exit(1); } fg_vbopen(handle);
If you create the virtual buffer with fg_vballoc, you also should use fg_vbfree to release the virtual buffer memory when it's no longer needed:
/* close the virtual buffer */
fg_vbclose(); fg_vbfree(handle);
Again, we recommend using fg_vballoc and fg_vbfree only with 16-bit compilers that do not provide easy methods for creating huge arrays.
Example 8-15 illustrates the use of the fg_vbcut routine, which
essentially performs the inverse operation of fg_vbpaste. That is, fg_vbcut copies a rectangular area from the active video page to the active virtual buffer. The program begins by drawing a 20x20 blue rectangle with a white border in the upper left corner of the active video page. After a keystroke, it sets up a 20x20 virtual buffer and calls fg_vbcut to copy the rectangle to � 176 Fastgraph User's Guide
the virtual buffer. The program then calls fg_vbpaste in a loop to display 16
copies of the virtual buffer contents across the bottom of the screen. Note
that example 8-15 uses a virtual buffer that is just 20 pixels square, or 400
bytes total. Because it is so small, we chose to declare a 400-byte array for
the virtual buffer instead of allocating its memory dynamically as in the
previous example. Note also that because the virtual buffer array size is less
than 64K bytes, we can declare it far instead of huge in 16-bit environments
(huge arrays less than 64K are functionally equivalent to far arrays).
Example 8-15.
#include <fastgraf.h>
#define WIDTH 20 #define HEIGHT 20
void main(void);
#ifdef FG32 char buffer[WIDTH*HEIGHT]; #else char far buffer[WIDTH*HEIGHT]; #endif
void main() { int handle; int old_mode; int x;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(19); fg_vbinit();
fg_setcolor(15); fg_rect(0,WIDTH-1,0,HEIGHT-1); fg_setcolor(9); fg_rect(1,WIDTH-2,1,HEIGHT-2); fg_waitkey();
handle = fg_vbdefine(buffer,WIDTH,HEIGHT); fg_vbopen(handle); fg_vbcut(0,WIDTH-1,0,HEIGHT-1,0,HEIGHT-1);
for (x = 0; x <= 320-WIDTH; x += WIDTH) fg_vbpaste(0,WIDTH-1,0,HEIGHT-1,x,199); fg_waitkey();
fg_vbclose(); fg_setmode(old_mode); fg_reset(); } � Chapter 8: Video Pages and Virtual Buffers 177
If you create a virtual buffer that is taller or wider than the page size
(or perhaps both taller and wider), it's possible to perform virtual buffer scrolling. To achieve a scrolling effect, you generally just call fg_vbpaste iteratively such that the source region in the virtual buffer increments gradually, while the destination region on the active video page stays the same. Depending on the video mode and the size of the scrolling region, you may need to include a delay factor between fg_vbpaste calls so the area being scrolled doesn't appear to jump immediately to its ultimate destination.
Example 8-16 performs virtual buffer scrolling. This example runs in the
XVGA 320x200 256-color graphics mode (mode 20) and creates a 1000x50 virtual buffer using the method of example 8-14. The program fills the virtual buffer with a series of one-pixel wide rectangles, each 50 pixels high and in alternating colors. The actual scrolling takes place in the loop containing the two fg_vbpaste calls. We'll define a 100x50 area in the middle of the visual page, with horizontal extremes between 110 and 209, and vertical extremes between 75 and 124, as our scrolling region. We'll scroll the top half (25 pixels) of the virtual buffer from right to left while scrolling the bottom half from left to right. In other words, we'll be moving two 100x25 subsets of the virtual buffer through the scrolling region.
The first fg_vbpaste call scrolls the top half of the virtual buffer. The
starting x coordinate defining the region to transfer from the virtual buffer ranges from 0 to 900 in one-pixel increments, and the width of the transfer region is always 100 pixels. The height of the transfer region remains constant at 25 pixels (virtual buffer rows 0 to 24). The destination position is the upper half of the scrolling region on the visual page; its lower left corner is at x=110 and y=99.
The second fg_vbpaste call, which scrolls the bottom half of the virtual
buffer but in the opposite direction, behaves similarly. In this case, the starting x coordinate in the virtual buffer decreases from 900 to 0 in one- pixel steps, and its width is always 100 pixels. The height of the transfer region is again 25 pixels, but this time it uses rows 25 to 49 in the virtual buffer. The destination position is the lower half of the scrolling region on the visual page; its lower left corner is at x=110 and y=124.
Example 8-16.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> #ifdef __TURBOC__ #include <alloc.h> #else #include <malloc.h> #endif
#define WIDTH 1000 #define HEIGHT 50
void main(void);
void main() { int handle; �
178 Fastgraph User's Guide
int old_mode; int x; #ifdef FG32 char *buffer; #else char huge *buffer; #endif
/* initialize the video environment */
fg_initpm(); old_mode = fg_getmode(); fg_setmode(20); fg_vbinit();
/* fill the screen with light blue pixels */
fg_setcolor(9); fg_fillpage();
/* set up the virtual buffer */
#ifdef FG32 buffer = (char *)malloc(WIDTH*HEIGHT); #elif defined(__TURBOC__) buffer = (char huge *)farmalloc((long)WIDTH*(long)HEIGHT); #else buffer = (char huge *)halloc((long)WIDTH*(long)HEIGHT,1); #endif if (buffer == NULL) { fg_setmode(old_mode); fg_reset(); printf("Could not create the virtual buffer.\n"); exit(1); } handle = fg_vbdefine(buffer,WIDTH,HEIGHT); fg_vbopen(handle);
/* fill the virtual buffer with a series of narrow rectangles */
for (x = 0; x < WIDTH; x++) { fg_setcolor(x); fg_rect(x,x,0,HEIGHT-1); }
/* scroll the virtual buffer through a 100x50 window on the */ /* visual page, such that the top half scrolls left and the */ /* bottom half scrolls right */
for (x = 0; x < WIDTH-99; x++) { fg_vbpaste(x,x+99,0,24,110,99); fg_vbpaste(WIDTH-100-x,WIDTH-1-x,25,49,110,124); } fg_waitkey();
/* close the virtual buffer */ � Chapter 8: Video Pages and Virtual Buffers 179
fg_vbclose();
/* restore original video mode and exit */
fg_setmode(old_mode); fg_reset(); }
The last virtual buffer example program we'll present in this chapter is
a version of example 8-12 modified to work with virtual buffers. Example 8-12 used a logical page in conventional memory to preserve the visual page contents across video mode switches, with some help from Fastgraph's fg_getentry and fg_setentry routines. Example 8-17 illustrates how you can accomplish the same thing with a virtual buffer. It runs in the 320x240 256- color graphics mode (mode 22) and uses a virtual buffer whose size is identical to the screen resolution. After creating the virtual buffer, the program fills the visual page with blue pixels and draws a white border around it. It then uses fg_vbcut to copy the screen contents to the virtual buffer. Like example 8-12, the program temporarily switches back to the original video mode and waits for a keystroke. It then reverts to mode 22 and uses fg_vbpaste to restore the screen contents.
Example 8-17.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> #ifdef __TURBOC__ #include <alloc.h> #else #include <malloc.h> #endif
void main(void);
void main() { int handle; int old_mode; #ifdef FG32 char *buffer; #else char huge *buffer; #endif
fg_initpm(); old_mode = fg_getmode(); fg_setmode(22); fg_vbinit();
#ifdef FG32 buffer = (char *)malloc(320*240); #elif defined(__TURBOC__) buffer = (char huge *)farmalloc(320L*240L); �
180 Fastgraph User's Guide
#else buffer = (char huge *)halloc(320L*240L,1); #endif if (buffer == NULL) { fg_setmode(old_mode); fg_reset(); printf("Could not create the virtual buffer.\n"); exit(1); } handle = fg_vbdefine(buffer,320,240);
fg_setcolor(9); fg_fillpage(); fg_setcolor(15); fg_box(0,319,0,239); fg_vbopen(handle); fg_vbcut(0,319,0,239,0,239); fg_vbclose(); fg_waitkey();
fg_setmode(old_mode); fg_cursor(0); fg_setcolor(15); fg_text("Press any key.",14); fg_waitkey();
fg_setmode(22); fg_vbopen(handle); fg_vbpaste(0,319,0,239,0,239); fg_waitkey();
fg_vbclose(); fg_setmode(old_mode); fg_reset(); }
Fastgraph includes other functions for working with virtual buffers, but
we'll defer our discussion of them until later chapters.
Summary of Video Page and Virtual Buffer Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_ALLOCATE creates a virtual video page. The amount of memory required
depends on the current video mode. This routine has no effect if it references a physical or logical video page.
FG_ALLOCEMS creates a logical page in expanded memory (EMS). The amount
of memory required depends on the current video mode and video buffer dimensions. This routine has no effect if it references a physical or virtual �
Chapter 8: Video Pages and Virtual Buffers 181
video page. In protected mode, fg_initems always fails, so fg_allocems is
effectively disabled.
FG_ALLOCXMS creates a logical page in extended memory (XMS). The amount
of memory required depends on the current video mode and video buffer dimensions. This routine has no effect if it references a physical or virtual video page. In protected mode, fg_initxms always fails, so fg_allocxms is effectively disabled.
FG_COPYPAGE transfers the contents of one video page to another. The
pages may be physical, virtual, or logical video pages. If both pages are logical pages, they must exist in the same type of memory. This routine always applies to video pages, even when a virtual buffer is active.
FG_DEFPAGES defines the SVGA banks for the source and destination page
numbers when using Fastgraph's block transfer routines with extended video pages.
FG_FINDPAGE finds an available video page number for a virtual or logical
page.
FG_FREEPAGE releases a virtual or logical video page created with
fg_allocate, fg_alloccms, fg_allocems, or fg_allocxms. This routine has no effect if it references a physical video page, or a virtual page that was never created.
FG_GETADDR returns the real mode segment address or protected mode
segment selector for the active video page.
FG_GETENTRY retrieves the type and address of a physical, virtual, or
logical video page. This routine is useful for saving virtual or logical page contents across video mode changes.
FG_GETPAGE returns the active video page number.
FG_GETVPAGE returns the visual video page number.
FG_INITEMS initializes expanded memory for use with Fastgraph's logical
pages. In protected mode, the expanded memory initialization will always fail.
FG_INITXMS initializes extended memory for use with Fastgraph's logical
pages. In protected mode, the extended memory initialization will always fail.
FG_PAGESIZE returns the video page size in bytes for the current video
mode. The page size is always the video page size, even when a virtual buffer is active.
FG_RESIZE changes the dimensions of a video page in EGA and VGA graphics
modes. This function has no effect when a virtual buffer is active.
FG_SETENTRY specifies the type and address of a physical, virtual, or
logical video page. For logical pages, it further specifies if the page resides in conventional, expanded, or extended memory. This routine is useful for saving virtual or logical page contents across video mode changes, or for manual creation of virtual and logical pages. � 182 Fastgraph User's Guide
FG_SETPAGE establishes the active video page. It may be a physical or
virtual page.
FG_SETVPAGE establishes the visual video page. It may be a physical or
virtual page.
FG_VBALLOC creates a virtual buffer of the specified size. The memory for
the virtual buffer is allocated automatically. This routine should be used instead of fg_vbdefine for real mode compilers that do not support huge memory blocks (that is, far blocks larger than 64K bytes). The fg_vballoc routine is not present in Fastgraph's protected mode libraries.
FG_VBCLOSE closes the active virtual buffer and directs graphics output
back to the active video page.
FG_VBCUT copies a rectangular region from the active video page to the
active virtual buffer.
FG_VBDEFINE creates a virtual buffer of the specified size.
FG_VBFREE releases a virtual buffer's handle and frees the memory
allocated to a virtual buffer created with fg_vballoc. The fg_vbfree routine is not present in Fastgraph's protected mode libraries.
FG_VBHANDLE returns the handle for the active virtual buffer, or -1 if no
virtual buffer is active.
FG_VBINIT initializes Fastgraph's virtual buffer environment. This
routine must be called once, before any other routines that reference virtual buffers.
FG_VBOPEN makes an existing virtual buffer the active virtual buffer.
FG_VBPASTE copies a rectangular region from the active virtual buffer to
the active video page.
FG_VBUNDEF releases the handle associated with a virtual buffer.
Chapter 9
Image Files � 184 Fastgraph User's Guide
Overview
Within the context of Fastgraph, an image is a rectangular area
containing some type of picture. An image might be something as simple as a pointing hand icon, or as detailed as the dashboard of a sports car. Fastgraph includes several routines to display, retrieve, and manipulate images. In this chapter we'll begin our discussion of images by looking at the PCX, GIF, FLI/FLC, and pixel run image file formats Fastgraph supports, as well as the routines available for displaying and creating image files in these formats.
PCX Files
The PCX file format was originally developed by ZSoft Corporation for
their commercial paint program, PC Paintbrush. It has evolved into one of the more popular image file formats because so many products can read and write PCX files to at least some extent. Fastgraph includes routines for displaying and creating PCX files, as well as other PCX support functions.
The fg_showpcx routine displays an image stored in a PCX file. It can
position the image using the coordinate information in the PCX header, or such that its upper left corner is at the graphics cursor position on the active video page. The first argument to fg_showpcx is the name of the PCX file (it may include a path name), and its second argument is a bit mask that controls how the image is displayed. The file name must be terminated with a null character, so BASIC, FORTRAN, and Pascal programmers will need to store a zero byte as the last character of the file name string. The fg_showpcx routine cannot display PCX images in virtual buffers. A separate routine, fg_loadpcx, is provided for this purpose and will be described later in this section.
In the current version of Fastgraph, only the low-order three bits (bits
0 to 2) of the bit mask argument are meaningful. The following table summarizes the meanings of these bits.
Bit Value Meaning
0 0 Use palette values stored in the PCX file 0 1 Use the current palette settings 1 0 Display image at position indicated in PCX header 1 1 Display image at current graphics position 2 0 Display image data from the PCX file 2 1 Display image data from the fg_imagebuf buffer
All other bits are reserved and should be zero to guarantee compatibility with future releases. The fg_showpcx routine returns a value of 0 if successful, 1 if the specified file wasn't found, and 2 if the file is not a PCX file.
The fg_makepcx routine creates a PCX file from the specified rectangular
region of the active video page or virtual buffer. Its first four arguments define the minimum x, maximum x, minimum y, and maximum y screen space coordinates of the region (the minimum x coordinate is reduced to a byte boundary if necessary). Its fifth argument is the name of the PCX file to create (it may include a path name). As with fg_showpcx, the file name must be terminated with a null character. If an identically named file exists, it is �
Chapter 9: Image Files 185
overwritten. The fg_makepcx routine returns a value of 0 if successful, and 1
if the PCX file was not created.
Example 9-1 uses fg_showpcx and fg_makepcx to create a new PCX file from
selected rows of an existing 256-color 320x200 PCX file. As written, the program uses the file CORAL.PCX to create NEW.PCX, but it could easily be extended to work with any PCX files. The call to fg_showpcx displays the image in CORAL.PCX using the screen position and palette settings defined in the PCX file. After waiting for a keystroke, the program calls fg_makepcx to create a PCX file named NEW.PCX from pixel rows 80 through 99 of the original image. In case the program encounters any problems, it prints an error message before exiting.
Example 9-1.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode; int read_status, write_status;
fg_initpm(); if (fg_testmode(19,1) == 0) { printf("This program requires a 320 "); printf("x 200 MCGA graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(19);
read_status = fg_showpcx("CORAL.PCX",0); fg_waitkey(); if (read_status == 0) write_status = fg_makepcx(0,319,80,99,"NEW.PCX"); else write_status = 1;
fg_setmode(old_mode); fg_reset();
if (read_status == 1) printf("CORAL.PCX not found.\n"); else if (read_status == 2) printf("CORAL.PCX is not a PCX file.\n"); if (write_status == 1) printf("NEW.PCX not created.\n"); }
In the Tandy/PCjr 16-color graphics mode (mode 9) and the native EGA
graphics modes (modes 13 through 16), the palette registers are not readable. Hence, fg_makepcx will use the default palette settings when used in these � 186 Fastgraph User's Guide
video modes on Tandy and EGA systems. Displaying a PCX file at a lower
resolution (for example, a 640x480 PCX file at 320x200) will truncate the
display on the right and on the bottom. This effectively displays the upper
left corner of the image. The fg_showpcx and fg_makepcx routines have no
effect in text video modes or in the Hercules low-resolution graphics mode.
If you want to display a PCX file in a virtual buffer, you must use
Fastgraph's fg_loadpcx routine instead of fg_showpcx. The fg_loadpcx parameters and return values are identical to those of fg_showpcx, but the image destination is a virtual buffer and not video memory. We found it preferable to create a separate function for loading PCX images into virtual buffers because PCX files closely resemble the structure of video memory. The fg_showpcx routine is optimized to take advantage of this, while fg_loadpcx must perform the additional task of converting the pixel data to the virtual buffer format.
Example 9-2 shows how to display a PCX image in a virtual buffer with
fg_loadpcx. The CORAL.PCX file used in this example is a 320x200 image, so the required virtual buffer size is 64,000 bytes. After creating and opening the virtual buffer, the program calls fg_loadpcx to display the image in the virtual buffer. If successful, it makes the image visible by copying the virtual buffer contents to the visual page using fg_vbpaste.
Example 9-2.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> #ifdef __TURBOC__ #include <alloc.h> #else #include <malloc.h> #endif void main(void);
void main() { int handle; int old_mode; int status; #ifdef FG32 char *buffer; #else char huge *buffer; #endif
fg_initpm(); if (fg_testmode(19,1) == 0) { printf("This program requires a 320 "); printf("x 200 MCGA graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(19); fg_vbinit(); � Chapter 9: Image Files 187
#ifdef FG32 buffer = (char *)malloc(64000); #elif defined(__TURBOC__) buffer = (char huge *)farmalloc(64000L); #else buffer = (char huge *)halloc(64000L,1); #endif if (buffer == NULL) { fg_setmode(old_mode); fg_reset(); printf("Could not create the virtual buffer.\n"); exit(1); } handle = fg_vbdefine(buffer,320,200); fg_vbopen(handle);
status = fg_loadpcx("CORAL.PCX",0); if (status == 0) { fg_vbpaste(0,319,0,199,0,199); fg_waitkey(); }
fg_vbclose(); fg_setmode(old_mode); fg_reset();
if (status == 1) printf("CORAL.PCX not found.\n"); else if (status == 2) printf("CORAL.PCX is not a PCX file.\n"); }
Because their structure parallels that of video memory, PCX files are
specific to certain video modes. If you try to display a PCX file in an incompatible video mode, fg_showpcx will still display something, but it will be garbled. The following table summarizes the compatible video modes for PCX files.
If PCX file was You can display created in mode it in these modes
4, 5 4, 5 6, 11 6, 11, 13-18, 28, 29 9 9 13-18 13-18, 28, 29 19-27 19-27 28-29 13-18, 28, 29
Unlike fg_showpcx, fg_loadpcx does not display a PCX image directly to
video memory. The fg_loadpcx routine instead converts the mode-specific structure of the PCX file to the mode-independent virtual buffer format as it unpacks the image data. This overhead means fg_showpcx is faster than fg_loadpcx, but fg_loadpcx makes it possible to display any PCX file in any graphics video mode. The only problem occurs when displaying a PCX image with more colors than the current video mode supports (for example, displaying a � 188 Fastgraph User's Guide
256-color PCX in a 16-color mode). In this case, fg_vbpaste will display
pixels of color c in color c modulo n, where n is the number of colors
available in the current video mode.
The fg_pcxpal routine retrieves the palette of an image stored in a PCX
file. Its first argument is a PCX file name, terminated by a zero byte as with fg_showpcx. Its second argument is the address of the array that will receive the PCX palette values. The palette values are returned as RGB color components, each between 0 and 63. The first three bytes of this array will contain the RGB values for color 0, the next three for color 1, and so forth. The array size in bytes must be at least three times the number of colors in the PCX image. If successful, the fg_pcxpal function return value is the number of colors in the PCX palette, either 16 or 256. The possible error return values are -1 (file not found) and -2 (file is not a PCX file).
For video modes 18 and above, the fg_pcxpal palette values are suitable
for use with fg_setdacs. For the native EGA graphics modes (13 to 16), the palette values must be converted into mode-specific values (with fg_maprgb) before being used with fg_palette or fg_palettes. If the PCX file includes an extended (256-color) palette, fg_pcxpal will return the values in the extended palette. Otherwise, it will return the values from the 16-color palette in the PCX header.
Fastgraph's fg_pcxmode function determines the optimal video mode for
displaying a PCX file. By optimal, we mean the compatible video mode having the lowest resolution larger than or equal to the image dimensions. The fg_pcxmode routine has a single argument -- the address of a buffer that contains a 128-byte PCX file header. Specific values defined in certain fields of the PCX header determine which video mode is optimal. A positive return value from fg_pcxmode represents the optimal video mode number. The possible error returns are -1 if the buffer does not contain a valid PCX header, and -2 if fg_pcxmode cannot find any compatible video mode.
Another useful PCX support function is fg_pcxrange, which returns the
image position information from the PCX header. The first fg_pcxrange argument is the address of a buffer containing a 128-byte PCX file header. The remaining four arguments receive the minimum x, maximum x, minimum y, and maximum y values of the corresponding PCX image. You can use the image extents to determine the image dimensions -- for example, the width of a PCX image would be maximum_x - minimum_x + 1.
How do we get the header from a PCX file into the buffer passed to
fg_pcxmode or fg_pcxrange? The easiest way is with the fg_pcxhead function. Its first argument is the name of the PCX file from which to retrieve the header (as before, the file name must be null-terminated). The second argument is the address of the buffer that will receive the PCX header. The size of this buffer must be at least 128 bytes. If successful, fg_pcxhead returns zero. Otherwise, the return value is -1 if the specified file could not be opened, or -2 if the file is not a PCX file. After successfully reading the PCX header, you can pass it to fg_pcxmode to determine the optimal video mode for the PCX file. Full information about the 128-byte PCX file header appears in Appendix H.
Example 9-3 uses Fastgraph's fg_pcxhead, fg_pcxmode, fg_pcxpal, and
fg_pcxrange routines to obtain information about the CORAL.PCX file. It �
Chapter 9: Image Files 189
displays the optimal video mode number for displaying the image, the image
dimensions, and the image's first 16 color palette values.
Example 9-3.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int i, j; int mode, status; int minx, maxx, miny, maxy; unsigned char PCXpal[768]; unsigned char header[128];
fg_initpm(); status = fg_pcxhead("CORAL.PCX",header); if (status == -1) { printf("Can't open CORAL.PCX.\n"); exit(1); } else if (status == -2) { printf("CORAL.PCX is not a PCX file.\n"); exit(1); }
mode = fg_pcxmode(header); printf("Optimal display mode is %d.\n",mode);
fg_pcxrange(header,&minx,&maxx,&miny,&maxy); printf("Image size is %d by %d pixels.\n",maxx-minx+1,maxy-miny+1);
fg_pcxpal("CORAL.PCX",PCXpal); printf("First 16 palette values are:\n"); j = 0; for (i = 0; i < 16; i++) { printf(" color %2d: R=%2d G=%2d B=%2d\n", i,PCXpal[j],PCXpal[j+1],PCXpal[j+2]); j += 3; } }
GIF Files
The GIF file format was created by CompuServe, Inc., as a transmission
format for images and graphics data across the CompuServe network. It has evolved into what is probably the most popular image file format in use today. GIF files are especially prevalent on bulletin boards and electronic data networks because their efficient image compression results in less storage space and faster transmission times than other image file formats. GIF, pronounced "jif", is an acronym for Graphics Interchange Format. The format is � 190 Fastgraph User's Guide
the copyright property of CompuServe, Inc., whose GIF specification "grants a
limited, non-exclusive, royalty-free license for the use of the Graphics
Interchange Format in computer software; computer software utilizing GIF must
acknowledge ownership of the Graphics Interchange Format and its Service Mark
by CompuServe, Inc., in user and technical documentation".
Two GIF specifications, released in 1987 and 1989, are defined. The 1989
specification (known as "89a") is a superset of the original 1987 specification (known as "87a"). Fastgraph's GIF file display routine can handle either 87a or 89a files. For maximum portability, the GIF file creation routine always produces files conforming to the 87a specification.
The fg_showgif routine displays an image stored in a GIF file. It can
position the image using the coordinate information in the GIF header, or such that its upper left corner is at the graphics cursor position on the active video page or virtual buffer. The fg_showgif arguments are the same as for fg_showpcx, except the file name must of course reference a GIF file rather than a PCX file. Likewise, the fg_showgif return values are analogous to those of fg_showpcx.
The fg_makegif routine creates a GIF file from the specified rectangular
region of the active video page or virtual buffer. Its arguments and return value are analogous to those of fg_makepcx.
Example 9-4 uses fg_showgif and fg_makegif to create a new GIF file from
selected rows of an existing 256-color 320x200 GIF file. Similar to example 9-1, the program uses the file CORAL.GIF to create NEW.GIF, but it could easily be extended to work with any GIF files. The call to fg_showgif displays the image in CORAL.GIF using the screen position and palette settings defined in the GIF file. After waiting for a keystroke, the program calls fg_makegif to create a GIF file named NEW.GIF from pixel rows 80 through 99 of the original image. In case the program encounters any problems, it prints an error message before exiting.
Example 9-4.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode; int read_status, write_status;
fg_initpm(); if (fg_testmode(19,1) == 0) { printf("This program requires a 320 "); printf("x 200 MCGA graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(19);
read_status = fg_showgif("CORAL.GIF",0); � Chapter 9: Image Files 191
fg_waitkey(); if (read_status == 0) write_status = fg_makegif(0,319,80,99,"NEW.GIF"); else write_status = 1;
fg_setmode(old_mode); fg_reset();
if (read_status == 1) printf("CORAL.GIF not found.\n"); else if (read_status == 2) printf("CORAL.GIF is not a GIF file.\n"); if (write_status == 1) printf("NEW.GIF not created.\n"); }
Like fg_makepcx, the fg_makegif routine will use the default palette
settings when running on Tandy and EGA systems. Displaying a GIF file at a lower resolution (for example, a 640x480 GIF file at 320x200) will truncate the display on the right and on the bottom. This effectively displays the upper left corner of the image. Unlike PCX files, GIF files do not exhibit compatibility problems between 16-color and 256-color graphics modes. When fg_showgif displays a 256-color GIF in a 16-color mode, it displays pixels of color c in color c modulo 16. The fg_showgif and fg_makegif routines have no effect in text video modes, or in CGA and Hercules graphics modes.
Fastgraph includes additional GIF support routines analogous to those for
PCX files. The fg_gifpal routine retrieves the palette of an image stored in a GIF file. If the GIF file includes a local palette for the first image, fg_gifpal will return the values from the local palette. Otherwise, fg_gifpal will return the values from the GIF file's global palette. The fg_gifmode function determines the optimal video mode for displaying a GIF file. The fg_gifrange routine returns the image position information from the GIF header. The fg_gifhead routine reads a GIF file's global header and first local header into a 23-byte array (full information about the headers appears in Appendix H). The parameters and return values for these routines are the same as for their PCX counterparts.
Example 9-5 uses Fastgraph's fg_gifhead, fg_gifmode, fg_gifpal, and
fg_gifrange routines to obtain information about the CORAL.GIF file. It displays the optimal video mode number for displaying the image, the image dimensions, and the image's first 16 palette values.
Example 9-5.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int i, j; int mode, status; �
192 Fastgraph User's Guide
int minx, maxx, miny, maxy; unsigned char GIFpal[768]; unsigned char header[23];
fg_initpm(); status = fg_gifhead("CORAL.GIF",header); if (status == -1) { printf("Can't open CORAL.GIF.\n"); exit(1); } else if (status == -2) { printf("CORAL.GIF is not a GIF file.\n"); exit(1); }
mode = fg_gifmode(header); printf("Optimal display mode is %d.\n",mode);
fg_gifrange(header,&minx,&maxx,&miny,&maxy); printf("Image size is %d by %d pixels.\n",maxx-minx+1,maxy-miny+1);
fg_gifpal("CORAL.GIF",GIFpal); printf("First 16 palette values are:\n"); j = 0; for (i = 0; i < 16; i++) { printf(" color %2d: R=%2d G=%2d B=%2d\n", i,GIFpal[j],GIFpal[j+1],GIFpal[j+2]); j += 3; } }
FLI and FLC files
FLI and FLC files (collectively called flic files) contain sequences of
image frames that can be displayed in rapid succession to achieve the illusion of movement (this is called playing a flic file). FLI files are produced by Autodesk Animator and always have a 320x200 resolution, while FLC files are produced by Autodesk Animator Pro and can have any resolution. Fastgraph's flic file routines work with both FLI and FLC files, but they are restricted to 256-color graphics modes because flic files always contain 256-color images. The first frame of a flic file is usually a compressed version of the entire image, while later frames are compressed versions of the differences between that frame and the previous frame. This compression scheme is often called delta compression in flic file literature.
Fastgraph includes both high-level and low-level routines for working
with flic files. The most important high-level routine, fg_showflic, plays the entire contents of a flic file any number of times. It can position the image such that its upper left corner is at the screen origin or at the graphics cursor position on the active video page or vitual buffer. The fg_showflic routine expects three arguments. The first is the flic file name, which may include a path name, but must be null- terminated. The second specifies the number of times to play the flic file. If the play count is zero, fg_showflic will play it continuously. The fg_showflic routine will stop playing the flic �
Chapter 9: Image Files 193
file if the Escape key is pressed. Note that this is the only way to stop
playing the flic file if the play count is zero (continuous play).
The third fg_showflic argument is a bit mask that controls how the image
is displayed. In the current version of Fastgraph, only the low-order three bits (bits 0 to 2) of the bit mask argument are meaningful. The following table summarizes the meanings of these bits.
Bit Value Meaning 0 0 Delay between frames as indicated in flic header 0 1 No delay between frames 1 0 Display image relative to screen origin 1 1 Display image relative to current graphics position 2 0 Display image data from the specified flic file 2 1 Display image data from the fg_imagebuf buffer 4 0 Use palette data in flic file 4 1 Ignore palette data in flic file
All other bits are reserved and should be zero to guarantee compatibility with future releases. The fg_showflic routine returns a value of 0 if successful, 1 if the specified file wasn't found, and 2 if the file is not a flic file.
Example 9-6 is a simple flic file player. It uses the standard VGA/MCGA
256-color graphics mode (mode 19) to play the flic file GLASS.FLI, one of the examples supplied with Autodesk Animator. The upper left corner of the flic file will be at the screen origin, with a delay between frames as defined in the flic file header.
Example 9-6. #include <fastgraf.h> #include <stdio.h> void main(void);
void main(void) { int status;
fg_initpm(); fg_setmode(19);
status = fg_showflic("GLASS.FLI",1,0); if (status == 0) fg_waitkey();
fg_setmode(3); fg_reset();
if (status == 1) printf("GLASS.FLI not found.\n"); else if (status == 2) printf("GLASS.FLI is not an FLI or FLC file.\n"); }
Fastgraph includes additional flic support routines similar to those for
PCX and GIF files. The fg_flichead routine reads the specified flic file's
�
194 Fastgraph User's Guide
128-byte header (full information about the header appears in Appendix H). The
fg_flicmode function determines the optimal video mode for playing a flic
file. Its only argument is a 128-byte array containing a flic file header
returned by fg_flichead. If successful, it returns the optimal video mode
number for playing the flic image. If the array does not contain a valid flic
file header, fg_flicmode returns -1. The fg_flicsize routine returns the image
dimensions from the flic header. Its first argument is a 128-byte flic header
array, and is remaining two arguments receive the image width and height in
pixels. Example 9-7 uses these three routines to obtain information about the
GLASS.FLI file. It displays the optimal video mode number for playing the flic
file, as well as the image dimensions.
Example 9-7.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int mode, status; int width, height; unsigned char header[128];
fg_initpm(); status = fg_flichead("GLASS.FLI",header); if (status == -1) { printf("Can't open GLASS.FLI.\n"); exit(1); } else if (status == -2) { printf("GLASS.FLI is not a FLI or FLC file.\n"); exit(1); }
mode = fg_flicmode(header); printf("Optimal display mode is %d.\n",mode);
fg_flicsize(header,&width,&height); printf("Image size is %d by %d pixels.\n",width,height); }
Fastgraph's low-level flic routines provide the ability to display flic
files one frame at a time. This is desirable when your program must perform other tasks between frames, or for playing two or more flic files at the same time. To use Fastgraph's low-level flic routines, call fg_flicopen for each flic file. The first fg_flicopen argument is the flic file name. The second argument is a 16-byte array that will receive a context descriptor for the flic file. You must create a context descriptor with fg_flicopen for each flic file you'll access with the low-level flic file routines (the number of flic files you can have open at any one time is limited by the FILES specifier in your CONFIG.SYS file). The context descriptor is then passed to other routines when accessing the flic file. If successful, fg_flicopen fills the context descriptor, positions the flic file at the first frame, and returns zero. The �
Chapter 9: Image Files 195
possible error return values are -1 (file not found) and -2 (file is not an
FLI or FLC file).
The fg_flicplay routine plays one or more frames from a flic file and
leaves the file positioned at the beginning of the next frame. Its three arguments are the same as for fg_showflic except the first argument is a context descriptor instead of a flic file name. The fg_flicskip routine advances over flic file frames. Its first argument is the flic file's context descriptor, and its second argument is the number of frames to skip (if the frame count is negative, the file position is reset to the first frame). Both routines return the number of frames played, which may be less than the number of frames requested if the end-of-file is reached. Fastgraph's last low-level flic routine, fg_flicdone, closes a flic file previously opened with fg_flicopen. Its only argument is the flic file's context descriptor.
Example 9-8 is similar to example 9-6, but it plays the GLASS.FLI file
one frame at a time using Fastgraph's low-level flic routines. It opens the flic file with fg_flicopen, which returns a 16-byte context descriptor for the file. If the file was opened successfully, the program plays each frame by calling fg_flicplay in a loop, waiting for a keystroke between each frame (note that the bit mask passed to fg_flicplay has bit 0 set, as it's usually not too meaningful to delay between frames when playing frames individually). Eventually we'll reach the end-of-file, indicated by an fg_flicplay return value of zero. When this occurs, the program calls fg_flicdone and exits.
Example 9-8.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main(void) { int frames; int status; char context[16];
fg_initpm(); fg_setmode(19);
status = fg_flicopen("GLASS.FLI",context); if (status == 0) { do { frames = fg_flicplay(context,1,1); fg_waitkey(); } while (frames > 0); fg_flicdone(context); }
fg_setmode(3); fg_reset();
if (status == -1) printf("GLASS.FLI not found.\n"); else if (status == -2) �
196 Fastgraph User's Guide
printf("GLASS.FLI is not an FLI or FLC file.\n"); }
Pixel Run Files
Fastgraph also provides its own mode-independent image file format called
pixel run format. Pixel run files are useful in programs that must run in different video modes (but with the same resolution) because you can use the same image files for two-color modes as for 256-color modes. Two variations of the pixel run format exist -- standard pixel run files (SPR files) and packed pixel run files (PPR files). The packed pixel run format does not support 256- color images but will produce a smaller file if the image has 16 colors or less. Pixel run files do not include a header or any color palette information.
The best way to illustrate the pixel run file format is with an example.
Suppose we want to display a small triangle whose perimeter is a different color than its interior. To create the standard pixel run equivalent of this image, we must inscribe the triangle in a rectangular area. Hence, the pixel representation of our triangle might appear as shown here:
. . . . * . . . . . . . * x * . . . . . * x x x * . . . * x x x x x * . * * * * * * * * *
As shown in this diagram, our triangle image is nine pixels wide at its
base and five pixels high. The pixels indicated by an asterisk (*) are the triangle's perimeter, while those indicated by an x represent its interior points. The pixels shown as periods (.) are not part of the triangle itself, but they are part of the image. In this example, we can treat them as background pixels.
If we start at the lower left corner of the image and proceed to the
right, we could represent the first row of the image as nine pixels of color "asterisk". Such a group of consecutive identically colored pixels is called a pixel run, so a single pixel run describes the first row of the image. The row above this one is a bit more complex. It consists of five pixel runs: one pixel of color "period", followed by one of color "asterisk", then five of color "x", one of color "asterisk", and finally one of color "period".
While we could construct separate pixel runs for each row of the image,
notice that three of the five rows in our triangle begin with the same color pixel as the rightmost pixel in the previous row. Fastgraph's pixel run formats let you take advantage of this property by allowing pixel runs to wrap from one row to the next. This means we can represent the pixel run of color "period" extending from the right side of the second row to the left side of the third row as a single run of three pixels.
An standard pixel run (SPR) file is nothing more than such a sequence of
(color,count) pairs, as shown in the following diagram. �
Chapter 9: Image Files 197
byte 0 color for run 1
1 count for run 1
2 color for run 2
3 count for run 2
2n-2 color for run n
2n-1 count for run n
Each color is a value between 0 and 255 specifying the color index for that
pixel run. Each count is a value between 0 and 255 specifying the length in
pixels of that pixel run. If a single run exceeds 255 pixels, it must be
broken into two or more runs. For example, we could represent a pixel run of
length 265 as a run of length 255 followed by a run of length 10 of the same
color. Note that the space in bytes needed to store an SPR image is twice the
number of runs.
Fastgraph's fg_showspr routine displays an SPR file. Its first argument
is the name of the file containing the image (it may include a path name). The file name must be terminated with a null character, so BASIC, FORTRAN, and Pascal programmers will need to store a zero byte as the last character of the file name string. The second argument is the width in pixels of the image. The fg_showspr routine displays the image such that its lower left corner is at the graphics cursor position. The possible return values for fg_showspr are success (0) and file not found (1). To create an SPR file, use the fg_makespr routine. Its arguments and return values are the same as for fg_makepcx and fg_makegif.
Example 9-9 uses fg_showspr and fg_makespr to create a new SPR file from
selected rows of an existing 16-color 320x200 SPR file. Similar to examples 9-1 and 9-4, the program uses the file CORAL.SPR to create NEW.SPR, but it could easily be extended to work with any SPR files. The call to fg_move establishes the lower left corner of the screen as the graphics cursor position (contrast this with the upper left corner being the reference point for PCX, GIF, and flic files). The program then calls fg_showspr to display the image. After waiting for a keystroke, the program calls fg_makespr to create an SPR file named NEW.SPR from pixel rows 80 through 99 of the original image. In case the program encounters any problems, it prints an error message before exiting.
Example 9-9.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() �
198 Fastgraph User's Guide
{ int new_mode, old_mode; int read_status, write_status;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode); fg_move(0,199);
read_status = fg_showspr("CORAL.SPR",320); fg_waitkey(); if (read_status == 0) write_status = fg_makespr(0,319,80,99,"NEW.SPR"); else write_status = 1;
fg_setmode(old_mode); fg_reset();
if (read_status == 1) printf("CORAL.SPR not found.\n"); if (write_status == 1) printf("NEW.SPR not created.\n"); }
If you have an image that only uses the first 16 color indices (0 to 15),
you can use Fastgraph's packed pixel run (PPR) image format. This format packs two color values into each color byte, so it takes three bytes instead of four to represent two pixel runs. This means a PPR file is 25% smaller than its SPR equivalent. In each set of three bytes, the high four bits of the first byte contain the color of the first run, and the low four bits contain the color of the second run. The second byte contains the length of the first run, and the third byte contains the length of the second run.
The following diagram illustrates the structure of the packed pixel file.
In this example, the file is assumed to contain n pixel runs, where n is an even number. If n is odd, the byte offset for the last element is 3n/2 (truncated) instead of 3n/2-1, and the low four bits of the last color byte (that is, the color for pixel run n+1) are ignored.
7 4 3 0
byte 0 color for run 1 color for run 2
1 count for run 1
2 count for run 2
3 color for run 3 color for run 4 � Chapter 9: Image Files 199
4 count for run 3
5 count for run 4
3n/2-3 color for run n-1 color for run n
3n/2-2 count for run n-1
3n/2-1 count for run n
The structure of the PPR file allows for color values between 0 and 15,
and run lengths between 0 and 255. The space in bytes needed to store an image in PPR format is 1.5 times the number of runs, compared to twice the number of runs for the SPR format.
The fg_showppr and fg_makeppr routines display and create PPR files,
respectively. Their arguments and return values are the same as those of fg_showspr and fg_makespr. If we wanted to display PPR files instead of SPR files in example 9-9, all that's necessary is changing the fg_showspr and fg_makespr calls to fg_showppr and fg_makeppr.
Fastgraph's fg_dispfile routine displays both SPR and PPR files. The
first of its three arguments is the name of the image file (it may include a path name). The file name must be terminated with a null character, so BASIC, FORTRAN, and Pascal programmers will need to store a zero byte as the last character of the file name string. The second argument is the image width in pixels, and the third argument defines the image format (that is, SPR or PPR). As with other pixel run display routines, fg_dispfile displays the image such that its lower left corner is at the graphics cursor position.
Example 9-10 illustrates how to use fg_dispfile to display an image
stored in a pixel run file. The program displays two identical images, one in an SPR file and the other in a PPR file. Each image is a picture of the sea floor and some coral, as might be used for the background in an aquarium. The program runs in a 320x200 graphics mode, and the images fill the entire screen.
The SPR image is in file CORAL.SPR. The program uses fg_move to establish
the lower left corner of the screen as the graphics cursor position and then calls fg_dispfile to display the image. The value of fg_dispfile's third argument tells Fastgraph the image format. A value of 0 indicates the file contains an image in SPR format, while a value of 1 indicates an image in PPR format. As mentioned earlier, the image fills the entire screen, so its width is 320 pixels.
After waiting for a keystroke, the program clears the previous image from
the screen and then calls fg_dispfile to display the PPR image from the file CORAL.PPR. The program leaves the second image on the screen until another keypress, at which time it restores the original video mode and screen attributes and returns to DOS. � 200 Fastgraph User's Guide
Example 9-10.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_move(0,199); fg_dispfile("CORAL.SPR",320,0); fg_waitkey();
fg_erase(); fg_dispfile("CORAL.PPR",320,1); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
The SNAPSHOT utility distributed with Fastgraph is a terminate and stay
resident program (TSR) that can capture graphics mode screen images and save them in SPR files. Thus, you can easily create files with SNAPSHOT and display them with fg_showspr or fg_dispfile. Another TSR utility, GrabRGB, is useful for capturing RGB color values from 256-color images. Appendix A contains complete descriptions of the SNAPSHOT and GrabRGB utilities.
Display Patterns
Example 9-10 works well in the graphics video modes with 16 or 256
available colors. However, in the four-color CGA graphics modes the resulting image is not too good because of our limited color choices, and it would look even worse in the Hercules graphics mode. The Fastgraph routine fg_pattern allows you to associate a dither pattern (actually, any pixel sequence) with one of Fastgraph's 256 color indices appearing in a pixel run map. When displaying an SPR or PPR file, Fastgraph will use the pattern associated with that color index instead of displaying the color itself. �
Chapter 9: Image Files 201
The fg_pattern routine requires two integer arguments -- a color index
(between 0 and 255) and the display pattern defined for that color index. A display pattern's structure resembles the structure of video memory and is thus dependent on the current video mode. The following sections list the initial display patterns and explain how to construct new display patterns for different graphics video modes.
CGA four-color graphics modes
In the four-color CGA graphics modes (modes 4 and 5), the display pattern
consists of an 8-bit shift count followed by an 8-bit pixel pattern. Each pixel assumes a value between 0 and 3, so the pattern represents four pixels. In even-numbered pixel rows, Fastgraph uses the pixel pattern itself. In odd- numbered pixel rows, Fastgraph rotates the original pattern to the left by the number of bits specified by the shift count.
For example, if we are using the default CGA color palette, we could
create a darker shade of cyan by alternating cyan pixels (color 1, 01 binary) with white pixels (color 3, 11 binary), as shown here:
01 11 01 11
If we convert this pixel pattern to its hexadecimal equivalent, we get the
value 77.
To complete the display pattern, we need to determine the shift count. If
we use a shift count of zero, the resulting display will simply be a series of cyan and white vertical lines. What we really need is a checkerboard effect where a white pixel is above and below each cyan pixel, and vice versa. If we rotate the pattern one pixel (two bits) to the left, we will achieve the desired effect. That is, a shift count of two produces the following pixel patterns:
even-numbered rows 01 11 01 11 odd-numbered rows 11 01 11 01
Combining the shift count with the pixel pattern yields the display pattern 0277 hex. The shift count is normally a multiple of two; note that a zero shift count results in the same pattern being applied to all pixel rows.
For the CGA four-color graphics modes, fg_setmode establishes the
following initial display patterns:
color shift count hexadecimal index and pattern equivalent
0 0 00000000 0000 1 0 01010101 0055 2 0 10101010 00AA 3 0 11111111 00FF
These values are repeated as necessary to define color indices 4 to 255. That is, colors 4, 8, 12, ... , 252 use the same defaults as color 0. Colors 5, 9, 13, ... , 253 use the same defaults as color 1, and so forth. Also note that � 202 Fastgraph User's Guide
pattern 0000 represents four pixels of color 0, 0055 represents four pixels of
color 1, 00AA represents four pixels of color 2, and 00FF represents four
pixels of color 3.
CGA two-color graphics mode
In the two-color CGA graphics mode (mode 6), the display pattern also
consists of an 8-bit shift count followed by an 8-bit pixel pattern. Each pixel assumes the value 0 or 1, so the pattern represents eight pixels. In even-numbered pixel rows, Fastgraph uses the pixel pattern itself. In odd- numbered pixel rows, Fastgraph rotates the original pattern to the left by the number of bits specified by the shift count.
For example, we could create a lighter shade of white by alternating
black pixels (color 0) with white pixels (color 1), as shown here:
0 1 0 1 0 1 0 1
If we convert this pixel pattern to its hexadecimal equivalent, we get the
value 55.
To complete the display pattern, we need to determine the shift count. We
must rotate the pattern one pixel (one bit) to the left to achieve the checkerboard effect as in the CGA four color graphics modes. That is, a shift count of one produces the following pixel patterns:
even-numbered rows 0 1 0 1 0 1 0 1 odd-numbered rows 1 0 1 0 1 0 1 0
Combining the shift count with the pixel pattern yields the display pattern 0155 hex.
For the CGA two-color graphics mode, fg_setmode establishes the initial
display patterns such that all even-numbered color indices are assigned the value 0000, while all odd-numbered color indices are assigned the value 00FF. Note that pattern 0000 represents eight pixels of color 0, and 00FF represents eight pixels of color 1.
Tandy/PCjr 16-color graphics mode
In the Tandy/PCjr 16-color graphics mode (mode 9), the display pattern
also consists of an 8-bit shift count followed by an 8-bit pixel pattern. Each pixel assumes a value between 0 and 15, so the pattern represents two pixels. In even-numbered pixel rows, Fastgraph uses the pixel pattern itself. In odd- numbered pixel rows, Fastgraph rotates the original pattern to the left by the number of bits specified by the shift count.
For example, we could create a lighter shade of blue by alternating blue
pixels (color 1, 0001 binary) with white pixels (color 15, 1111 binary), as shown here:
0001 1111 � Chapter 9: Image Files 203
If we convert this pixel pattern to its hexadecimal equivalent, we get the value 1F.
To complete the display pattern, we need to determine the shift count.
Using the same process as in the CGA graphics modes, we must rotate the pattern one pixel (four bits) to the left to achieve the checkerboard effect. That is, a shift count of four produces the following pixel patterns:
even-numbered rows 0001 1111 odd-numbered rows 1111 0001
Combining the shift count with the pixel pattern yields the display pattern 041F hex. The shift count is normally zero or four; note that a zero shift count results in the same pattern being applied to all pixel rows.
For the Tandy/PCjr 16-color graphics modes, fg_setmode establishes the
initial display patterns such that color 0 is assigned the value 0000 (two pixels of color 0), color 1 is assigned the value 0011 (two pixels of color 1), color 2 is assigned the value 0022 (two pixels of color 2), and so forth. These values are repeated as necessary to define color indices 16 to 255. That is, colors 0, 16, 32, ... , 240 use the same defaults as color 0. Colors 1, 17, 33, ... , 241 use the same defaults as color 1, and so forth.
Hercules graphics modes
The structure of the display patterns for the Hercules graphics modes
(modes 11 and 12) is the same as two of the CGA graphics modes. For the standard Hercules graphics mode (mode 11), please refer to the discussion of CGA two-color (mode 6) display patterns. For the low-resolution Hercules graphics mode (mode 12), please refer to the discussion of the CGA four-color (mode 4) display patterns.
EGA/VGA/SVGA 16-color graphics modes
In the EGA/VGA/SVGA 16-color graphics modes (modes 13 to 16, 18, 28, and
29), the display pattern consists of two 4-bit color values (for consistency with the other video modes, we still pass the display pattern as a 16-bit or 32-bit quantity). Each pixel assumes a value between 0 and 15 (0 and 5 in the EGA monochrome graphics mode), so the pattern represents two pixels. In even- numbered pixel rows, Fastgraph uses the pixel pattern itself. In odd-numbered pixel rows, Fastgraph rotates the original pattern one pixel (four bits) to the left.
For example, we could create a lighter shade of blue by alternating blue
pixels (color 1, 0001 binary) with white pixels (color 15, 1111 binary), as shown here:
0001 1111
If we convert this pixel pattern to its hexadecimal equivalent, we get the
value 1F. The implied four-bit shift count produces the following pixel
patterns: �
204 Fastgraph User's Guide
even-numbered rows 0001 1111 odd-numbered rows 1111 0001
Extending the pixel pattern to a 16-bit or 32-bit quantity yields the display pattern 001F hex.
For the EGA/VGA/SVGA 16-color graphics modes, fg_setmode establishes the
initial display patterns such that color 0 is assigned the value 0000 (two pixels of color 0), color 1 is assigned the value 0011 (two pixels of color 1), color 2 is assigned the value 0022 (two pixels of color 2), and so forth. These values are repeated as necessary to define color indices 16 to 255. That is, colors 0, 16, 32, ... , 240 use the same defaults as color 0. Colors 1, 17, 33, ... , 241 use the same defaults as color 1, and so forth.
MCGA/VGA 2-color graphics mode
In the two-color MCGA/VGA graphics mode (mode 17), the display pattern
consists of two 1-bit color values (for consistency with the other video modes, we still pass the display pattern as a 16-bit or 32-bit quantity). Each pixel assumes the value 0 or 1, so the pattern represents two pixels. In even- numbered pixel rows, Fastgraph uses the pixel pattern itself. In odd-numbered pixel rows, Fastgraph rotates the original pattern one pixel (one bit) to the left.
For example, we could create a lighter shade of white by alternating
black pixels (color 0) with white pixels (color 1), as shown here:
0 1
If we convert this pixel pattern to its hexadecimal equivalent, we get the
value 01. The implied one-bit shift count produces the following pixel
patterns:
even-numbered rows 0 1 odd-numbered rows 1 0
Extending the pixel pattern to a 16-bit or 32-bit quantity yields the display pattern 0001 hex.
For the VGA/MCGA two-color graphics mode, fg_setmode establishes the
initial display patterns such that all even-numbered color indices are assigned the value 0000 (two pixels of color 0), while all odd-numbered color indices are assigned the value 0003 (11 binary, or two pixels of color 1).
256-color graphics modes
The 256-color graphics modes (modes 19 through 27) offer 262,144
different colors, so dithering is seldom (if ever) required. For this reason, fg_pattern has no effect in these video modes. �
Chapter 9: Image Files 205
An example
Example 9-11 illustrates the use of display patterns in several graphics
modes. This program runs in any 320x200 color graphics mode and displays the CORAL.PPR image with one or more of the color indices redefined. If the program runs in the standard CGA four-color mode (mode 4), it redefines the first 16 display patterns using the fg_pattern routine and the values in the CGApatterns array. In the Tandy/PCjr 16-color graphics mode (mode 9) and the EGA low-resolution graphics mode (mode 13), the program redefines color index 15 to produce an alternating gray and white dither pattern. In the MCGA 256- color mode (mode 19), display patterns are not available, so the program uses fg_setrgb to define color index 15 as slightly darker shade of gray than the default for color 7.
Example 9-11.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
int CGApatterns[] = { 0x0000,0x00FF,0x00FF,0x00FF, 0x02BB,0x0000,0x0222,0x0255, 0x00FF,0x00FF,0x00FF,0x0055, 0x00AA,0x00AA,0x00FF,0x0277 };
void main() { int color; int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
if (new_mode == 4) { fg_palette(0,0); for (color = 0; color < 16; color++) fg_pattern(color,CGApatterns[color]); } else if (new_mode == 9 || new_mode == 13) fg_pattern(15,0x04F7); else fg_setrgb(15,38,38,38);
fg_move(0,199); fg_showppr("CORAL.PPR",320); �
206 Fastgraph User's Guide
fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Controlling the Image Buffer Size
By default, all of Fastgraph's image file display and creation routines
use an internal 4,096-byte buffer. This buffer provides an intermediate storage area, making it possible to perform more efficient buffered I/O when reading or writing the image files. The fg_imagebuf routine lets you define your own buffer for this purpose (the buffer size is limited to 64K bytes in real mode and 16-bit protected mode). Larger buffers generally make image display and creation faster. This is especially true in protected mode and when playing flic files. Calling fg_setmode resets the fg_imagebuf buffer to its default 4K size.
The fg_imagebuf routine does not allocate storage for the internal
buffer. Rather, it just defines the array or dynamically allocated memory block to be used as the buffer. The first argument passed to fg_imagebuf is the address of this array or memory block, and the second argument is the internal buffer size in bytes, represented as an unsigned integer. In 32-bit modes, the address is passed as an ordinary near pointer, while in 16-bit modes it is passed as a far (segmented) pointer. Fastgraph uses a far pointer in 16-bit modes to avoid wasting valuable space in the default data segment, and it almost always results in the ability to use a larger buffer. In real mode Pascal programs, the space for the internal buffer must be allocated dynamically with the GetMem procedure because it provides the only way to pass something by far reference in Pascal. Protected mode Pascal programs can use either GetMem or the GlobalAllocPtr function to allocate the buffer memory. BASIC programs must pass the image buffer as a fixed-length string.
Example 9-12 shows how to use fg_imagebuf to define a larger buffer when
displaying the CORAL.PCX file. In this example, we'll use a 20,000-byte static array as the image buffer. This size was chosen because it's larger than the PCX file size, so fg_showpcx can read the entire PCX file in one pass.
Example 9-12.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#ifdef FG32 char buffer[20000]; #else char far buffer[20000]; #endif
void main() { int old_mode; � Chapter 9: Image Files 207
fg_initpm(); if (fg_testmode(19,1) == 0) { printf("This program requires a 320 "); printf("x 200 MCGA graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(19); fg_imagebuf(buffer,20000); fg_showpcx("CORAL.PCX",0); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
You don't need to create separate buffers for each image you display or
create. Once you define an internal image buffer with fg_imagebuf, Fastgraph will use that buffer until your program exits, or until you call fg_imagebuf with a buffer size equal to zero.
It's also possible to display PCX, GIF, and FLI/FLC images directly from
the buffer pointed to by fg_imagebuf. This can be quite useful, for instance, when we need to display the same image file several times because we only read the file from disk once. To do this, set bit 2 of the flags parameter when using Fastgraph's PCX, GIF, or FLI/FLC image display routines. This tells Fastgraph to retrieve the image data from the fg_imagebuf buffer rather than from the file itself. In protected mode applications, using this method usually provides better performance, especially when displaying FLI or FLC files. Example 9-13 shows how to display a PCX image stored in the fg_imagebuf buffer.
Example 9-13.
#include <fastgraf.h> #include <io.h> #include <stdio.h> #include <stdlib.h> void main(void);
#ifdef FG32 char buffer[20000]; #else char far buffer[20000]; #endif
void main() { int file_size; int old_mode; FILE *stream;
fg_initpm(); if (fg_testmode(19,1) == 0) { �
208 Fastgraph User's Guide
printf("This program requires a 320 "); printf("x 200 MCGA graphics mode.\n"); exit(1); }
stream = fopen("CORAL.PCX","rb"); file_size = (int)(filelength(fileno(stream))); fread(buffer,1,file_size,stream); fclose(stream);
old_mode = fg_getmode(); fg_setmode(19);
fg_imagebuf(buffer,file_size); fg_showpcx("",4); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
In example 9-13, we use a 20,000-byte array for the fg_imagebuf buffer.
The array used with fg_imagebuf must be large enough to hold the entire image file. Note that we pass the actual file size to fg_imagebuf (in this example, we assume the file size does not exceed 20,000 bytes). It is crucial that you specify the actual file size when displaying 256-color PCX files so Fastgraph can locate the extended (256-color) palette data that might follow the image data. You must also specify the actual file size when using Fastgraph's low- level flic support routines to play flic images from the fg_imagebuf buffer. For other types of image files, we can specify either the file size or the buffer size.
It's not necessary to pass a file name to the image display routines if
the image data resides in the fg_imagebuf buffer. In other words, the image display routines ignore the file name argument when bit 2 of the flags argument is set. However, you must still include a "place holder" argument where a file name would otherwise be expected. We recommend using the null string as in the fg_showpcx call of example 9-13, although any string can be used instead.
The maximum size of the image file we can display from the fg_imagebuf
buffer is of course limited to the buffer size. While this isn't in issue in 32-bit protected mode, it does impose an important restriction in real mode and 16-bit protected mode. The size of the fg_imagebuf buffer is limited to 64K bytes in 16-bit environments, meaning this feature applies only to image files that are 64K or less if you're using real mode or 16-bit protected mode.
Summary of Image File Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual. The image display and creation functions apply only to graphics video modes. �
Chapter 9: Image Files 209
FG_DISPFILE displays an image stored in a standard or packed pixel run
file. The image is positioned so that its lower left corner is at the current graphics position.
FG_FLICDONE closes the flic file associated with the specified context
descriptor.
FG_FLICHEAD reads a flic file header into a 128-byte buffer.
FG_FLICMODE determines the optimal video mode for the flic image
associated with the specified flic file header. The optimal mode is the 256- color graphics mode having the lowest resolution larger than or equal to the image dimensions.
FG_FLICOPEN opens a flic file for subsequent processing by Fastgraph's
other low-level flic file support routines. If successful, the file pointer will be positioned at the beginning of the first frame.
FG_FLICPLAY displays the next one or more frames in a flic file
previously opened with fg_flicopen.
FG_FLICSIZE returns the dimensions for the flic image associated with the
specified flic file header.
FG_FLICSKIP advances one or more frames in a flic file previously opened
with fg_flicopen. If the last frame played by fg_flicplay displayed the frame from the fg_imagebuf buffer, the frame position will be adjusted in the fg_imagebuf buffer. Otherwise, the flic file position itself will be adjusted.
FG_GIFHEAD reads the GIF file's global header and first local header into
a 23-byte buffer.
FG_GIFMODE determines the optimal video mode for displaying a GIF file.
The optimal mode is the video mode having the lowest resolution larger than or equal to the image dimensions.
FG_GIFPAL retrieves the palette of an image stored in a GIF file. The
palette values are returned as RGB color components, each between 0 and 63. If the GIF file includes a local palette for the first image, fg_gifpal will return the values from the local palette. Otherwise, fg_gifpal will return the values from the GIF file's global palette.
FG_GIFRANGE returns the image extents for the GIF image associated with
the specified GIF file header.
FG_IMAGEBUF specifies the size and address of the buffer used internally
when creating or displaying GIF, PCX, FLI/FLC, or SPR/PPR files. Fastgraph's default internal buffer size is 4,096 bytes. Image display or creation is typically faster when a larger buffer is used, especially in protected mode or when playing flic files. In 16-bit environments, the size of the fg_imagebuf buffer is limited to 64K bytes.
FG_LOADPCX loads a PCX image into the active virtual buffer. �
210 Fastgraph User's Guide
FG_MAKEGIF creates a GIF file from the specified rectangular region of
the active video page or virtual buffer. The region's extremes are expressed in screen space units. This routine is meaningful only in 16-color and 256- color graphics modes.
FG_MAKEPCX creates a PCX file from the specified rectangular region of
the active video page or virtual buffer. The region's extremes are expressed in screen space units.
FG_MAKEPPR creates a packed pixel run file from the specified rectangular
region of the active video page or virtual buffer. The region's extremes are expressed in screen space units.
FG_MAKESPR creates a standard pixel run file from the specified
rectangular region of the active video page or virtual buffer. The region's extremes are expressed in screen space units.
FG_PATTERN defines a display pattern for use when displaying pixel run
files in video modes that offer 16 or less colors.
FG_PCXHEAD reads a PCX file header into a 128-byte buffer.
FG_PCXMODE determines the optimal video mode for displaying a PCX file.
The optimal mode is the compatible video mode having the lowest resolution larger than or equal to the image dimensions.
FG_PCXPAL retrieves the palette of an image stored in a PCX file, and the
number of colors in the palette. The palette values are returned as RGB color components, each between 0 and 63. If the PCX file includes an extended (256-color) palette, fg_pcxpal will return the values in the extended palette. Otherwise, fg_pcxpal will return the values from the 16-color palette in the PCX header.
FG_PCXRANGE returns the image extents for the PCX image associated with
the specified PCX file header.
FG_SHOWGIF displays an image stored in a GIF file.
FG_SHOWFLIC displays an image stored in an FLI or FLC file (collectively
called flic files).
FG_SHOWPCX displays an image stored in a PCX file.
FG_SHOWPPR displays an image stored in a packed pixel run file. The image
will be positioned so its lower left corner is at the graphics cursor position of the active video page or virtual buffer.
FG_SHOWSPR displays an image stored in a standard pixel run file. The
image will be positioned so its lower left corner is at the graphics cursor position of the active video page or virtual buffer.
Chapter 10
Bitmapped Images � 212 Fastgraph User's Guide
Overview
In this chapter, we'll continue our discussion of images by concentrating
on an important class of images called bitmapped images. Fastgraph includes routines to display, retrieve, and manipulate bitmapped images in mode- specific and mode-independent formats. This chapter will discuss the Fastgraph routines that deal with both classes of bitmapped images.
Displaying bitmapped images is an essential part of animation with
Fastgraph. While the image files discussed in the previous chapter are useful for displaying backgrounds or importing pictures from other sources, an animation sequence can only achieve its speed through the bitmapped image display routines described in this chapter, along with the block transfer routines of the next chapter.
Mode-Independent Bitmapped Images
This section will discuss the image display routines that use the same
bitmapped image format for all graphics video modes. Another class of routines, described in the next section, use different formats for different video modes. While these mode-independent image display routines are more general, they achieve this generality at the sake of execution speed. This may especially be a concern if the image is large, or if speed is critical in an application (as in arcade-style graphics). For many programs, however, the mode-independent routines provide all the image display capability needed.
Let's begin by returning to an example of a very simple image -- the
triangle introduced in the previous chapter:
. . . . * . . . . . . . * x * . . . . . * x x x * . . . * x x x x x * . * * * * * * * * *
Recall that the triangle's perimeter is a different color than its interior pixels, and to use this image with Fastgraph, we must inscribe the triangle in a rectangular area. As before, our triangle is nine pixels wide at its base and five pixels high. The pixels indicated by an asterisk (*) are the triangle's perimeter, while those indicated by an x represent its interior points. We need to distinguish between these pixels because they will be different colors. The pixels shown as periods (.) are not part of the triangle itself. They are required to make the image rectangular, so from Fastgraph's perspective they are indeed part of the image.
The Fastgraph routine fg_drawmap is a suitable routine for drawing our
triangle. To use fg_drawmap, we must create separate bitmaps for each color in the image (excluding the points used to fill the rectangular region, which are considered transparent). In this example, we will thus need two bitmaps -- one for the perimeter points, and one for the interior points. Let's break the image into these two bitmaps. �
Chapter 10: Bitmapped Images 213
. . . . * . . . . . . . . . . . . . . . . * . * . . . . . . . x . . . . . . * . . . * . . . . . x x x . . . . * . . . . . * . . . x x x x x . . * * * * * * * * * . . . . . . . . .
perimeter points interior points
The next step is to convert these two bitmaps into their binary
representations. Just as there are eight bits in a byte, we will create a data structure (an array in this case) with each byte holding eight pixels. Bits that are set (1) indicate the corresponding pixel will appear displayed in the color associated with that bitmap. Bits that are reset (0) leave the corresponding pixel unchanged. The size of each bitmap array must be at least 10 bytes because each bitmap contains five rows with nine pixels in each row (that is, two bytes are required for each row of the image). Hence, when we convert these bitmaps to their binary representations, and subsequently to their hexadecimal equivalent, the results will appear as shown here. The boldface bits represent the actual image; the other bits are filler bits needed to complete each row of the bitmaps after the ninth pixel. All filler bits must be zero.
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 08 00
0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 14 00
0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 22 00
0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 41 00
1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 FF 80
perimeter bitmap
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 00
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 08 00
0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 1C 00
0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 3E 00
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 00
interior bitmap
The next matter is the order in which the bitmaps are stored in the
corresponding data structures. Since our data structure is an array, it is only necessary to show the relationship of the subscripts to the bitmap structures above. The next diagram shows the subscript order for the case of a two-column by five-row bitmap.
[8] [9] �
214 Fastgraph User's Guide
[6] [7]
[4] [5]
[2] [3]
[0] [1]
From this diagram, we see the first element of the array (that is, the
element with subscript [0]) represents the lower left corner of the image. The subscript progression then continues right until reaching the end of the first row. It then resumes at the leftmost element of the second row and continues to the right until the end of that row. It continues in this manner for all remaining rows.
We are now ready to present an example program to display our triangle.
The program will use the Fastgraph routine fg_drawmap, which expects three arguments. The first argument is the bitmap array (passed by reference), the second is the width of the bitmap in bytes, and the last is the height of the bitmap in pixel rows. The fg_drawmap routine displays the image such that its lower left corner is at the graphics cursor position on the active video page. The routine has no effect in text video modes. Additionally, fg_drawmap displays the image using the current color index, which means we will need to call fg_drawmap once for each color in the image.
Example 10-1 runs in any 320x200 color graphics mode (it could be made to
run in mode 12 too, but that would detract from the purpose of the example). After establishing the video mode, the program uses fg_rect to fill the entire screen with a gray rectangle (white in CGA). Next, the program establishes (156,101) as the graphics cursor position; this causes the triangle to be centered on the screen. The two calls to fg_drawmap, one for each color in the image, actually display the triangle. Note especially how fg_setcolor is used before each call to fg_drawmap to define the current color index. The result is a triangle with a blue perimeter (cyan in CGA) and green interior (magenta in CGA).
Example 10-1.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char perimeter[] = { 0xFF,0x80,0x41,0x00,0x22,0x00,0x14,0x00,0x08,0x00 }; char interior[] = { 0x00,0x00,0x3E,0x00,0x1C,0x00,0x08,0x00,0x00,0x00 };
void main() { int old_mode, new_mode; � Chapter 10: Bitmapped Images 215
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(7); fg_rect(0,319,0,199);
fg_move(156,101); fg_setcolor(1); fg_drawmap(perimeter,2,5); fg_setcolor(2); fg_drawmap(interior,2,5); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
We should mention that fg_drawmap does not perform clipping when
displaying an image. If you want the image to be constrained by the current clipping limits, use fg_clipmap instead of fg_drawmap. The fg_clipmap routine takes the same three arguments as fg_drawmap, but it is not as fast as fg_drawmap because of the additional overhead required when performing the image clipping.
The different color bitmaps used by fg_drawmap do not all have to be the
same size. In our triangle example, the perimeter is 9 pixels wide by 5 pixels high, but the interior is only 5 pixels wide by 3 pixels high. Hence, the bitmap for the interior pixels only requires one byte for each of its three rows, so we can store it in a three-byte array. Its structure would be:
[2] 08
[1] 1C
[0] 3E
Example 10-2 is similar to example 10-1, but it uses a three-byte array
for the interior bitmap. Note the second call to fg_move in this example. It is needed because the bottom row of the smaller interior bitmap corresponds to the second row of the larger perimeter bitmap. In other words, the interior bitmap must be displayed one row above the perimeter bitmap.
Example 10-2.
#include <fastgraf.h> �
216 Fastgraph User's Guide
#include <stdio.h> #include <stdlib.h> void main(void);
char perimeter[] = { 0xFF,0x80,0x41,0x00,0x22,0x00,0x14,0x00,0x08,0x00 }; char interior[] = { 0x3E,0x1C,0x08 };
void main() { int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(7); fg_rect(0,319,0,199);
fg_move(156,101); fg_setcolor(1); fg_drawmap(perimeter,2,5); fg_move(156,100); fg_setcolor(2); fg_drawmap(interior,1,3); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
In example 10-2, the time required to execute the second call to fg_move
may not be worth the saving of 7 bytes. When array space is critical, or when the images are larger, the use of smaller bitmaps for certain colors may be more valuable.
Yet another possibility for example 10-2 would be to shift the elements
of the interior bitmap two pixels to the left. In this way, the bitmap would be aligned against the left side of the array, as the perimeter bitmap is. The three values comprising the interior bitmap would then become F8, 70, and 20. We also would need to change the x coordinate in the second call to fg_move from 156 to 158. �
Chapter 10: Bitmapped Images 217
Mode-Specific Bitmapped Images
This section will discuss the image display routines that use bitmapped
image formats specific to each text and graphics video mode. The different image formats closely resemble the structure of video memory in each mode, so these routines are much faster than displaying mode-independent bitmaps with fg_drawmap. If you use the mode-specific bitmaps in a program that supports several video modes, there will be some additional programming that is not needed when using mode-independent bitmaps. Usually, however, your efforts will be rewarded with significantly faster graphics.
We'll demonstrate the use of mode-specific bitmaps in graphics modes with
the familiar two-color triangle whose pixel representation appears below.
. . . . * . . . . . . . * x * . . . . . * x x x * . . . * x x x x x * . * * * * * * * * *
As before, our triangle is nine pixels wide at its base and five pixels
high. The pixels indicated by an asterisk (*) are the triangle's perimeter, while those indicated by an x represent its interior points. We need to distinguish between these pixels because they will be different colors. The pixels shown as periods (.) are not part of the triangle itself. They are required to make the image rectangular, so from Fastgraph's perspective they are indeed part of the image.
Regular Images
The Fastgraph routine fg_drwimage displays regular mode-specific
bitmapped images (by regular, we mean an image that is neither clipped nor rotated). Its arguments and the bitmap array's subscript order are the same as for fg_drawmap. The major difference is the bitmap structure -- we combine the information for all colors into a single bitmap, in a way consistent with the structure of video memory for the various modes. As with the other image display routines, fg_drwimage displays the image on the active video page or virtual buffer with its lower left corner at the graphics cursor position (or the text cursor position for text modes). We'll now examine the use of fg_drwimage in several video modes.
CGA four-color graphics modes
In the four-color CGA graphics modes (modes 4 and 5), each pixel can
assume a value between 0 and 3. This means it takes two bits to represent a pixel, or put another way, each byte of video memory holds four pixels. Our triangle image is nine pixels wide, so three bytes are needed for each row of the image. Because the image is five pixels high, we need a bitmap array of at least 15 bytes (five rows times three bytes per row) to hold the image.
The image's binary representation and its hexadecimal equivalent for the
four-color CGA graphics modes are shown here. The binary values in boldface represent the actual image; the others are the filler bits needed to complete each row of the bitmap after the ninth pixel. We have coded the perimeter � 218 Fastgraph User's Guide
pixels to be color 1 (01 binary) and the interior pixels to be color 2 (10
binary). Any pixel whose value is zero (00 binary) is transparent and will
thus leave the contents of video memory at that position unchanged.
00 00 00 00 01 00 00 00 00 00 00 00 00 40 00
00 00 00 01 10 01 00 00 00 00 00 00 01 90 00
00 00 01 10 10 10 01 00 00 00 00 00 06 A4 00
00 01 10 10 10 10 10 01 00 00 00 00 1A A9 00
01 01 01 01 01 01 01 01 01 00 00 00 55 55 40
Example 10-3 uses this mode-specific bitmap to display the triangle in
the standard CGA four-color graphics mode (mode 4). After establishing the video mode, the program uses fg_rect to fill the entire screen with a white rectangle. Next, the program establishes (156,101) as the graphics cursor position; this causes the triangle to be centered on the screen. The call to fg_drwimage produces a triangle with a cyan perimeter (color 1) and a magenta interior (color 2).
Example 10-3.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char triangle[] = { 0x55,0x55,0x40, 0x1A,0xA9,0x00, 0x06,0xA4,0x00, 0x01,0x90,0x00, 0x00,0x40,0x00 };
void main() { int old_mode;
fg_initpm(); if (fg_testmode(4,1) == 0) { printf("This program requires a 320 "); printf("x 200 CGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(4);
fg_setcolor(7); fg_rect(0,319,0,199);
fg_move(156,101); fg_drwimage(triangle,3,5); fg_waitkey(); � Chapter 10: Bitmapped Images 219
fg_setmode(old_mode); fg_reset(); }
CGA two-color graphics mode
In the two-color CGA graphics mode (mode 6), each pixel can assume the
values 0 or 1. This means it takes just one bit to represent a pixel, so each byte of video memory holds eight pixels. Our triangle image is nine pixels wide, so two bytes are needed for each row of the image. Because the image is five pixels high, we need a bitmap array of at least 10 bytes (five rows times two bytes per row) to hold the image.
The image's binary representation and its hexadecimal equivalent for the
two-color CGA graphics mode are shown here. The binary values in boldface represent the actual image; the others are the filler bits needed to complete each row of the bitmap after the ninth pixel. We have coded both the perimeter pixels and the interior pixels to be color 1. Any pixel whose value is zero is transparent and will thus leave the contents of video memory at that position unchanged.
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 08 00
0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 1C 00
0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 3E 00
0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 7F 00
1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 FF 80
Example 10-4 uses this mode-specific bitmap to display the triangle in
the CGA two-color graphics mode (mode 6). After establishing the video mode, the program establishes (316,101) as the graphics cursor position; this causes the triangle to be centered on the screen. The call to fg_drwimage produces a solid triangle.
Example 10-4.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char triangle[] = { 0xFF,0x80, 0x7F,0x00, 0x3E,0x00, 0x1C,0x00, 0x08,0x00 };
void main() { int old_mode; �
220 Fastgraph User's Guide
fg_initpm(); if (fg_testmode(6,1) == 0) { printf("This program requires a "); printf("CGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(6);
fg_move(316,101); fg_drwimage(triangle,2,5); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Tandy/PCjr 16-color graphics mode
The structure of mode-specific bitmaps for the Tandy/PCjr 16-color
graphics mode (mode 9) is the same as the mode-specific bitmap structure for the EGA/VGA/SVGA 16-color graphics modes discussed later in this section.
Hercules graphics modes
The structure of mode-specific bitmaps for the Hercules graphics modes
(modes 11 and 12) is the same as two of the CGA graphics modes. For the standard Hercules graphics mode (mode 11), please refer to the discussion of CGA two-color (mode 6) bitmaps. For the low-resolution Hercules graphics mode (mode 12), please refer to the discussion of the CGA four-color (mode 4) bitmaps.
EGA/VGA/SVGA 16-color graphics modes
In the native EGA and VGA graphics modes (modes 13 through 18) and the
16-color SVGA graphics modes (modes 28 and 29), each pixel can assume a value between 0 and 15. This means it takes four bits to represent a pixel, so each byte of the bitmap holds two pixels. Our triangle image is nine pixels wide, so five bytes are needed for each row of the image. Because the image is five pixels high, we need a bitmap array of at least 25 bytes (five rows times five bytes per row) to hold the image.
In these modes, it is easy to develop the hexadecimal representation of a
bitmap without first producing its binary equivalent. This is because a pixel value and a hexadecimal digit each occupy four bits. The triangle's hexadecimal representation for these video modes is shown here. The pixels in boldface represent the actual image; the others are the filler values needed to complete each row of the bitmap after the ninth pixel. We have chosen to display the perimeter pixels in color 1 and the interior pixels in color 2. Any pixel whose value is zero is transparent and will thus leave the contents of video memory at that position unchanged. �
Chapter 10: Bitmapped Images 221
00 00 10 00 00
00 01 21 00 00
00 12 22 10 00
01 22 22 21 00
11 11 11 11 10
Example 10-5 is similar to example 10-3, but it uses the 320x200 EGA
graphics mode (mode 13) and the mode-specific bitmap just constructed to display the triangle. The call to fg_drwimage produces a triangle with a blue perimeter (color 1) and a green interior (color 2).
Example 10-5.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char triangle[] = { 0x11,0x11,0x11,0x11,0x10, 0x01,0x22,0x22,0x21,0x00, 0x00,0x12,0x22,0x10,0x00, 0x00,0x01,0x21,0x00,0x00, 0x00,0x00,0x10,0x00,0x00 };
void main() { int old_mode;
fg_initpm(); if (fg_testmode(13,1) == 0) { printf("This program requires a 320 "); printf("x 200 EGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(13);
fg_setcolor(7); fg_rect(0,319,0,199);
fg_move(156,101); fg_drwimage(triangle,5,5); fg_waitkey();
fg_setmode(old_mode); fg_reset(); } �
222 Fastgraph User's Guide
256-color graphics modes
In 256-color graphics modes (modes 19 through 27), each pixel can assume
a value between 0 and 255 (FF hex). This means it takes eight bits to represent a pixel, or each byte of video memory holds one pixel. Our triangle image is nine pixels wide, so nine bytes are needed for each row of the image. Because the image is five pixels high, we need a bitmap array of at least 45 bytes (five rows times nine bytes per row) to hold the image. Note we will never need any filler bits in the 256-color video modes.
It is especially simple to develop the bitmap for an image in the 256-
color modes because each byte holds exactly one pixel. The triangle's hexadecimal representation for the 256-color graphics modes is shown here. As before, we have coded the perimeter pixels to be color 1 (01 hex) and the interior pixels to be color 2 (02 hex). Any pixel whose value is zero is transparent and will thus leave the contents of video memory at that position unchanged.
00 00 00 00 01 00 00 00 00
00 00 00 01 02 01 00 00 00
00 00 01 02 02 02 01 00 00
00 01 02 02 02 02 02 01 00
01 01 01 01 01 01 01 01 01
Example 10-6 is also similar to example 10-3, but it uses the MCGA 256-
color graphics mode (mode 19) and the mode-specific bitmap just constructed to display the triangle. The call to fg_drwimage produces a triangle with a blue perimeter (color 1) and a green interior (color 2).
Example 10-6.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char triangle[] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x00,0x01,0x02,0x02,0x02,0x02,0x02,0x01,0x00, 0x00,0x00,0x01,0x02,0x02,0x02,0x01,0x00,0x00, 0x00,0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
void main() { int old_mode;
fg_initpm(); � Chapter 10: Bitmapped Images 223
if (fg_testmode(19,1) == 0) { printf("This program requires a 320 "); printf("x 200 MCGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(19);
fg_setcolor(7); fg_rect(0,319,0,199);
fg_move(156,101); fg_drwimage(triangle,9,5); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Sometimes you may need to include black pixels that are not transparent
in a mode-specific bitmapped image. The easiest way to do this is to use fg_putimage, which we'll describe shortly. Another possibility is using fg_palette or fg_setrgb to make an unused color index black and then use that color index for non-transparent black pixels. For example, calling fg_palette(8,0) in a 16-color graphics mode would display color 8 pixels as black. Similarly, fg_setrgb(248,0,0,0) in a 256-color graphics mode would display color 248 pixels as black. The choice of colors 8 and 248 in these examples is arbitrary; any unused color will do. Yet another possibility is to use the masking maps discussed later in this chapter.
Virtual Buffers
The structure of mode-specific bitmaps for virtual buffers is the
same as the mode-specific bitmap structure for 256-color graphics modes discussed in the previous section.
Text Modes
You also can use the fg_drwimage routine to display images in text video
modes (modes 0, 1, 2, 3, and 7). As one might expect, the image structure in the text modes is rather different from the graphics modes. In Chapter 5 we saw that each character cell on the screen actually consists of a character and an attribute. The character value determines what character is displayed, while the attribute value controls the character's appearance. The structure of the attribute is:
bits attribute
0-3 foreground color 4-6 background color 7 blinking
The text mode image structure used with fg_drwimage also consists of a
series of characters and attributes. For example, the following diagram � 224 Fastgraph User's Guide
illustrates the structure of an image that is three characters wide and two
characters high.
char attr char attr char attr
char attr char attr char attr
To illustrate the use of fg_drwimage in a text video mode, we'll display
the phrase "hello there" on two different lines in the center of the screen. Furthermore, let's assume we would like the first character of each word to appear in foreground color 1, the second in color 2, and so forth. Our image will consist of two lines each containing five characters, and each character requires two bytes of storage (one for the character and another for its attribute), so we'll need a 20-byte array for holding the image. The array really doesn't hold a bitmap as in the graphics modes, so in the text modes the first argument passed to fg_drwimage is instead called the image array. In our example, the structure of the image array is:
'h' 1 'e' 2 'l' 3 'l' 4 'o' 5
't' 1 'h' 2 'e' 3 'r' 4 'e' 5
The subscript order that fg_drwimage uses for text modes is the same as for
the graphics modes. For our five-row by two-column image, this means the array
subscripts would be numbered as follows:
[10] [11] [12] [13] [14] [15] [16] [17] [18] [19]
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
Depending on the character and attribute values in the image array,
fg_drwimage can display new characters and attributes, new characters leaving the existing attribute unchanged, new attributes leaving the existing character unchanged, or leave both the existing character and attribute unchanged in video memory. To keep an existing character or attribute, simply specify a value of 0 in the corresponding element of the image array. This capability is analogous to the fact that zero-valued pixels in graphics mode bitmaps leave video memory unchanged.
Example 10-7 demonstrates the use of fg_drwimage in the 80-column color
text mode (mode 3). After establishing the video mode and making the cursor invisible, the program calls fg_drwimage to display the "hello there" image just discussed (note we pass the dimensions of the image array as the number of bytes, not the number of characters). The program waits for a keystroke and then calls fg_drwimage again, passing a different image array (called "image") of the same size. This array changes the first letter of both words from lower case to upper case (leaving the attribute unchanged), and it makes the remaining characters have the same attribute as the first character. This is done in part by using zero-valued characters and attributes to leave video memory unchanged. After waiting for another keystroke, the program exits. �
Chapter 10: Bitmapped Images 225
Example 10-7.
#include <fastgraf.h> void main(void);
char hello[] = { 't',1, 'h',2, 'e',3, 'r',4, 'e',5, 'h',1, 'e',2, 'l',3, 'l',4, 'o',5 };
char image[] = { 'T',0, 0,1, 0,1, 0,1, 0,1, 'H',0, 0,1, 0,1, 0,1, 0,1 };
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(3); fg_cursor(0);
fg_locate(12,37); fg_drwimage(hello,10,2); fg_waitkey();
fg_drwimage(image,10,2); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Clipped Images
The fg_drwimage routine does not perform clipping when displaying an
image. If you want the image to be constrained by the clipping limits (as established by the most recent call to fg_setclip), use fg_clpimage instead of fg_drwimage. The fg_clpimage routine takes the same three arguments as fg_drwimage and also displays the image such that its lower left corner is at the graphics cursor position. Unlike fg_drwimage, the fg_clpimage routine has no effect when used in a text video mode. Because of the additional overhead involved in checking the clipping limits, fg_clpimage is not as fast as fg_drwimage.
Reversed Images
The fg_revimage routine displays an image reversed (that is, mirrored
about the y-axis) without clipping. It takes the same three arguments as fg_drwimage and also displays the image such that its lower left corner is at � 226 Fastgraph User's Guide
the graphics cursor position. The fg_revimage routine has no effect when used
in a text video mode.
Reversed Clipped Images
The fg_flpimage routine combines the effects of the fg_revimage and
fg_clpimage routines -- it displays a reversed image constrained by the current clipping limits. It takes the same three arguments as fg_drwimage and also displays the image such that its lower left corner is at the graphics cursor position. Like the fg_clpimage routine, fg_flpimage has no effect when used in a text video mode.
Images Without Transparent Pixels
The fg_putimage routine is the same as fg_drwimage except it does not
consider color 0 pixels to be transparent. Because it does not need to check for transparent pixels, fg_putimage is faster than fg_drwimage. Using fg_putimage is recommended for cases where transparency is not an issue.
Some Examples
Example 10-8 illustrates the use of fg_drwimage, fg_clpimage,
fg_revimage, fg_flpimage, and fg_putimage in the standard CGA four-color graphics mode (mode 4). The program uses each of these routines to display a small white arrow, as shown in this pixel map:
. . . . . . * . . . . . . . . . * * . . * * * * * * * * * . * * * * * * * * * * * * * * * * * * * . . . . . . . * * . . . . . . . . * . . .
As before, we must first convert this image to a bitmap. The image is ten pixels wide and seven high. In mode 4, each pixel occupies two bits, so we need a 21-byte array (7 rows by 3 columns) to store the image. Since we want to make the arrow white, each pixel will be displayed in color 3 (11 binary). Here is the bitmap and its hexadecimal equivalent for the arrow image in mode 4 (the actual image is in boldface).
00 00 00 00 00 00 11 00 00 00 00 00 00 0C 00
00 00 00 00 00 00 11 11 00 00 00 00 00 0F 00
11 11 11 11 11 11 11 11 11 00 00 00 FF FF C0
11 11 11 11 11 11 11 11 11 11 00 00 FF FF F0
11 11 11 11 11 11 11 11 11 00 00 00 FF FF C0
00 00 00 00 00 00 11 11 00 00 00 00 00 0F 00 � Chapter 10: Bitmapped Images 227
00 00 00 00 00 00 11 00 00 00 00 00 00 0C 00
After establishing the video mode, the program fills the screen with
color 1 pixels and defines a clipping region. It then uses fg_drwimage to display the arrow pointing to the right and fg_clpimage to do the same thing, but with respect to the clipping limits. Because the left edge of the arrow is displayed at x=10 and the right clipping limit is at x=15, the call to fg_clpimage only draws the first six columns of the arrow (that is, it does not draw the arrow head).
Next, example 10-8 uses fg_revimage to display the arrow pointing to the
left. To allow for the filler pixels, we must establish the graphics cursor position two pixels to the left of the position used by fg_drwimage if we want the tip of the left-pointing arrow to align with the tail of the right- pointing arrow. The program then uses fg_flpimage to display an arrow pointing to the left with regard to the clipping limits. The call to fg_flpimage displays the arrow head and the first two columns of the arrow shaft. Finally, the program uses fg_putimage to display the unclipped right-pointing arrow without transparent pixels (this produces a black border around the arrow).
Example 10-8.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char arrow[] = { 0x00,0x0C,0x00, 0x00,0x0F,0x00, 0xFF,0xFF,0xC0, 0xFF,0xFF,0xF0, 0xFF,0xFF,0xC0, 0x00,0x0F,0x00, 0x00,0x0C,0x00 };
void main() { int old_mode;
fg_initpm(); if (fg_testmode(4,1) == 0) { printf("This program requires a 320 "); printf("x 200 CGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(4); fg_setcolor(1); fg_fillpage(); fg_setclip(0,15,0,199);
fg_move(10,10); fg_drwimage(arrow,3,7); fg_move(10,20); fg_clpimage(arrow,3,7); �
228 Fastgraph User's Guide
fg_move(8,30); fg_revimage(arrow,3,7); fg_move(8,40); fg_flpimage(arrow,3,7); fg_move(8,50); fg_putimage(arrow,3,7); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Example 10-9 is the same as example 10-8, but it uses the low resolution
EGA graphics mode (mode 13). If we changed the mode number specified in the calls to fg_testmode and fg_setmode, the program also would run in any 16- color graphics mode. In these modes, we store two pixels per byte in the bitmap array, so we need a 35-byte array (7 rows by 5 columns) to store the image. Here is the bitmap's hexadecimal equivalent for the arrow image in mode 13, followed by the program to display it.
00 00 00 F0 00
00 00 00 FF 00
FF FF FF FF F0
FF FF FF FF FF
FF FF FF FF F0
00 00 00 FF 00
00 00 00 F0 00
Example 10-9.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char arrow[] = { 0x00,0x00,0x00,0xF0,0x00, 0x00,0x00,0x00,0xFF,0x00, 0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF0, 0x00,0x00,0x00,0xFF,0x00, 0x00,0x00,0x00,0xF0,0x00 };
void main() { � Chapter 10: Bitmapped Images 229
int old_mode;
fg_initpm(); if (fg_testmode(13,1) == 0) { printf("This program requires a 320 "); printf("x 200 EGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(13); fg_setcolor(1); fg_fillpage(); fg_setclip(0,15,0,199);
fg_move(10,10); fg_drwimage(arrow,5,7); fg_move(10,20); fg_clpimage(arrow,5,7); fg_move(8,30); fg_revimage(arrow,5,7); fg_move(8,40); fg_flpimage(arrow,5,7); fg_move(8,50); fg_putimage(arrow,5,7); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Retrieving Images
Sometimes it's necessary to retrieve an image from video memory and store
it in one or more arrays as a bitmapped image. Fastgraph includes two routines, fg_getmap and fg_getimage, for this purpose. The fg_getmap routine retrieves pixels of the current color index and stores them in the mode- independent bitmap format used by fg_drawmap. The fg_getimage routine retrieves an image and stores it in the mode-specific bitmap format used by fg_drwimage, fg_clpimage, fg_revimage, fg_flpimage, and fg_putimage. The arguments to fg_getmap and fg_getimage are respectively analogous to those of fg_drawmap and fg_drwimage: the first is an array (passed by reference) to receive the bitmap, the second is the width of the bitmap in bytes, and the last is the height of the bitmap in pixel rows. With either routine, the graphics cursor position on the active video page defines the lower left corner of the image to retrieve.
If we want to use fg_getmap to retrieve an image containing more than one
color, we must call the routine once per color. In this case we'll usually want to pass different bitmap arrays to fg_getmap (or perhaps different offsets into the same array). This might seem unusual at first, but it parallels the behavior of the fg_drawmap routine. That is, to display a multicolor image using fg_drawmap, we must call it once for each color in the image. � 230 Fastgraph User's Guide
Example 10-10 demonstrates a typical use of the fg_getmap routine. The
program displays the word "text" in the upper left corner of the screen using a 320x200 graphics mode. It uses fg_getmap to retrieve the word as an image and then displays it in a new position with the fg_drawmap routine. Let's look at the program now, and afterward we'll more closely examine the screen coordinates and the structure of the bitmap array.
Example 10-10.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { char bitmap[32]; int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(9); fg_text("text",4); fg_waitkey();
fg_move(0,7); fg_getmap(bitmap,4,8); fg_move(4,15); fg_drawmap(bitmap,4,8); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
In all 320x200 graphics video modes, individual characters are 8 pixels
wide and 8 pixels high. This means the lower left corner of the (0,0) character cell is referenced by the screen coordinates (0,7). Hence, these are the coordinates of the first call to fg_move. The image retrieved in example 10-10 is four characters long (32 pixels wide), so we need a bitmap array capable of holding 8 rows of 32 pixels (4 bytes) each. Our bitmap array is therefore a 32-byte array, logically structured to have 4 columns and 8 rows. These values are the width and height arguments passed to fg_getmap and fg_drawmap. �
Chapter 10: Bitmapped Images 231
After it retrieves the image, example 10-10 displays it one line below
and one-half character cell (four pixels) to the right of its original position. In other words, the program displays the image four pixels to the right of the (1,0) character cell. The lower left corner of that cell is referenced by the screen coordinates (0,15), so the image should appear at the position (4,15). These are the coordinates of the second call to fg_move.
Example 10-11 illustrates the use of fg_getmap and fg_drawmap to retrieve
and display a two-color image. This example is similar to example 10-10, but this program first draws a rectangle in the upper left corner of the screen and then displays the word "text" on top of the rectangle in a different color. Each character in a 320x200 graphics video mode is 8 pixels wide and 8 pixels high, so the rectangle must be 32 pixels wide (4 characters times 8 pixels per character) and 8 pixels high. The image to retrieve will be the same size as the rectangle.
The image retrieved in example 10-10 required a 32-byte array, logically
structured to have 4 columns and 8 rows. Example 10-11 will retrieve an image of the same structure, but the image contains two colors instead of just one. This means we need two 32-byte arrays, one for each color, to hold the image. We could instead use a single 64-byte array and pass an offset into that array (specifically, &bitmap[32]) for processing the second color.
Example 10-11.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { char bitmap1[32], bitmap2[32]; int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(7); fg_rect(0,31,0,7); fg_setcolor(9); fg_text("text",4); fg_waitkey();
fg_move(0,7); fg_setcolor(7); fg_getmap(bitmap1,4,8); fg_setcolor(9); �
232 Fastgraph User's Guide
fg_getmap(bitmap2,4,8);
fg_move(4,15); fg_setcolor(7); fg_drawmap(bitmap1,4,8); fg_setcolor(9); fg_drawmap(bitmap2,4,8); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Example 10-12 is similar to example 10-11, but it uses fg_getimage and
fg_drwimage instead of fg_getmap and fg_drawmap to retrieve and display the image. That is, it uses the mode-specific rather than the mode-independent image retrieval and display routines. When using the mode-specific routines, the size of the bitmap needed to hold the image depends on the video mode. For programs that run in only one video mode, bitmap widths are constant, but when a program must run in several video modes, the width is variable. The Fastgraph routine fg_imagesiz computes the number of bytes required to store a mode-specific bitmapped image of specified dimensions. Its two integer arguments specify the image width and height in pixels.
The program computes the image width in bytes by passing a height of 1 to
fg_imagesiz. The size of the bitmap array in example 10-12 is 256 bytes, the size required in 256-color graphics modes (32 bytes times 8 bytes). Other video modes require less storage, so in these modes only a portion of the bitmap array will actually be used. The image width is then used in the calls to both fg_getimage and fg_drwimage.
Example 10-12.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { char bitmap[256]; int old_mode, new_mode; int width;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode); width = (int)fg_imagesiz(32,1); � Chapter 10: Bitmapped Images 233
fg_setcolor(7); fg_rect(0,31,0,7); fg_setcolor(9); fg_text("text",4); fg_waitkey();
fg_move(0,7); fg_getimage(bitmap,width,8); fg_move(4,15); fg_drwimage(bitmap,width,8); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
While this example used an array to store the image, it's usually preferable
to allocate dynamic memory for this purpose. We could have done this in
example 10-12 by calling fg_imagesiz with arguments of 32 (width) and 8
(height). The routine's return value would then tell us the number of bytes we
would need to allocate.
We can also use fg_getimage to retrieve images in text video modes. In
text modes, however, there are a few differences we must consider when using fg_getimage. First, the text cursor position, not the graphics cursor position, specifies the lower left corner of the image. Hence, we must use fg_locate instead of fg_move to define the image location. Second, the image width is always twice the number of characters per image row (that is, for each character we have a character byte and an attribute byte). The fg_getmap routine has no effect when used in a text video mode.
Example 10-13 shows a simple use of fg_getimage in text modes. This
program is similar to example 10-12, but it runs in an 80-column text mode rather than a 320x200 graphics mode. As before, the program will retrieve the four characters "text" as an image from the upper left corner of the screen and then display it in a different location. Because the image consists of four characters in one row, the image width is 8 bytes and the image height is 1.
Example 10-13.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode; char image[8];
fg_initpm(); old_mode = fg_getmode(); �
234 Fastgraph User's Guide
if (fg_testmode(3,1)) fg_setmode(3); else if (fg_testmode(7,1)) fg_setmode(7); else { printf("This program requires\n"); printf("an 80-column display.\n"); exit(1); } fg_cursor(0);
fg_setattr(9,7,0); fg_text("text",4); fg_waitkey();
fg_locate(0,0); fg_getimage(image,8,1); fg_locate(1,1); fg_drwimage(image,8,1); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Finally, here's a tip that's worth remembering. In the native EGA and VGA
graphics modes (13 to 18) and the 16-color SVGA graphics modes (28 and 29), the routines for displaying and retrieving mode-specific bitmaps can be anywhere from 10% to 20% faster if the current graphics x position is an even number. This is because these routines must perform additional bitmap alignment when displaying or retrieving images starting at odd-numbered pixels.
Inverting Bitmaps
Fastgraph's mode-independent and mode-specific bitmapped image display
routines expect images to be stored starting with the bottom row and proceeding toward the top. This convention is often contrary to the "top to bottom" row order used in other graphics libraries. The fg_invert routine reverses the row order of bitmapped images, so a "top to bottom" image becomes a "bottom to top" image, or vice versa. This will often make it easier to import such images from other sources for use with Fastgraph's bitmapped image display routines. Note that fg_invert does not change the orientation for Fastgraph's bitmapped image display routines; it merely reverses the row order of the image itself.
The fg_invert routine requires three arguments. The first is the address
of the array containing the mode-independent or mode-specific bitmapped image data. The resulting inverted image is stored in this same array. The second and third arguments respectively specify the bitmap width and height in bytes.
Example 10-14 is a modified version of example 10-6 that defines the
triangle's bitmap data starting with the top row and proceeding toward the bottom. To display this image with Fastgraph's fg_drwimage routine, we must �
Chapter 10: Bitmapped Images 235
translate the bitmapped image to the "bottom to top" format. The program
performs this translation with fg_invert immediately after setting the video
mode (though it could be done anytime before calling fg_drwimage). Other than
the additional fg_invert call and the order of the bitmap data, example 10-14
is the same as example 10-6.
Example 10-14.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char triangle[] = { 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x00, 0x00,0x00,0x01,0x02,0x02,0x02,0x01,0x00,0x00, 0x00,0x01,0x02,0x02,0x02,0x02,0x02,0x01,0x00, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 };
void main() { int old_mode;
fg_initpm(); if (fg_testmode(19,1) == 0) { printf("This program requires a 320 "); printf("x 200 MCGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(19); fg_invert(triangle,9,5);
fg_setcolor(7); fg_rect(0,319,0,199);
fg_move(156,101); fg_drwimage(triangle,9,5); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Note that fg_invert also can be used to create inverted versions of any
mode-independent or mode-specific bitmapped image. This means you can create versions of bitmaps mirrored about the x-axis, somewhat analogous to the way fg_revimage displays images mirrored about the y-axis. � 236 Fastgraph User's Guide
Converting Mode-Specific Bitmaps
Earlier in this chapter we presented a bitmapped image format that was
independent of the video mode (such images are displayed with fg_drawmap or fg_clipmap). While this format works well for images with one or two colors, the performance can degrade significantly if the image contains many colors. In this section we'll show how Fastgraph's "one pixel per byte" mode-specific bitmap format used with 256-color graphics modes and virtual buffers can provide an alternate way to use the same image data in multiple video modes.
The basis of this scheme is to store all bitmaps in the "one pixel per
byte" format. When using 256-color graphics modes or virtual buffers, we simply use the "one pixel per byte" bitmaps with the fg_drwimage family of routines because the bitmaps are already in the expected format. However, when using graphics modes with fewer colors, we must translate the bitmaps to a suitable format for those modes. Fastgraph's fg_pack routine provides an easy way to do this: it converts bitmapped images in the "one pixel per byte" format to the mode-specific bitmap format for the current video mode. The converted bitmaps can then be displayed with the fg_drwimage family.
The fg_pack routine's first two arguments are the addresses of the source
and destination bitmap arrays. The source array contains the "one pixel per byte" bitmapped image, and the destination array will receive the converted mode-specific image (it's important to make sure the destination array is large enough to hold the converted image). The last two fg_pack arguments specify the width and height in pixels of the source bitmap. In 256-color graphics modes, or when a virtual buffer is active, fg_pack merely copies the source array contents to the destination array.
Example 10-15 shows how you can use the same bitmap data in 256-color and
16-color graphics modes. We define our familiar triangle bitmap in the 256- color mode-specific format, as in example 10-6. The program first displays the triangle bitmap in the standard VGA/MCGA 320x200 256-color graphics mode (mode 19) against a gray background. After a keystroke, the program switches to the EGA/VGA 320x200 16-color graphics mode (mode 13). In this mode, fg_drwimage expects two pixels per bitmap byte, so we must call fg_pack to convert the bitmap data to this format. We store the resulting bitmap in the triangle16 array and again use fg_drwimage to display the triangle bitmap.
Example 10-15.
#include <fastgraf.h> void main(void);
char triangle[] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x00,0x01,0x02,0x02,0x02,0x02,0x02,0x01,0x00, 0x00,0x00,0x01,0x02,0x02,0x02,0x01,0x00,0x00, 0x00,0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 }; char triangle16[25];
void main() { � Chapter 10: Bitmapped Images 237
int old_mode;
fg_initpm(); old_mode = fg_getmode();
fg_setmode(19); fg_setcolor(7); fg_fillpage(); fg_move(156,101); fg_drwimage(triangle,9,5); fg_waitkey();
fg_setmode(13); fg_setcolor(7); fg_fillpage(); fg_pack(triangle,triangle16,9,5); fg_move(156,101); fg_drwimage(triangle16,5,5); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Note that the 256-color bitmap is nine bytes wide and five bytes tall. When we
convert the image to the 16-color mode-specific format, the bitmap width is
reduced to five bytes because two pixels are packed into each byte. The second
pixel in the last byte of each row becomes a transparent filler pixel (that
is, its value is zero).
As you might guess, Fastgraph's fg_unpack routine performs the opposite
function of fg_pack. That is, it converts a bitmap from the mode-specific format of the current video mode to the "one pixel per byte" format. The fg_unpack routine is intended as a helper function for displaying mode- specific images in virtual buffers when using video modes with fewer than 256 colors. When a virtual buffer is active, fg_drwimage always expects the bitmap to be in the "one pixel per byte" format, regardless of the current video mode. The fg_unpack routine makes it easy to convert images to this format before displaying them in a virtual buffer.
The fg_unpack routine's first two arguments are the addresses of the
source and destination bitmap arrays. The source array contains the mode- specific bitmapped image, and the destination array will receive the converted "one pixel per byte" image. The last fg_unpack argument specifies the size of the source array in bytes. Like fg_pack, fg_unpack merely copies the source array contents to the destination array in 256-color graphics modes or when a virtual buffer is active.
Example 10-16 illustrates how to use fg_unpack to convert mode-specific
bitmaps to the virtual buffer format. The program uses the 10-pixel by 7-pixel arrow bitmap of example 10-9 and runs in the EGA/VGA 320x200 16-color graphics mode (mode 13). In this mode, two pixels are packed into each bitmap byte, so the size of the bitmap array is 5x7, or 35 bytes. The call to fg_unpack converts the mode-specific image in the 35-byte arrow array into a "one pixel per byte" format image, storing the result in the 70-byte arrow256 array. � 238 Fastgraph User's Guide
We'll create a 70-byte virtual buffer -- just large enough to hold the 10x7
arrow bitmap -- and display the arrow256 bitmap in it against a light blue
(color 9) background. Finally, we'll use fg_vbpaste to display the virtual
buffer contents in the middle of the screen.
Example 10-16.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char arrow[] = { 0x00,0x00,0x00,0xF0,0x00, 0x00,0x00,0x00,0xFF,0x00, 0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF0, 0x00,0x00,0x00,0xFF,0x00, 0x00,0x00,0x00,0xF0,0x00 }; char arrow256[70];
#ifdef FG32 char buffer[70]; #else char far buffer[70]; #endif
void main() { int handle; int old_mode;
fg_initpm(); if (fg_testmode(13,1) == 0) { printf("This program requires a 320 "); printf("x 200 EGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(13); fg_unpack(arrow,arrow256,35);
fg_vbinit(); handle = fg_vbdefine(buffer,10,7); fg_vbopen(handle); fg_setcolor(9); fg_fillpage(); fg_move(0,6); fg_drwimage(arrow256,10,7);
fg_vbpaste(0,9,0,6,156,101); fg_waitkey(); � Chapter 10: Bitmapped Images 239
fg_vbclose(); fg_setmode(old_mode); fg_reset(); }
Bitmap Scaling and Shearing
Fastgraph's fg_scale routine performs horizontal and vertical scaling of
bitmapped images. It expects a source bitmap stored in the "one pixel per byte" format of Fastgraph's 256-color modes, and it returns an expanded or reduced bitmap in the same format. To scale images in graphics modes with fewer than 256 colors, you must first use fg_unpack to convert the bitmap to the format expected by fg_scale, perform the scaling, and finally use fg_pack to convert the scaled image back to the mode-specific format. Because Fastgraph's virtual buffers also use the one pixel per byte format, you can also use fg_scale to scale images stored in virtual buffers.
The fg_scale routine has six arguments. The first two specify the
addresses of the source and destination bitmap arrays. The source array contains the original (unscaled) bitmapped image; the destination array will receive the expanded or reduced (scaled) bitmap. Both bitmaps are stored in the "one pixel per byte" format. The third and fourth arguments specify the width and height in pixels of the unscaled image, while the fifth and sixth arguments do the same for the resulting scaled image.
Example 10-17 shows how to expand and reduce bitmapped images with
fg_scale. The program displays a 64x40 light blue rectangle with a white border and the word SCALE centered inside it, in the upper left corner of the screen. It retrieves the rectangle contents as a mode-specific bitmap using fg_getimage. The first fg_scale call increases the size of this bitmap by 10 pixels in both directions, meaning the 64x40 image becomes a 74x50 image. The program then displays the expanded bitmap in the lower left corner of the screen using fg_putimage. The second fg_scale call reduces the original bitmap by a factor of two to create a 32x20 bitmap. The reduced bitmap is then displayed in the lower right corner, again using fg_putimage. Note that example 10-17 runs in mode 19, which is a 256-color graphics mode, so fg_getimage automatically stores the original bitmap in the "one pixel per byte" format expected by fg_scale.
Example 10-17.
#include <fastgraf.h> void main(void);
char source[64*40], dest[74*50];
void main() { /* initialize the video environment */
fg_initpm(); fg_setmode(19);
/* draw a blue rectangle with a thick white border */ �
240 Fastgraph User's Guide
fg_setcolor(9); fg_rect(0,63,0,39); fg_setcolor(15); fg_boxdepth(5,5); fg_box(0,63,0,39); fg_move(32,20); fg_justify(0,0); fg_print("SCALE",5);
/* retrieve the rectangle as a mode-specific bitmap */
fg_move(0,39); fg_getimage(source,64,40); fg_waitkey();
/* expand the bitmap by 10 pixels in each direction and */ /* then display it in the lower left corner of the screen */
fg_move(0,199); fg_scale(source,dest,64,40,74,50); fg_putimage(dest,74,50); fg_waitkey();
/* reduce the original bitmap by 50% in each direction and */ /* then display it in the lower right corner of the screen */
fg_move(288,199); fg_scale(source,dest,64,40,32,20); fg_putimage(dest,32,20); fg_waitkey();
/* restore 80x25 text mode and exit */
fg_setmode(3); fg_reset(); }
Shearing can be thought of as anchoring one corner of a rectangular
region and stretching the opposite corner horizontally or vertically. For example, bitmaps containing text or other characters could be sheared horizontally to the right for an italic effect. A sheared image will always be larger than the original image, and it will contain empty triangular areas at its corners. The empty areas will be filled with color 0 pixels, meaning they will be transparent when you display a sheared image with the fg_drwimage family of routines. Like fg_scale, fg_shear expects bitmaps in the "one pixel per byte" format and can likewise be used with images stored in virtual buffers.
The fg_shear routine has six arguments. The first two specify the
addresses of the source and destination bitmap arrays. The source array contains the original bitmapped image; the destination array will receive the sheared bitmap. Both bitmaps are stored in the "one pixel per byte" format. The third and fourth arguments specify the width and height in pixels of the original image. For horizontal shears, the fifth argument specifies the �
Chapter 10: Bitmapped Images 241
resulting width in pixels of the sheared bitmap. For vertical shears, it
specifies the resulting height.
The final fg_shear argument defines the shear type. Four distinct shear
types are available:
* horizontal left shear (region's bottom edge is stretched to the right) * horizontal right shear (region's top edge is stretched to the right) * vertical left shear (region's left edge is stretched up) * vertical right shear (region's right edge is stretched up)
The type is selected by a value between 0 and 3, respectively corresponding to the above four shear types. For example, shear type 2 represents a vertical left shear.
Example 10-18 displays a 64x40 light blue rectangle with a white border
and the word SHEAR centered inside it, in the upper left corner of the screen. It retrieves the rectangle contents as a mode-specific bitmap using fg_getimage. The program then calls fg_shear to perform a 16-pixel horizontal right shear, which stretches the image's top edge 16 pixels to the right. This produces an 80x40 bitmap, which is then displayed in the lower left corner of the screen with fg_putimage. Because this example runs in mode 19, which is a 256-color graphics mode, fg_getimage automatically stores the original bitmap in the "one pixel per byte" format expected by fg_shear.
Example 10-18.
#include <fastgraf.h> void main(void);
char source[64*40], dest[80*40];
void main() { /* initialize the video environment */
fg_initpm(); fg_setmode(19);
/* draw a blue rectangle with a thick white border */
fg_setcolor(9); fg_rect(0,63,0,39); fg_setcolor(15); fg_boxdepth(5,5); fg_box(0,63,0,39); fg_move(32,20); fg_justify(0,0); fg_print("SHEAR",5);
/* retrieve the rectangle as a mode-specific bitmap */
fg_move(0,39); fg_getimage(source,64,40); fg_waitkey(); �
242 Fastgraph User's Guide
/* shear the bitmap horizontally and to the right 16 pixels */ /* then display it in the lower left corner of the screen */
fg_move(0,199); fg_shear(source,dest,64,40,80,1); fg_putimage(dest,80,40); fg_waitkey();
/* restore 80x25 text mode and exit */
fg_setmode(3); fg_reset(); }
It's possible to use fg_shear for rudimentary bitmap rotation. Shearing
an image horizontally left and then vertically right by the same amount will rotate an image counterclockwise. Similarly, shearing horizontally right and then vertically left will rotate it clockwise.
Virtual buffers use the same "one pixel per byte" format expected by
fg_scale and fg_shear. This means you can pass virtual buffer addresses to these functions and apply scaling and shearing operations on virtual buffers. Note, however that 16-bit modes limit the size of arrays passed to fg_scale and fg_shear to 64K bytes, meaning you cannot apply these functions to larger virtual buffers. Further, the address of a real mode virtual buffer is a segment:offset pair, so you must use the large memory model to scale or shear images residing in virtual buffers in real mode programs.
Example 10-19 demonstrates how to scale the contents of a virtual buffer.
The program creates two virtual buffers -- one is 320x200 pixels and the other is one-fourth this size, or 80x50 pixels. The CORAL.PCX image is loaded into the 320x200 virtual buffer using the fg_loadpcx routine and then copied to the visual page. The program then calls fg_scale, passing it the two virtual buffer addresses, to reduce the image to one-fourth its original size. The resulting image is stored in the 80x50 virtual buffer and finally copied to the lower left corner of the visual page.
Example 10-19.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> #if defined(__TURBOC__) #include <alloc.h> #else #include <malloc.h> #endif void main(void);
void main() { int handle1, handle2; #if defined(__WATCOMC__) || defined(__HIGHC__) char *buffer1, *buffer2; #else � Chapter 10: Bitmapped Images 243
char far *buffer1, far *buffer2; #endif
fg_initpm(); fg_setmode(19); fg_vbinit();
#if defined(__WATCOMC__) || defined(__HIGHC__) buffer1 = (char *)malloc(320*200); buffer2 = (char *)malloc(80*50); #elif defined(__TURBOC__) buffer1 = (char far *)farmalloc(320L*200L); buffer2 = (char far *)farmalloc(80L*50L); #else buffer1 = (char far *)halloc(320L*200L,1); buffer2 = (char far *)halloc(80L*50L,1); #endif if (buffer1 == NULL || buffer2 == NULL) { fg_setmode(3); fg_reset(); printf("Could not create the virtual buffers.\n"); exit(1); } handle1 = fg_vbdefine(buffer1,320,200); handle2 = fg_vbdefine(buffer2,80,50);
fg_vbopen(handle1); fg_loadpcx("CORAL.PCX",0); fg_vbpaste(0,319,0,199,0,199); fg_waitkey();
fg_scale(buffer1,buffer2,320,200,80,50); fg_vbopen(handle2); fg_vbpaste(0,79,0,49,0,199); fg_waitkey();
fg_vbclose(); fg_setmode(3); fg_reset(); }
In example 10-19, we created the virtual buffers with fg_vbdefine, so we
knew their addresses. What if we were using BASIC or real mode Pascal and created them with fg_vballoc? In this case the virtual buffer addresses wouldn't be immediately available to the program. Fortunately, there is an easy solution. Fastgraph's fg_vbaddr function returns the address of the specified virtual buffer; its only argument is the virtual buffer handle. In 16-bit modes, the address will be a real mode segment:offset pair or protected mode selector:offset pair. In 32-bit modes, it will be an offset into the default data segment. If you were using fg_vballoc in example 10-19, the virtual buffer creation and address retrieval could be done as follows:
char far *buffer1, far *buffer2; �
244 Fastgraph User's Guide
handle1 = fg_vballoc(320,200); handle2 = fg_vballoc(80,50); if (handle1 < 0 || handle2 < 0) { fg_setmode(3); fg_reset(); printf("Could not create the virtual buffers.\n"); exit(1); } buffer1 = (char far *)fg_vbaddr(handle1); buffer2 = (char far *)fg_vbaddr(handle2);
The statements to release the memory allocated to the virtual buffers would be:
fg_vbclose(); fg_vbfree(handle1); fg_vbfree(handle2);
Pixel Run Maps
The bitmaps used with the fg_drawmap, fg_drwimage, and related routines
can consume array space quite rapidly. This is especially true if the image is large or contains many colors. For example, a mode-independent bitmapped image that occupies the entire screen in a 320x200 graphics mode requires 8,000 bytes of space per color. Fastgraph provides another mode-independent image format called pixel run maps, which are more efficient in terms of space. Pixel run maps are structured just like the pixel run files introduced in the previous chapter, but the image resides in an array instead of a file.
Let's return to our familiar triangle example and show how we could use a
pixel run map to display it.
. . . . * . . . . . . . * x * . . . . . * x x x * . . . * x x x x x * . * * * * * * * * *
As before, the pixels indicated by an asterisk (*) are the triangle's perimeter, while those indicated by an x represent its interior points. The pixels shown as periods (.) are not part of the triangle itself, but they are part of the pixel run map.
Using the standard pixel run format introduced in the previous chapter,
we see it takes 16 pixel runs to store our triangle image as a pixel run map. If we want to display the perimeter pixels in color 1, the interior pixels in color 2, and the filler area in color 7, the pixel run map would contain 16 sets of (color,count) pairs: (1,9), (7,1), (1,1), (2,5), (1,1), (7,3), (1,1), (2,3), (1,1), (7,5), (1,1), (2,1), (1,1), (7,7), (1,1), and (7,4). Unlike the bitmapped image formats already discussed, pixel run maps have no provision for transparent colors.
The Fastgraph routine fg_display displays an image stored as a pixel run
map. The fg_display routine expects three arguments. The first is an array containing the pixel runs (passed by reference), the second is the number of �
Chapter 10: Bitmapped Images 245
pixel runs in the array, and the third is the width in pixels of the image. As
with the other image display routines, fg_display displays the image such that
its lower left corner is at the graphics cursor position on the active video
page or virtual buffer. Again, the format of the pixel run map is the same as
that of a standard pixel run file. In addition, any display patterns defined
by fg_pattern also apply to fg_display.
Example 10-20 uses the fg_display routine to display the triangle as a
pixel run map in a 320x200 graphics mode. The program displays the triangle against a background of color 7, so the selection of color 7 for the filler area was important. If some other color were chosen, the filler area would not blend in with the background.
Example 10-20.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char triangle[] = { 1,9, 7,1, 1,1, 2,5, 1,1, 7,3, 1,1, 2,3, 1,1, 7,5, 1,1, 2,1, 1,1, 7,7, 1,1, 7,4 };
void main() { int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(7); fg_rect(0,319,0,199);
fg_move(156,101); fg_display(triangle,16,9); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
As you might guess, Fastgraph also offers a packed pixel run map image
format analogous to the packed pixel run file format introduced in the previous chapter. Example 10-21 is the same as example 10-20, but it uses fg_displayp rather than fg_display to display the image. Note the use of � 246 Fastgraph User's Guide
hexadecimal numbers for defining the packed color values, which of course is
not necessary but certainly easier to read than expressing the quantities as
decimal numbers. As with fg_display, any display patterns defined by
fg_pattern also apply to fg_displayp.
Example 10-21.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char triangle[] = { 0x17,9,1, 0x12,1,5, 0x17,1,3, 0x12,1,3, 0x17,1,5, 0x12,1,1, 0x17,1,7, 0x17,1,4 };
void main() { int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(7); fg_rect(0,319,0,199);
fg_move(156,101); fg_displayp(triangle,16,9); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Both fg_display and fg_displayp require the pixel run image to be stored
in an array. In examples 10-20 and 10-21, the image is defined within the program itself. We can also use these routines in place of fg_dispfile when the image is stored in a file if we first read the file contents into an array. Example 10-22 demonstrates this procedure. The program displays two identical images stored in files, one in standard pixel run format and the other in packed pixel run format.
The first image, in standard pixel run format, is in the file CORAL.SPR.
Note the program must open the file for reading in binary mode ("rb" in the call to fopen). The program reads the file's entire contents into the pixel_runs array, whose size must be at least as large as the file size. �
Chapter 10: Bitmapped Images 247
Because the image is stored in standard pixel run format, the number of pixel
runs is one-half the file size. The program then uses fg_move to establish the
lower left corner of the screen as the graphics cursor position and then calls
fg_display to display the image. The image fills the entire screen, so its
width is 320 pixels.
After waiting for a keystroke, the program similarly displays the second
image. This image is in the file CORAL.PPR and is stored in packed pixel run format. Because the image is packed, the number of pixel runs is two-thirds the file size. The program then clears the previous image from the screen and calls fg_displayp to display the image. After another keystroke, the program restores the original video mode and screen attributes and returns to DOS.
Example 10-22.
#include <fastgraf.h> #include <io.h> #include <stdio.h> #include <stdlib.h> void main(void);
char pixel_runs[20000];
void main() { FILE *stream; int file_size, run_count; int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
stream = fopen("CORAL.SPR","rb"); file_size = (int)(filelength(fileno(stream))); fread(pixel_runs,sizeof(char),file_size,stream); fclose(stream); run_count = file_size / 2; fg_move(0,199); fg_display(pixel_runs,run_count,320); fg_waitkey();
stream = fopen("CORAL.PPR","rb"); file_size = (int)(filelength(fileno(stream))); fread(pixel_runs,sizeof(char),file_size,stream); fclose(stream); run_count = file_size / 3 * 2; fg_erase(); fg_displayp(pixel_runs,run_count,320); �
248 Fastgraph User's Guide
fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Masking Maps
It is not possible to include color 0 pixels in an image displayed with
fg_drwimage, fg_clpimage, fg_revimage, or fg_flpimage. This is because these routines consider color 0 pixels to be transparent, which means such pixels do not affect the corresponding pixels in video memory. There are times, however, when you will want color 0 pixels to be destructive, or replace the video memory contents.
Consider again the arrow image of example 10-8. In that example, we
displayed a white (color 3) arrow against a black (color 0) background in the standard CGA four-color graphics mode. Suppose, though, that we want to do just the opposite -- display a black (color 0) arrow against a white (color 3) background. We could of course use fg_putimage, fg_drawmap, or one of the routines for displaying pixel run maps, but these methods do not support clipping or reversing an image. There are, however, four Fastgraph routines designed just for this purpose. These routines are fg_drawmask, fg_clipmask, fg_revmask, and fg_flipmask.
Each of these routines uses a data structure called a masking map. A
masking map is similar in structure to a pixel run map, but it does not include any information about colors. Instead, it consists of a series of pixel runs that alternate between protected and unprotected pixels. An example might best clarify this.
Once again, here is the arrow image of example 10-8.
. . . . . . * . . . . . . . . . * * . . * * * * * * * * * . * * * * * * * * * * * * * * * * * * * . . . . . . . * * . . . . . . . . * . . .
This time, though, we want the arrow to appear in color 0. Put another way, we need the "period" pixels (.) to protect video memory, while we want the "asterisk" pixels (*) to zero video memory. Looking at this problem from the perspective of a pixel run map, we have an alternating series of "protect" and "zero" runs. We don't need any information about pixel colors, just whether to protect or to zero video memory.
This is precisely the structure of a masking map. Starting from the lower
left corner of the image and proceeding to the right, wrapping up to the next row when needed, we could represent this image as a masking map with 6 protected pixels, 1 zeroed pixel, 9 protected pixels, 2 zeroed pixels, and so on. In general, the structure of a masking map is as follows. �
Chapter 10: Bitmapped Images 249
[1] length of 1st protect run
[2] length of 1st zero run
[3] length of 2nd protect run
[4] length of 2nd zero run
. . .
[n-2] length of final protect run
[n-1] length of final zero run
Looking at this diagram, we see the even-numbered array elements hold the
length of the "protect" runs, and the odd-numbered elements hold the length of the "zero" runs. If you need the first run to be a "zero" run, just include a "protect" run of length zero as the first element of the array. If the final run is a "protect" run, you do not need to include a zero-length "zero" run at the end of the array. Finally, if either type of run exceeds 255 pixels, you'll need to split this into two or more pixel runs. In this case, be sure to include a zero-length run of the other type between the two array elements.
Example 10-23 illustrates the use of a masking map through fg_drawmask,
fg_clipmask, fg_revmask, and fg_flipmask in the standard CGA four-color graphics mode (mode 4) to draw a black (color 0) arrow against a white background. These four routines are respectively analogous to fg_drwimage, fg_clpimage, fg_revimage, and fg_flpimage, but they use masking maps rather than bitmaps. The first argument of each routine is the masking map array (passed by reference), the second argument is the number of runs (that is, the number of elements) in the masking map array, and the third argument is the width in pixels of the image.
Example 10-23.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char arrow[] = {6,1,9,2,2,9,1,19,7,2,8,1};
void main() { int old_mode;
fg_initpm(); if (fg_testmode(4,1) == 0) { printf("This program requires a 320 "); printf("x 200 CGA graphics mode.\n"); exit(1); } �
250 Fastgraph User's Guide
old_mode = fg_getmode(); fg_setmode(4); fg_setclip(0,15,0,199);
fg_setcolor(3); fg_rect(0,319,0,199);
fg_move(10,10); fg_drawmask(arrow,12,10); fg_move(10,20); fg_clipmask(arrow,12,10); fg_move(10,30); fg_revmask(arrow,12,10); fg_move(10,40); fg_flipmask(arrow,12,10); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
One of the more useful features of masking maps is their ability to clear
a portion of video memory before placing an image there. This technique provides an efficient, simple way to include color 0 pixels in an image. It is especially effective when displaying large or dithered images because the masking map is typically much smaller than the bitmap required by fg_drawmap or its related routines. Example 10-24 illustrates this process in the standard CGA four-color graphics mode (mode 4) by displaying our arrow image against a colored background. In this example, the arrow has a white (color 3) perimeter and a black (color 0) interior.
The program displays the arrow in two steps. It first uses fg_drawmask to
clear the video memory where the arrow will be displayed. It then draws the arrow's perimeter using fg_drwimage. The interior pixels in the perimeter bitmap are transparent, but since we just zeroed that video memory, they appear in color 0. Note we could improve this example by creating a smaller masking map that only applies to the rectangle inscribing the arrow's interior. That is, we don't need to zero the video memory under the arrow's perimeter because we will immediately display other pixels there.
Example 10-24.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
char arrow_white[] = { 0x00,0x0C,0x00, 0x00,0x0F,0x00, 0xFF,0xFC,0xC0, 0xC0,0x00,0x30, 0xFF,0xFC,0xC0, 0x00,0x0F,0x00, 0x00,0x0C,0x00 };
char arrow_black[] = {6,1,9,2,2,9,1,19,7,2,8,1}; � Chapter 10: Bitmapped Images 251
void main() { int old_mode;
fg_initpm(); if (fg_testmode(4,1) == 0) { printf("This program requires a 320 "); printf("x 200 CGA graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(4);
fg_setcolor(2); fg_rect(0,319,0,199);
fg_move(10,10); fg_drawmask(arrow_black,12,10); fg_drwimage(arrow_white,3,7); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Summary of Bitmapped Image Display Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
For all bitmapped image routines, images are displayed or retrieved so
their lower left corner is at the graphics cursor position (or text cursor position for those routines that also work in text video modes). In 16-bit environments, the size of any arrays passed to these routines is limited to 64K bytes.
FG_CLIPMAP displays a clipped image stored as a mode-independent bitmap.
This routine has no effect when used in a text video mode.
FG_CLIPMASK displays a clipped image stored as a masking map. This
routine has no effect when used in a text video mode.
FG_CLPIMAGE displays a clipped image stored as a mode-specific bitmap.
Color 0 pixels are considered transparent. This routine has no effect when used in a text video mode.
FG_DISPLAY displays an image stored in Fastgraph's standard pixel run
format, where the image resides in an array. This routine has no effect when used in a text video mode. � 252 Fastgraph User's Guide
FG_DISPLAYP displays an image stored in Fastgraph's packed pixel run
format, where the image resides in an array. This routine has no effect when used in a text video mode.
FG_DRAWMAP displays an image stored as a mode-independent bitmap. This
routine has no effect when used in a text video mode.
FG_DRAWMASK displays an image stored as a masking map. This routine has
no effect when used in a text video mode.
FG_DRWIMAGE displays an image stored as a mode-specific bitmap. Color 0
pixels are considered transparent.
FG_FLIPMASK displays a reversed clipped image stored as a masking map.
This routine has no effect when used in a text video mode.
FG_FLPIMAGE displays a reversed clipped image stored as a mode-specific
bitmap. Color 0 pixels are considered transparent. This routine has no effect when used in a text video mode.
FG_GETIMAGE retrieves an image as a mode-specific bitmap.
FG_GETMAP retrieves an image as a mode-independent bitmap. This routine
has no effect when used in a text video mode.
FG_IMAGESIZ determines the number of bytes required to store a mode-
specific bitmapped image of specified dimensions.
FG_INVERT inverts the row order of a mode-specific or mode-independent
bitmapped image, so a "top to bottom" image becomes a "bottom to top" image, or vice versa.
FG_PACK converts a bitmap in the "one pixel per byte" format used in
256-color graphics modes and virtual buffers to the mode-specific bitmap format for the current video mode.
FG_PUTIMAGE displays an image stored as a mode-specific bitmap. No
support is provided for transparent pixels.
FG_REVIMAGE displays a reversed image stored as a mode-specific bitmap.
Color 0 pixels are considered transparent. This routine has no effect when used in a text video mode.
FG_REVMASK displays a reversed image stored as a masking map. This
routine has no effect when used in a text video mode.
FG_SCALE expands or reduces a bitmapped image stored in the "one pixel
per byte" format.
FG_SHEAR shears a bitmapped image stored in the "one pixel per byte"
format.
FG_UNPACK converts a mode-specific bitmapped image to the "one pixel per
byte" format used in 256-color graphics modes and virtual buffers. �
Chapter 10: Bitmapped Images 253
FG_VBADDR returns the address of the specified virtual buffer. In 16-bit
modes, the address will be a real mode segment:offset pair or protected mode selector:offset pair. In 32-bit modes, it will be an offset into the default data segment. � 254 Fastgraph User's Guide
Chapter 11
Block Transfer Routines � 256 Fastgraph User's Guide
Overview
The Fastgraph routines described in this chapter copy rectangular blocks
between areas of video memory, between virtual buffers, between conventional memory and video memory, or between conventional memory and virtual buffers. Such routines are sometimes called Blit or BitBlt routines in other literature. Block transfers are useful in many graphics applications, but they are especially important in animation.
Fastgraph provides several types of block transfer routines, each
optimized for its specific purpose. Because these routines are often used in speed-critical contexts, they do not perform clipping. If needed, clipping can generally be done at the application level by adjusting the block coordinates to fit within the clipping region.
This chapter will discuss Fastgraph's block transfer routines in detail.
The information presented here, combined with the video page, virtual buffer, and image management routines of the previous three chapters, will provide the tools we need for the animation techniques presented in the next chapter.
Full Page Transfer
Fastgraph's simplest block transfer routine is fg_copypage, introduced in
Chapter 8. The fg_copypage routine transfers the entire contents of one video page to another. The first argument is the number of the source video page, and the second argument is the number of the destination video page. The pages may be physical, virtual, or logical video pages. If both the source and destination pages are logical pages, the pages must exist in the same type of memory. For example, you cannot copy a logical page in extended memory to a logical page in conventional memory. The fg_copypage routine always works with video pages, even if a virtual buffer is active.
Example 11-1 illustrates the use of fg_copypage in a 320x200 color
graphics mode. The program displays the word "test" in the middle of the visual page (page 0) and then uses fg_allocate to create a virtual video page (page 1). The virtual page is needed in case the program is running in a video mode with only one physical page. Next, the program uses fg_copypage to transfer the visual page contents to page 1. After waiting for a keystroke, the program erases the visual page, waits for another keystroke, and copies the contents of page 1 back to the visual page. It then releases the virtual page and exits.
Example 11-1.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode;
fg_initpm(); � Chapter 11: Block Transfer Routines 257
new_mode = fg_bestmode(320,200,2); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(7); fg_rect(0,319,0,199); fg_setcolor(9); fg_locate(12,18); fg_text("test",4); fg_waitkey();
fg_allocate(1); fg_copypage(0,1); fg_erase(); fg_waitkey();
fg_copypage(1,0); fg_waitkey();
fg_freepage(1); fg_setmode(old_mode); fg_reset(); }
Byte Boundaries
Video memory, like standard random-access memory, is divided into units
called bytes. In text modes, each byte holds either a character or an attribute. In graphics modes, each byte of video memory holds one or more horizontally contiguous pixels. If two adjacent horizontal pixels are stored in different bytes, then we say a byte boundary exists between the two pixels.
The number of pixels per byte depends on the video mode being used, so
the location of the byte boundaries also depends on the video mode. That is, a byte boundary in a CGA graphics mode is not necessarily a byte boundary in a VGA graphics mode. The following table summarizes the number of pixels per byte of video memory and the byte boundary sequences for each supported graphics video mode. Notice that any horizontal coordinate whose value is a multiple of 8 is always a byte boundary, regardless of the video mode.
mode pixels horizontal coordinates number per byte of byte boundaries
4 4 0, 4, 8, 12, ... , 316 5 4 0, 4, 8, 12, ... , 316 6 8 0, 8, 16, 24, ... , 632 9 2 0, 2, 4, 6, ... , 318 11 8 0, 8, 16, 24, ... , 712 12 4 0, 4, 8, 12, ... , 316 �
258 Fastgraph User's Guide
13 8 0, 8, 16, 24, ... , 312 14 8 0, 8, 16, 24, ... , 632 15 8 0, 8, 16, 24, ... , 632 16 8 0, 8, 16, 24, ... , 632 17 8 0, 8, 16, 24, ... , 632 18 8 0, 8, 16, 24, ... , 632 19 1 0, 1, 2, 3, ... , 319 20 1 0, 4, 8, 12, ... , 316 21 1 0, 4, 8, 12, ... , 316 22 1 0, 4, 8, 12, ... , 316 23 1 0, 4, 8, 12, ... , 316 24 1 0, 1, 2, 3, ... , 639 25 1 0, 1, 2, 3, ... , 639 26 1 0, 1, 2, 3, ... , 799 27 1 0, 1, 2, 3, ... , 1023 28 8 0, 8, 16, 24, ... , 792 29 8 0, 8, 16, 24, ... , 1016
Block transfer routines are often used in animation sequences requiring
high-performance graphics, so these routines must be as efficient as possible. To this end, Fastgraph will force their horizontal pixel coordinates to byte boundaries, which eliminates the need to process any pixels individually. Fastgraph accomplishes this by reducing minimum horizontal coordinates to a byte boundary and extending maximum horizontal coordinates to the last pixel in a video memory byte. Since we are talking about pixel coordinates and not character cells, the coordinate adjustment only occurs in graphics video modes. Designing an application so block transfers occur on byte boundaries might take additional planning, but it will be time well spent.
An example might best help explain this important feature. In the
EGA/VGA/SVGA 16-color graphics modes (modes 13 to 18, 28, and 29), byte boundaries occur at every eighth pixel. Thus, when you use the block transfer routines in these modes, Fastgraph reduces minimum x coordinates to the next lower multiple of eight. Similarly, it extends their maximum x coordinates to the next higher multiple of eight, less one pixel. That is, if a minimum x coordinate is 10 and a maximum x coordinate is 30, Fastgraph will adjust these values to 8 and 31 respectively. If the x coordinates were originally 8 and 31, Fastgraph would leave them unchanged.
In the MCGA and SVGA 256-color graphics modes (modes 19 and 24 to 27)
each pixel occupies a separate byte of video memory, so Fastgraph does not need to adjust horizontal coordinates. However, in the XVGA graphics modes (modes 20 to 23), some coordinate adjustment might be needed. The XVGA modes store four pixels at each video memory address, one in each of four bit planes. The bit plane number for a pixel whose horizontal coordinate is x is given by the quantity x modulo 4. In XVGA modes, the source and destination minimum x coordinates must reference pixels in the same bit plane. Put another way, the relation
xmin_source modulo 4 = xmin_destination modulo 4
must be true. If it isn't, Fastgraph reduces the destination minimum x value to the same bit plane as the source minimum x value. �
Chapter 11: Block Transfer Routines 259
Dual SVGA Banks
Accessing video memory in SVGA graphics modes is controlled through a
banking scheme that maps contiguous 64KB blocks of video memory into a segmented address space. In other words, referencing a specific byte in video memory requires a bank number and an address within that bank. Some SVGA chipsets provide separate read and write bank registers, while others perform both operations through the same bank register.
If a chipset supports separate read and write banks, Fastgraph's block
transfer routines can copy the source region directly to the destination region. However, chipsets that employ a single bank register require that these routines copy the source region to an intermediate buffer and then copy the buffer contents to the destination. This obviously makes a block transfer operation slower on single-bank chipsets. Bit 3 of the fg_svgastat return value will be set if the active SVGA chipset supports separate read and write banks.
The "Hidden" Video Page
Some of Fastgraph's block transfer routines reference a video page called
the hidden page. The Fastgraph routine fg_sethpage defines which video page will be used as the hidden page. This routine takes as its only argument an integer value specifying the hidden page number. If you are using a virtual video page for the hidden page, you must call fg_sethpage after allocating that page. There is also a routine named fg_gethpage that returns the hidden page number, as specified in the most recent call to fg_sethpage, as its function value. The fg_gethpage routine takes no arguments.
Saving and Restoring Blocks
The next two block transfer routines we'll discuss are fg_save and
fg_restore. The fg_save routine transfers a rectangular region from the active video page (as defined in the most recent call to fg_setpage) to the same position on the hidden video page (as defined in the most recent call to fg_sethpage). The fg_restore routine performs the complementary task -- it transfers a rectangular region from the hidden page to the active page. Each of these routines requires four arguments that define the coordinates of the block to transfer, in the order minimum x, maximum x, minimum y, and maximum y. In text modes, the coordinates are expressed as character space quantities (rows and columns). In graphics modes, they are expressed as screen space values (pixels), with the x coordinates extended to byte boundaries if required. There are also world space versions of these routines named fg_savew and fg_restorew available in graphics modes. The fg_restore, fg_restorew, fg_save, and fg_savew routines always work with video pages, even if a virtual buffer is active.
Example 11-2 demonstrates the use of fg_save, fg_restore, and fg_sethpage
in an 80-column text video mode. After establishing the video mode (note the calls to fg_testmode specify that two video pages are needed), the program fills the screen with text and then waits for a keystroke. Following this, the program displays a small pop-up window prompting for another keystroke. After waiting for the second keystroke, the program erases the pop-up window by � 260 Fastgraph User's Guide
restoring the original screen contents, and then waits for yet another
keystroke before returning to DOS. We'll present the program now, and
afterward analyze it in detail.
Example 11-2.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int row; int old_mode; char string[17];
fg_initpm(); old_mode = fg_getmode();
if (fg_testmode(3,2)) fg_setmode(3); else if (fg_testmode(7,2)) fg_setmode(7); else { printf("This program requires\n"); printf("an 80-column display.\n"); exit(1); } fg_cursor(0); fg_setattr(9,7,0);
for (row = 0; row < 25; row++) { sprintf(string," This is row %2d ",row); fg_locate(row,0); fg_text(string,16); fg_text(string,16); fg_text(string,16); fg_text(string,16); fg_text(string,16); } fg_waitkey();
fg_allocate(1); fg_sethpage(1); fg_save(32,47,11,13); fg_setcolor(1); fg_rect(32,47,11,13); fg_setattr(15,1,0); fg_locate(12,33); fg_text("Press any key.",14); fg_waitkey();
fg_restore(32,47,11,13); fg_waitkey(); � Chapter 11: Block Transfer Routines 261
fg_freepage(1); fg_setmode(old_mode); fg_reset(); }
Example 11-2 first establishes the video mode and uses fg_cursor to make
the BIOS cursor invisible. It then executes a for loop that fills each row of the screen with the phrase "This is row n", where n is the row number (between 0 and 24). Next, the program uses fg_allocate to create video page 1 as a virtual video page. This is needed in case the program is running in mode 7, which has only one true page (if the program is running in mode 3, fg_allocate has no effect). The program then makes page 1 the hidden page by calling fg_sethpage.
After setting up the hidden video page, but before displaying the pop-up
window, example 11-2 uses fg_save to save the current contents of the area that the pop-up window will replace. The fg_save routine copies this region to the hidden page. The program then displays the pop-up window in the middle of the screen and leaves it there until a key is pressed. Following this, the program uses fg_restore to replace the pop-up window with the original contents of that region. This effectively erases the pop-up window and restores the original screen. The program then waits for another keystroke, after which it releases the virtual page and returns to DOS.
The next example, 11-3, is similar to example 11-2, but it runs in a
320x200 color graphics mode instead of a text mode. The main differences between this program and example 11-2 are the use of 40-column text and the use of screen space coordinates instead of character space coordinates in the calls to fg_save, fg_restore, and fg_rect. Note that the call to fg_allocate creates a virtual page if the program is running in modes 4, 9, or 19. In modes 13 and 20, which respectively have four and eight physical pages, fg_allocate does nothing.
Example 11-3.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int row; int new_mode, old_mode; char string[21];
fg_initpm(); new_mode = fg_bestmode(320,200,2); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode); �
262 Fastgraph User's Guide
fg_setcolor(7); fg_rect(0,319,0,199); fg_setcolor(9);
for (row = 0; row < 25; row++) { sprintf(string," This is row %2d ",row); fg_locate(row,0); fg_text(string,20); fg_text(string,20); } fg_waitkey();
fg_allocate(1); fg_sethpage(1); fg_save(96,223,88,111); fg_setcolor(1); fg_rect(96,223,88,111); fg_setcolor(15); fg_locate(12,13); fg_text("Press any key.",14); fg_waitkey();
fg_restore(96,223,88,111); fg_waitkey();
fg_freepage(1); fg_setmode(old_mode); fg_reset(); }
A More General Block Transfer Routine
The fg_save and fg_restore routines each copy a rectangular region from
one video page to the same position on another video page. What if you need to copy the region to a different position on another video page, or copy it elsewhere on the same video page? Fastgraph provides a more general block transfer routine named fg_transfer. The fg_transfer routine copies a rectangular region on any video page to any position on any video page (however, it cannot copy overlapping blocks on the same video page). Like fg_save and fg_restore, fg_transfer works in text and graphics video modes. In graphics modes, fg_transfer extends its x coordinates to byte boundaries if necessary. The fg_transfer routine always works with video pages, even if a virtual buffer is active (use fg_vbcut and fg_vbpaste to copy blocks between virtual buffers and video pages, or fg_vbcopy to copy blocks between virtual buffers).
The fg_transfer routine requires eight integer arguments. The first four
arguments define the region to copy, in the same order as expected by fg_save and fg_restore. The next two arguments define the lower left corner of the block destination, while the final two arguments respectively specify the source and destination video page numbers. In short, fg_transfer copies the specified region from the source page to the specified position on the destination page. �
Chapter 11: Block Transfer Routines 263
Example 11-4 is the same as example 11-2, but it uses fg_transfer rather
than fg_save and fg_restore. We have arbitrarily chosen to copy the region overwritten by the pop-up window to the lower left corner of the hidden page (page 1). When we copy this region back to the visual page, we copy from the lower left corner of the hidden page back to the original position on the visual page (page 0). This sequence is shown in the following diagram.
(11,32) (11,47) (22,0) (22,15) first call This is row 11 ------------> This is row 11 This is row 12 This is row 12 This is row 13 <------------ This is row 13 second call (13,32) (13,47) (24,0) (24,15)
visual page (0) hidden page (1)
To copy one region to a new position and then back to its original position, note how we make the fifth and sixth arguments in the first call to fg_transfer the same values as the first and fourth arguments in the second call. Similarly, the fifth and sixth arguments in the second call must be the same as the first and fourth arguments in the first call. With all that out of the way, here is example 11-4.
Example 11-4.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int row; int old_mode; char string[17];
fg_initpm(); old_mode = fg_getmode();
if (fg_testmode(3,2)) fg_setmode(3); else if (fg_testmode(7,2)) fg_setmode(7); else { printf("This program requires\n"); printf("an 80-column display.\n"); exit(1); } fg_cursor(0); fg_setattr(9,7,0);
for (row = 0; row < 25; row++) { sprintf(string," This is row %2d ",row); fg_locate(row,0); �
264 Fastgraph User's Guide
fg_text(string,16); fg_text(string,16); fg_text(string,16); fg_text(string,16); fg_text(string,16); } fg_waitkey();
fg_allocate(1); fg_transfer(32,47,11,13,0,24,0,1); fg_setcolor(1); fg_rect(32,47,11,13); fg_setattr(15,1,0); fg_locate(12,33); fg_text("Press any key.",14); fg_waitkey();
fg_transfer(0,15,22,24,32,13,1,0); fg_fg_waitkey();
fg_freepage(1); fg_setmode(old_mode); fg_reset(); }
Example 11-5 illustrates another use of the fg_transfer routine. This
example is functionally identical to example 10-10, but it uses fg_transfer instead of fg_getmap and fg_drawmap. With the fg_transfer routine, we eliminate the calls to fg_getmap and fg_drawmap, the two calls to fg_move, and the 32-byte array needed to retrieve the block. As an added bonus, using fg_transfer is much faster than the technique of example 10-10, although we probably won't notice this gain with such a small block.
The block copied in example 11-5 is one row of four characters, so its
width in screen space is 32 pixels and its height is 8 pixels. Because the block is in the upper left corner of the screen, the block boundaries are xmin=0, xmax=31, ymin=0, and ymax=7. We want to move the block one-half character cell (4 pixels) to the right and one row (8 pixels) down, so our destination coordinates are x=4 (xmin+4) and y=15 (ymax+8). Note how the program restricts itself to modes 19 and 20 to insure the block copy is not affected by byte boundaries. Also, we are copying the block from one position to another on the visual page, so both the source and destination pages are 0.
Example 11-5.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode, new_mode;
fg_initpm(); � Chapter 11: Block Transfer Routines 265
new_mode = fg_bestmode(320,200,1); if (new_mode < 19) { printf("This program requires a "); printf("256-color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(9); fg_text("text",4); fg_waitkey();
fg_transfer(0,31,0,7,4,15,0,0); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Example 11-6 shows yet another application of fg_transfer in a graphics
video mode. The program displays a rectangle in the upper left quadrant of the screen and then centers the word "quadrant" inside the rectangle. After waiting for a keystroke, the program uses fg_transfer to first copy the upper left quadrant to the upper right quadrant. It then uses fg_transfer again to copy the upper half of the screen to the lower half. The result of this is the screen being filled with what was originally in the upper left quadrant.
Example 11-6.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(7); fg_rect(0,159,0,99); fg_setcolor(9); fg_locate(6,6); fg_text("quadrant",8); �
266 Fastgraph User's Guide
fg_waitkey();
fg_transfer(0,159,0,99,160, 99,0,0); fg_transfer(0,319,0,99, 0,199,0,0); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Block Transfer Routines for Virtual Buffers
Fastgraph's fg_restore, fg_save, and fg_transfer routines copy blocks
between physical or virtual video pages. Other routines are provided for block transfers between virtual buffers and video pages, or between virtual buffers. In our discussion of virtual buffers in Chapter 8, we described Fastgraph's fg_vbcut and fg_vbpaste routines. Recall that fg_vbcut copies a block from the active video page to the active virtual buffer, while fg_vbpaste copies a block from the active virtual buffer to the active video page.
We'll now introduce another block transfer routine, fg_vbcopy, for
copying blocks between two virtual buffers, or to a non-overlapping position in the same virtual buffer. The fg_vbcopy arguments are exactly the same as those of fg_transfer, except the last two arguments reference the source and destination virtual buffer handles instead of video page numbers. Example 11-7 is similar to example 11-6, but it uses fg_vbcopy to perform the two block copy operations in a 320x200 virtual buffer (these were done with fg_transfer in example 11-6). After this, it calls fg_vbpaste to display the virtual buffer contents.
Example 11-7.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#ifdef FG32 char buffer[64000]; #else char far buffer[64000]; #endif
void main() { int handle; int new_mode, old_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); � Chapter 11: Block Transfer Routines 267
} old_mode = fg_getmode(); fg_setmode(new_mode);
fg_vbinit(); handle = fg_vbdefine(buffer,320,200); fg_vbopen(handle);
fg_setcolor(7); fg_rect(0,159,0,99); fg_setcolor(9); fg_locate(6,6); fg_text("quadrant",8);
fg_vbcopy(0,159,0,99,160, 99,handle,handle); fg_vbcopy(0,319,0,99, 0,199,handle,handle); fg_vbpaste(0,319,0,199,0,199); fg_waitkey();
fg_vbclose(); fg_setmode(old_mode); fg_reset();
Blocks with Transparent Colors
The next block transfer routines we'll discuss are fg_tcxfer, fg_tcmask,
and fg_tcdefine. The fg_tcxfer routine is similar to fg_transfer in that it copies a rectangular region from one position to another, but fg_tcxfer allows you to treat one or more colors as transparent (the name fg_tcxfer stands for transparent color transfer). In other words, any pixel whose color value is defined to be transparent is not copied to the destination area. The fg_tcxfer routine's arguments are the same as for the fg_transfer routine, but fg_tcxfer has no effect in text video modes. Because fg_tcxfer must examine the color of individual pixels, it is not nearly as fast as fg_transfer. The fg_tcxfer routine always works with video pages, even if a virtual buffer is active (the fg_vbtcxfer routine, described in the next section, provides transparent color block transfers for virtual buffers).
You can use either fg_tcmask or fg_tcdefine to define which colors are
considered transparent in subsequent calls to fg_tcxfer. The fg_tcmask routine's argument is an integer bit mask (specifically, a 16-bit mask) where each bit indicates whether or not the color is transparent. For example, if bit 0 (the rightmost bit) is set in the mask, then color 0 will be transparent; if bit 0 is reset, color 0 will not be transparent. Because the bit mask size is 16 bits, only the first 16 color values may be defined as transparent using fg_tcmask.
Example 11-8 illustrates the use of the fg_tcxfer and fg_tcmask routines.
This program is similar to example 11-6, except the color of the word "quadrant" (color 9) is defined to be transparent, and fg_tcxfer is used in place of fg_transfer. Because color 9 maps to color 1 in the CGA four-color graphics mode (mode 4), we must define both colors 1 and 9 to be transparent (remember, fg_tcmask considers actual color values transparent, not color indices). The bit mask passed to fg_tcmask thus will be 0000 0010 0000 0010 � 268 Fastgraph User's Guide
binary, or 0202 hex. This causes the word "quadrant" to appear in the
background color (color 0) instead of color 9 in the upper right, lower left,
and lower right quadrants.
Example 11-8.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(7); fg_rect(0,159,0,99); fg_setcolor(9); fg_locate(6,6); fg_text("quadrant",8); fg_waitkey();
fg_tcmask(0x0202); fg_tcxfer(0,159,0,99,160, 99,0,0); fg_tcxfer(0,319,0,99, 0,199,0,0); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
The fg_tcdefine routine expects two integer arguments -- one defining the
color number (between 0 and 255) and another defining the transparency state associated with that color. If the state is zero, the specified color will be opaque (non-transparent). If it is any other value, the color will be transparent. In the previous example, we could use fg_tcdefine instead of fg_tcmask to make colors 1 and 9 transparent by replacing the call to fg_tcmask with the following:
fg_tcdefine(1,1); fg_tcdefine(9,1); � Chapter 11: Block Transfer Routines 269
If you don't call fg_tcmask or fg_tcdefine, the fg_tcxfer routine considers no
colors transparent.
Transparent Block Transfers for Virtual Buffers
Fastgraph's fg_vbtcxfer routine transfers blocks with transparent colors
from the active virtual buffer to the active video page. Its arguments the same as those of fg_vbpaste, but it does not copy any pixels whose colors are transparent. The fg_tcdefine or fg_tcmask routines define which colors are transparent, as when using fg_tcxfer.
Example 11-9 achieves the same result as example 11-8, but it does so
using virtual buffers. Rather than create a full-screen virtual buffer, however, this example creates a virtual buffer one-fourth the screen size and transfers the virtual buffer contents to each quadrant of the visual page in four separate operations. In the upper left quadrant, we simply call fg_vbpaste to display the virtual buffer contents. The three fg_vbtcxfer calls fill the other quadrants, but with color 9 pixels being transparent. This sequence of block copy operations from the virtual buffer creates the same resulting display as example 11-8. Note that this example uses fg_tcdefine to make color 9 transparent; we could just as well have used fg_tcmask.
Example 11-9.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#ifdef FG32 char buffer[16000]; #else char far buffer[16000]; #endif
void main() { int handle; int new_mode, old_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode);
fg_vbinit(); handle = fg_vbdefine(buffer,160,100); fg_vbopen(handle);
fg_setcolor(7); �
270 Fastgraph User's Guide
fg_fillpage(); fg_setcolor(9); fg_locate(6,6); fg_text("quadrant",8); fg_vbpaste(0,159,0,99,0,99); fg_waitkey();
fg_tcdefine(9,1); fg_vbtcxfer(0,159,0,99,160,99); fg_vbtcxfer(0,159,0,99,0,199); fg_vbtcxfer(0,159,0,99,160,199); fg_waitkey();
fg_vbclose(); fg_setmode(old_mode); fg_reset(); }
Transferring Blocks to and from Conventional Memory
The final two block transfer routines we'll discuss are fg_getblock and
fg_putblock. The fg_getblock routine transfers a rectangular region from the active video page or virtual buffer to an array (you can use fg_imagesiz to determine the array size needed to store the block). The fg_putblock routine transfers a block previously retrieved with fg_getblock to the active page or virtual buffer. While these two routines are faster than fg_getimage and fg_putimage, they are not as fast as fg_restore, fg_save, and fg_transfer.
Each of these routines requires five arguments. The first is the address
of the array that will receive or that contains the block. The remaining four arguments define the position of the block on the active page or virtual buffer, in the order minimum x, maximum x, minimum y, and maximum y. In text modes, the coordinates are expressed as character space quantities (rows and columns). In graphics modes, they are expressed as screen space values (pixels), with the x coordinates extended to byte boundaries if required.
Note that both fg_getblock and fg_putblock expect the array address to be
passed by far reference except in BASIC. This means real mode Pascal programs must use the GetMem procedure to allocate storage for the buffer, as this is the only way to pass something by far reference in real mode Pascal. In 16-bit environments, the maximum size of a block is 64K bytes, regardless of which compiler you're using.
Example 11-10 is similar to example 11-5 and shows fg_getblock and
fg_putblock in action in a 320x200 graphics mode. The program displays the word "text" and retrieves it into a 32 by 8 pixel block. After a keystroke, it displays the block 8 pixels below and 8 pixels to the right of its original position. The size of the buffer was chosen to be 256 bytes to accommodate the largest size required for a 32 by 8 block (which occurs in the 256-color graphics modes). Note also how the source and destination horizontal block extremes were chosen for byte boundary alignment in case fg_bestmode selected a 16-color graphics mode.
Example 11-10. � Chapter 11: Block Transfer Routines 271
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#ifdef FG32 char buffer[256]; #else char far buffer[256]; #endif
void main() { int old_mode, new_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(9); fg_text("text",4); fg_getblock(buffer,0,31,0,7); fg_waitkey();
fg_putblock(buffer,8,39,8,15); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Summary of Block Transfer Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
For all block transfer routines, Fastgraph extends the horizontal pixel
coordinates to a byte boundary when the routines are used in a graphics video mode.
FG_COPYPAGE transfers the contents of one video page to another. The
pages may be physical, virtual, or logical video pages. If both pages are logical pages, they must exist in the same type of memory. The fg_copypage routine does not work with virtual buffers. � 272 Fastgraph User's Guide
FG_GETBLOCK retrieves the block (for later display with fg_putblock) at
the specified position on the active video page or virtual buffer. In text modes, the block extremes are defined in character space; in graphics modes, they are defined in screen space.
FG_GETHPAGE returns the hidden page number, as defined in the most recent
call to fg_sethpage.
FG_PUTBLOCK displays the block (previously obtained with fg_getblock) at
the specified position on the active video page or virtual buffer. In text modes, the block extremes are defined in character space; in graphics modes, they are defined in screen space.
FG_RESTORE copies a block from the hidden video page to the same position
on the active video page. The fg_restore routine does not work with virtual buffers.
FG_RESTOREW is the same as fg_restore, but the block extremes are
specified as world space coordinates. The fg_restorew routine does not work with virtual buffers.
FG_SAVE copies a block from the active video page to the same position on
the hidden video page. The fg_save routine does not work with virtual buffers.
FG_SAVEW is the same as fg_save, but the block extremes are specified as
world space coordinates. The fg_savew routine does not work with virtual buffers.
FG_SETHPAGE defines the hidden video page (used by fg_restore,
fg_restorew, fg_save, and fg_savew).
FG_TCDEFINE defines the transparent attribute of a color index for use
with the fg_tcxfer routine. This routine has no effect when used in a text video mode.
FG_TCMASK defines which of the first 16 colors the fg_tcxfer routine will
consider transparent. This routine has no effect when used in a text video mode.
FG_TCXFER copies a block from any position on any video page to any
position on any video page, excluding any pixels whose color value is transparent. This routine has no effect when used in a text video mode and does not work with virtual buffers.
FG_TRANSFER copies a block from any position on any video page to any
position on any video page. It is Fastgraph's most general block transfer routine. The fg_transfer routine does not work with virtual buffers.
FG_VBCOPY copies a rectangular region from one virtual buffer to another,
or to a non-overlapping position within the same virtual buffer.
FG_VBTCXFER copies a rectangular region from the active virtual buffer to
the active video page, excluding any transparent pixels.
Chapter 12
Animation Techniques � 274 Fastgraph User's Guide
Overview
Unlike other microcomputers, the IBM PC and PS/2 family of systems do not
have any special graphics hardware or firmware to help in performing animation. This means any animation done on these systems must be implemented entirely through software. This chapter will show how to do this using Fastgraph's video page management, image display, and block transfer routines. The methods described in this chapter are not intended to be all inclusive, for that would itself fill a separate volume at least as large as this manual. However, the animation techniques presented here should provide a basis that you can readily extend to develop more sophisticated uses of animation. The examples in this chapter are restricted to graphics video modes.
Simple Animation
The first type of animation we'll examine is called simple animation. In
simple animation, we display an object, erase it, and then display it in a new position. When we perform this "erase and redisplay" sequence repetitively, the object moves. This method, however, has two drawbacks. First, unless the object is rather small, it will flicker because the erasing and display of the object does not coincide with the refresh rate of the video display. Second, and perhaps more importantly, anything underneath the object is not saved as the object moves across it. Despite these limitations, simple animation is sometimes useful, and it is a good place to begin our discussion of animation techniques.
Example 12-1 moves a small bright green rectangle (magenta in CGA) from
left to right across the screen in any 320x200 color graphics mode. The program moves the rectangle, 20 pixels wide and 10 pixels high, using a for loop. This loop first uses fg_clprect to display the rectangle, then uses fg_waitfor to leave the object on the screen momentarily, and finally uses fg_clprect again to erase the rectangle by redisplaying it in the original background color (fg_waitfor is described in Chapter 16). We use fg_clprect rather than fg_rect because the first few and last few loop iterations result in at least part of the rectangle being off the screen. Each successive loop iteration displays the rectangle five pixels to the right of its previous position.
Example 12-1.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode; int x;
/* initialize the video environment */
fg_initpm(); new_mode = fg_bestmode(320,200,1); � Chapter 12: Animation Techniques 275
if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode);
/* move the object across the screen */
for (x = -20; x < 320; x+=5) { fg_setcolor(10); fg_clprect(x,x+19,95,104); fg_waitfor(1); fg_setcolor(0); fg_clprect(x,x+19,95,104); }
/* restore the original video mode and return to DOS */
fg_setmode(old_mode); fg_reset(); }
Example 12-2 is the same as example 12-1, but it shows what happens when
we move the rectangle across an existing background (in this case, the background is solid white). If you run this program, you'll see that the rectangle leaves a trail of color 0 pixels behind it. While this might be occasionally useful, it demonstrates that simple animation is destructive because it does not preserve the background. In this example, if we changed the second call to fg_setcolor within the for loop to revert to color 15 instead of color 0, the background would be restored. In general, though, it may not be this easy to replace the background, so we must rely on some other method for preserving it.
Example 12-2.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode; int x;
/* initialize the video environment */
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); �
276 Fastgraph User's Guide
} old_mode = fg_getmode(); fg_setmode(new_mode);
/* draw some type of background */
fg_setcolor(15); fg_rect(0,319,0,199);
/* move the object across the screen */
for (x = -20; x < 320; x+=5) { fg_setcolor(10); fg_clprect(x,x+19,95,104); fg_waitfor(1); fg_setcolor(0); fg_clprect(x,x+19,95,104); }
/* restore the original video mode and return to DOS */
fg_setmode(old_mode); fg_reset(); }
To summarize, we've seen that simple animation is easy to implement, but
it is destructive and typically causes the animated object to flicker. For these reasons, it is not used too frequently.
XOR Animation
"Exclusive or" animation, or XOR animation for short, is an interesting
extension of simple animation and is most useful when animating a single-color object against a single-color background. Like simple animation, it uses the "erase and redisplay" technique to move an object, but it does this differently. Instead of erasing the object by displaying it in the background color, XOR animation does so by displaying it in the same color using an exclusive or, or XOR, operation. This method relies on a specific property of the exclusive or operator:
(object XOR background) XOR object = background
In other words, if you XOR something twice in the same position, the result is the same as the original image in that position.
Example 12-3 demonstrates XOR animation. This program is similar to
example 12-2, but it only runs in the 320x200 EGA graphics mode (mode 13). After establishing the video mode, it uses the Fastgraph routine fg_setfunc to select XOR mode. This causes any subsequent graphics output to be XORed with the contents of video memory instead of just replacing it. The fg_setfunc routine is described further in Chapter 17.
The other differences between examples 12-3 and 12-2 are that the call to
fg_setcolor has been moved outside the for loop, and that fg_setcolor takes a �
Chapter 12: Animation Techniques 277
different value. Since the existing background is bright white (color 15), we
can't just use color 10 if we want to display a bright green object. The
desired value is that which when XORed with color 15 produces color 10; the
easiest way to obtain this value is to XOR these two numbers. The call to
fg_setcolor can be moved outside the loop because we display the object using
the same color index throughout.
Example 12-3.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode; int x;
/* initialize the video environment */
fg_initpm(); if (fg_testmode(13,1) == 0) { printf("This program requires EGA.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(13); fg_setfunc(3);
/* draw some type of background */
fg_setcolor(15); fg_rect(0,319,0,199);
/* move the object across the screen */
fg_setcolor(10^15); for (x = -20; x < 320; x+=5) { fg_clprect(x,x+19,95,104); fg_waitfor(1); fg_clprect(x,x+19,95,104); }
/* restore the original video mode and return to DOS */
fg_setmode(old_mode); fg_reset(); }
Fastgraph only supports the XOR pixel operation in the native EGA and VGA
graphics video modes (modes 13 through 18) and 16-color SVGA modes (28 and 29). Thus, you cannot use XOR animation in CGA, Tandy/PCjr, Hercules, or 256- color graphics modes. � 278 Fastgraph User's Guide
While XOR animation is non-destructive (that is, it restores the original
background), it still suffers from the flickering encountered in simple animation. In spite of this, it may be useful when animating a single-color object against a single-color background.
Static Frame Animation
Static frame animation uses a different strategy than simple animation or
XOR animation. The general scheme of this method is to create the entire animation sequence off-screen and then successively display each item, or frame, in this sequence on one position of the visual video page. This results in a visually appealing animation that is non-destructive and does not include the flickering associated with simple animation and XOR animation. Static frame animation requires the visual video page and one or more additional pages (or virtual buffers) to implement. The number of pages needed depends on the number of frames and the size of each frame.
Example 12-4 runs in any 320x200 color graphics video mode and
illustrates a simple use of static frame animation. The program displays an animation sequence containing 12 frames; it displays this sequence three times. The animation sequence consists of a bright green rectangle (magenta in CGA) moving from left to right across the center of the frame. Each frame is 96 pixels wide and 50 pixels high. The 12 frames are set up on an off-screen video page as shown here:
0 95 96 191 192 287
0 frame 1 frame 2 frame 3 49
50 frame 4 frame 5 frame 6 99
100 frame 7 frame 8 frame 9 149
150 frame 10 frame 11 frame 12 199
Example 12-4 first establishes the video mode and allocates the
additional video page (needed if using a video mode in which page 1 is a virtual video page). The program then generates the background for frame 1; the background is a blue rectangle (cyan in CGA) with a white ellipse centered on it. After the call to fg_ellipse, the first frame is ready.
The next step is to create the remaining 11 frames. In frame 2, the right
half of the 20-pixel wide rectangle will enter the left edge of the frame. In frame 3, the rectangle will be ten pixels farther right, or aligned against the left edge of the frame. In frames 4 through 12, the rectangle will be ten pixels farther right in each frame, so by frame 12 only the left half of the �
Chapter 12: Animation Techniques 279
rectangle appears on the right edge of the frame. The first for loop in the
program builds frames 2 through 12 by copying the background from frame 1 and
then displaying the rectangle (that is, the animated object) in the proper
position for that frame.
The second for loop performs the animation sequence. To display the 12-
frame sequence three times, it must perform 36 iterations. The loop simply copies each frame from the proper position on video page 1 to the middle of the visual video page. Note how fg_waitfor is used to pause momentarily between frames.
Example 12-4.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define VISUAL 0 #define HIDDEN 1
int xmin[] = { 0, 96,192, 0, 96,192, 0, 96,192, 0, 96,192}; int ymax[] = { 49, 49, 49, 99, 99, 99,149,149,149,199,199,199};
void main() { int new_mode, old_mode; int frame, offset; int i, x, y;
/* initialize the video environment */
fg_initpm(); new_mode = fg_bestmode(320,200,2); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode); fg_allocate(HIDDEN);
/* draw the background in the upper left corner */
fg_setpage(HIDDEN); fg_setcolor(1); fg_rect(0,95,0,49); fg_setcolor(15); fg_move(48,25); fg_ellipse(20,20);
/* display the animated object against each background */
fg_setcolor(10); offset = -10; �
280 Fastgraph User's Guide
for (i = 1; i < 12; i++) { x = xmin[i]; y = ymax[i]; fg_transfer(0,95,0,49,x,y,HIDDEN,HIDDEN); fg_setclip(x,x+95,0,199); fg_clprect(x+offset,x+offset+19,y-29,y-20); offset += 10; }
/* slide the object across the background three times */
for (i = 0; i < 36; i++) { frame = i % 12; x = xmin[frame]; y = ymax[frame]; fg_transfer(x,x+95,y-49,y,112,124,HIDDEN,VISUAL); fg_waitfor(2); }
/* restore the original video mode and return to DOS */
fg_freepage(HIDDEN); fg_setmode(old_mode); fg_reset(); }
Dynamic Frame Animation
Dynamic frame animation is similar to static frame animation, but all the
animation frames are built as needed during the animation sequence instead of in advance. When using this method, you must first store a copy of the background on an off-screen video page. Then, to build a frame, create another copy (called the workspace) of the background elsewhere on the off-screen page (or even to a different off-screen page) and display the object on that copy. Finally, transfer the workspace to the visual page. Like static frame animation, this method produces a non-destructive, flicker-free animation sequence.
Example 12-5 is functionally identical to example 12-4, but it uses
dynamic rather than static frame animation. As before, the program builds the background in the upper left corner of video page 1, but it then uses fg_transfer to copy it to the center of the visual video page. The for loop builds each frame as it is needed and also copies it to the center of the visual page. Again, fg_waitfor creates the necessary pause between frames.
Example 12-5.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define VISUAL 0 � Chapter 12: Animation Techniques 281
#define HIDDEN 1
void main() { int new_mode, old_mode; int frame, offset; int i;
/* initialize the video environment */
fg_initpm(); new_mode = fg_bestmode(320,200,2); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode); fg_allocate(HIDDEN);
/* draw the background in the upper left corner */
fg_setpage(HIDDEN); fg_setcolor(1); fg_rect(0,95,0,49); fg_setcolor(15); fg_move(48,25); fg_ellipse(20,20);
/* copy it to the center of the visual page */
fg_transfer(0,95,0,49,112,124,HIDDEN,VISUAL);
/* slide the object across the background three times */
fg_setcolor(10); for (i = 0; i < 36; i++) { frame = i % 12; offset = 10 * frame - 10; fg_transfer(0,95,20,29,112,105,HIDDEN,HIDDEN); fg_rect(112+offset,131+offset,96,105); fg_transfer(112,207,96,105,112,105,HIDDEN,VISUAL); fg_waitfor(2); }
/* restore the original video mode and return to DOS */
fg_freepage(HIDDEN); fg_setmode(old_mode); fg_reset(); }
Two items in example 12-5 merit further discussion. First, we have chosen
our workspace on page 1 so it uses the same screen space coordinates as the � 282 Fastgraph User's Guide
image area on the visual page. This is not necessary unless you are using
fg_restore instead of fg_transfer. Second, the program can use the faster
fg_rect routine in place of fg_clprect. It can do this because even though the
object will extend beyond the workspace limits, we only transfer the workspace
itself. However, for this to function properly, the workspace's horizontal
limits must fall on byte boundaries.
Note too that we do not need to transfer the entire frame during the
animation sequence. In example 12-5, we know the vertical extremes of the moving image are y=96 and y=105, so we only transfer 10 rows instead of the entire frame. We could similarly compute the x extremes for each frame and only transfer the necessary portion. Recall, however, that fg_transfer extends the horizontal coordinates to byte boundaries, so we may copy a few extra pixels as well. This may or may not affect the animation sequence. Again, the problem is eliminated if you align your workspace on byte boundaries.
When we use dynamic frame animation, it is easy to change the number of
frames in the animation sequence. Suppose we wish to produce a smoother animation by increasing the number of frames from 12 to 24. This means the object will move in increments of five pixels instead of ten. The only changes needed are to double the number of loop iterations, modify the calculations for the frame number and offset values as shown here, and reduce the fg_waitfor pause from 2 to 1.
frame = i % 24; offset = 5 * frame - 10;
Compare this to all the changes that would be necessary if we were using
static frame animation.
Page Flipping
Page flipping is a variation of frame animation in which you construct
images on off-screen video pages and then repetitively make those pages the visual page. We can further divide the page flipping technique into static and dynamic variants, as we did with frame animation.
In static page flipping, we construct the entire animation sequence in
advance, with one frame per video page. Once this is done, we can display each frame by using fg_setvpage to switch instantly from one video page to another. Although this produces a smooth, flicker-free animation, we cannot carry the sequence very far before running out of video pages (and hence animation frames).
In dynamic page flipping, we construct each animation frame when it is
needed. As in static page flipping, we construct each frame on a separate video page. However, as example 12-6 demonstrates, we only need three video pages to produce the animation sequence, regardless of the number of frames in the sequence. Two of the three video pages will alternate as the visual page, while the remaining video page keeps a copy of the background.
Example 12-6, which performs an animation sequence similar to examples
12-4 and 12-5, illustrates dynamic frame animation in the 320x200 EGA graphics �
Chapter 12: Animation Techniques 283
video mode (mode 13). The program begins by displaying the background on video
page 2. Video pages 0 and 1 will alternate as the visual page; the page that
is not the visual page is called the hidden page. We start with page 0 as the
visual page, and hence page 1 as the hidden page. To build each frame, the
program uses fg_transfer to copy the background from page 2 to the hidden page
and then uses fg_clprect to display the animated object at the correct
position on the hidden page. After this, it displays the next frame by using
fg_setvpage to make the hidden page the visual page. Before beginning the next
iteration, the program toggles the hidden page number in preparation for the
next frame.
Example 12-6.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode; int hidden; int x;
/* initialize the video environment */
fg_initpm(); if (testmode(fg_13,3) == 0) { printf("This program requires EGA.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(13);
/* draw the background on page two */
fg_setpage(2); fg_setcolor(1); fg_rect(0,319,0,199); fg_setcolor(15); fg_move(160,100); fg_ellipse(20,20);
/* slide the object across the screen */
hidden = 1; setcolor(10); for (x = -10; x < 320; x+=4) { fg_setpage(hidden); fg_transfer(0,319,0,199,0,199,2,hidden); fg_clprect(x,x+19,96,105); fg_setvpage(hidden); hidden = 1 - hidden; fg_waitfor(1); } �
284 Fastgraph User's Guide
/* restore the original video mode and return to DOS */
fg_setmode(old_mode); fg_reset(); }
A problem with either page flipping technique arises if we use virtual
video pages. Page flipping relies on the fact that changing the visual page number occurs instantly, which is exactly what happens when we use physical video pages. However, such is not the case with virtual or logical pages because Fastgraph must copy the entire page contents into video memory. While this occurs quite rapidly, it is not instantaneous, and its effects are immediately apparent on the animation.
An Animation Example: The Fastgraph Fish Tank
If you installed the example programs when you installed Fastgraph, the
EXAMPLES subdirectory will include a fully-commented program called the fish tank that illustrates dynamic frame animation. The fish tank is an excellent example of multi-object non-destructive animation in which several types of tropical fish swim back and forth against a coral reef background. As a picture is worth 1,024 words, we suggest studying the fish tank source code for some useful techniques in developing a complete animation program. The source code for the fish tank program is in FISHTANK.C, FISHTANK.BAS, FISHTANK.FOR, or FISHTANK.PAS, depending on what language support you've installed with Fastgraph.
Summary of Animation Techniques
This chapter has presented five animation techniques: simple animation,
XOR animation, static frame animation, dynamic frame animation, and page flipping. The following table summarizes their behavior.
technique destructive? flicker-free?
simple yes no XOR no no static frame no yes dynamic frame no yes page flipping no yes
Simple animation and XOR animation are elementary techniques that are seldom used once you master frame animation and page flipping.
As stated at the beginning of this chapter, the simple examples presented
here serve as the basis for understanding the mechanics of the animation techniques we have discussed. In "real world" programs, you'll typically want to display an image using the fg_drwimage or fg_drawmap family of routines instead using rudimentary images such as the rectangles in our examples. A helpful rule is to use PCX, GIF, or pixel run files for both backgrounds and moving objects, and then use fg_getimage or fg_getmap to retrieve the moving objects as bitmapped images for later display. Of course, it's desirable to do this "behind the scenes" work on video pages other than the visual page. This �
Chapter 12: Animation Techniques 285
is precisely the technique used in the Fastgraph fish tank. �
286 Fastgraph User's Guide
Chapter 13
Special Effects � 288 Fastgraph User's Guide
Overview
This chapter will discuss the Fastgraph routines that help produce
special visual effects. These include the ability to dissolve the screen contents in small increments, scroll areas of the screen, change the physical origin of the screen, and set up a split screen environment. The accompanying example programs illustrate how to use these routines to produce some interesting effects.
Screen Dissolving
Screen dissolving is the process of replacing the entire screen contents
in random small increments instead of all at once. Fastgraph includes two routines, fg_fadeout and fg_fadein, for this purpose. The fg_fadeout routine incrementally replaces the visual page contents with pixels of the current color, while fg_fadein incrementally replaces the visual page contents with the hidden page contents (that is, the page defined in the most recent call to fg_sethpage). Both routines accept an integer argument that defines the delay between each incremental replacement. A value of zero means to perform the replacement as quickly as possible, while 1 is slightly slower, 2 is slower yet, and so forth. The fg_fadeout and fg_fadein routines have no effect in text video modes and always work with video pages, even if a virtual buffer is active.
Example 13-1 shows how to use fg_fadeout. The program, which runs in any
graphics video mode, first fills the screen with a rectangle of color 2. After waiting for a keystroke, the program incrementally replaces the screen contents with pixels of color 15 (the current color index when fg_fadeout is called). After another keystroke, the program exits gracefully.
Example 13-1.
#include <fastgraf.h> void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(fg_automode());
fg_setcolor(2); fg_rect(0,fg_getmaxx(),0,fg_getmaxy()); fg_waitkey();
fg_setcolor(15); fg_fadeout(0); fg_waitkey();
fg_setmode(old_mode); fg_reset(); } � Chapter 13: Special Effects 289
Example 13-2 shows how to use fg_fadein in any 320x200 color graphics
video mode. The program first fills the screen with a rectangle of color 2 and then fills video page 1 with a rectangle of color 1. After waiting for a keystroke, the program incrementally transfers the contents of page 1 to the visual page. After the call to fg_fadein, both page 0 (the visual page) and page 1 (the hidden page) will contain rectangles of color 1 that fill the entire video page. Finally, the program waits for another keystroke before returning to DOS.
Example 13-2.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,2); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode); fg_allocate(1); fg_sethpage(1);
fg_setcolor(2); fg_rect(0,319,0,199); fg_setpage(1); fg_setcolor(1); fg_rect(0,319,0,199); fg_waitkey();
fg_fadein(0); fg_waitkey();
fg_freepage(1); fg_setmode(old_mode); fg_reset(); }
You also can produce some appealing visual effects by replacing the
screen contents in a non-random fashion using the fg_restore or fg_transfer routines. For example, you could copy the hidden page contents to the visual page through a series of concentric rectangular areas, each slightly larger than the previous, until the entire screen is copied. Another interesting effect is to start around the screen perimeter and proceed toward the screen � 290 Fastgraph User's Guide
center, thus producing a "snake-like" effect. Experimenting with such
techniques may reveal other effects that suit your application.
Scrolling
Another useful effect is scrolling, and Fastgraph provides a routine that
performs vertical scrolling within a given region of the active video page. The fg_scroll routine scrolls a region defined in screen space or character space. It can scroll up or down and offers two types of scrolling: circular and end-off. In circular scrolling, rows that scroll off one edge of the defined region appear at its opposite edge. In end-off scrolling, such rows simply wind up above or below the scrolling area. The following diagrams illustrate the two types of scrolling.
end-off scrolling circular scrolling
before after before after
C B A A
A A B B
In these diagrams, the area bounded by the double lines is the scrolling
region, as specified in the call to fg_scroll. Also, the scrolling direction is assumed to be down (that is, toward the bottom of the screen), and the number of rows to scroll is the height of the area designated B. The number of rows to scroll is often called the scrolling increment.
For the end-off scrolling example, the scrolling operation transfers
region A downward so part of it is copied into area B. The area C (which is the same size as area B) at the top of the scrolling region is filled with pixels of the current color index (as defined in the most recent call to fg_setcolor), and the original contents of area B are lost. The circular scrolling example also copies region A downward into the original area B. Unlike end-off scrolling, however, circular scrolling preserves the area B by copying it to the opposite edge of the scrolling region.
The fg_scroll routine takes six arguments. The first four define the
scrolling region in the order minimum x coordinate, maximum x coordinate, minimum y coordinate, and maximum y coordinate. In graphics video modes, the x coordinates are extended to byte boundaries if needed. The fifth argument is the scrolling increment. It specifies the number of rows to scroll. If it is positive, the scrolling direction is toward the bottom of the screen; if it is negative, the scrolling direction is toward the top of the screen. The sixth and final argument specifies the scroll type. If this value is zero, the scroll will be circular; if it is any other value, the scroll will be end-off. If the scroll type is circular, Fastgraph will use the hidden page (as defined in the most recent call to fg_sethpage) as a workspace (more specifically, the area bounded by the scrolling region extremes on the hidden page will be used). The fg_scroll routine is disabled when a virtual buffer is active. �
Chapter 13: Special Effects 291
We'll now present three example programs that use the fg_scroll routine.
Example 13-3 runs in any 320x200 graphics video mode. The program displays two lines of text ("line one" and "line two") in the upper left corner of the screen against a white background. It then uses fg_scroll to move the second line down four pixel rows using an end-off scroll. After waiting for a keystroke, the program again uses fg_scroll to move the text back to its original position. Note especially how fg_setcolor is used before the first call to fg_scroll to replace the "scrolled off" rows with pixels of color 15, thus preserving the white background.
Example 13-3.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode;
fg_initpm(); new_mode = fg_bestmode(320,200,1); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode);
fg_setcolor(15); fg_rect(0,319,0,199); fg_setcolor(10); fg_text("line one",8); fg_locate(1,0); fg_text("line two",8); fg_waitkey();
fg_setcolor(15); fg_scroll(0,63,8,15,4,1); fg_waitkey(); fg_scroll(0,63,12,19,-4,1); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Example 13-4 is similar to example 13-3, but it runs in the 80-column
color text mode (mode 3). In text modes, we cannot scroll half a character row as in example 13-3, so the program scrolls the minimum one row instead.
Example 13-4. �
292 Fastgraph User's Guide
#include <fastgraf.h> void main(void);
void main() { int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(3); fg_cursor(0);
fg_setcolor(7); fg_rect(0,79,0,24); fg_setattr(10,7,0); fg_text("line one",8); fg_locate(1,0); fg_text("line two",8); fg_waitkey();
fg_setcolor(7); fg_scroll(0,7,1,1,1,1); fg_waitkey(); fg_scroll(0,7,2,2,-1,1); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Example 13-5, the final scrolling example, demonstrates a circular
scroll. The program runs in any 320x200 color graphics video mode; note the use of video page 1 for the workspace required when fg_scroll performs a circular scroll. The program first fills the screen with a light blue rectangle (cyan in CGA), displays a smaller white rectangle in the center of the screen, and then uses fg_move, fg_draw, and fg_paint to display a light green star (magenta in CGA) within the white rectangle. The program executes a while loop to scroll the star upward in four-pixel increments. Because the scroll is circular, rows of the star that "scroll off" the top edge of the white rectangle (whose height is the same as the scrolling region) reappear at its bottom edge. The use of fg_waitfor within the loop simply slows down the scroll. The scrolling continues until any key is pressed.
Example 13-5.
#include <conio.h> #include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int new_mode, old_mode; � Chapter 13: Special Effects 293
fg_initpm(); new_mode = fg_bestmode(320,200,2); if (new_mode < 0 || new_mode == 12) { printf("This program requires a 320 "); printf("x 200 color graphics mode.\n"); exit(1); } old_mode = fg_getmode(); fg_setmode(new_mode); fg_allocate(1); fg_sethpage(1);
fg_setcolor(9); fg_rect(0,319,0,199); fg_setcolor(15); fg_rect(132,188,50,150);
fg_setcolor(10); fg_move(160,67); fg_draw(175,107); fg_draw(140,82); fg_draw(180,82); fg_draw(145,107); fg_draw(160,67); fg_paint(160,77); fg_paint(150,87); fg_paint(160,87); fg_paint(170,87); fg_paint(155,97); fg_paint(165,97);
while (kbhit() == 0) { fg_waitfor(1); fg_scroll(136,184,50,150,-4,0); } fg_waitkey();
fg_freepage(1); fg_setmode(old_mode); fg_reset(); }
Changing the Screen Origin
Fastgraph includes two routines for changing the screen origin. By
changing the screen origin, we simply mean defining the (x,y) coordinate of the upper left corner of the display area. The fg_pan routine performs this function in screen space, while the fg_panw routine does in world space. Neither routine changes the graphics cursor position. Because the function of fg_pan and fg_panw is to change the screen origin, these routines are not applicable to virtual buffers. � 294 Fastgraph User's Guide
Each of these routines has two arguments that specify the x and y
coordinates of the screen origin. For fg_pan, the arguments are integer quantities. For fg_panw, they are floating point quantities.
In the EGA, VGA, MCGA, XVGA, and SVGA graphics modes (modes 13 to 29),
you can set the screen origin to any (x,y) coordinate position (that is, to any pixel). In the other graphics modes, certain restrictions exist, as imposed by specific video hardware. These constraints limit the coordinate positions that can be used as the screen origin. Fastgraph compensates for these restrictions by reducing the specified x and y coordinates to values that are acceptable to the current video mode, as shown in the following table.
x will be reduced y will be reduced video mode to a multiple of: to a multiple of:
4-5 8 2 6 16 2 9 4 4 11 8 4 12 4 2 or 3
In modes 4 and 5, for instance, the x coordinate will be reduced to a multiple of 8 pixels, and the y coordinate will be reduced to a multiple of 2 pixels. In the Hercules low resolution mode (mode 12), the y coordinate reduction depends on whether or not the specified pixel row is scan doubled.
Example 13-6 shows a useful effect that can be made with fg_pan or
fg_panw. This program uses fg_automode to select a video mode and then draws an unfilled white rectangle. The top and bottom sides of the rectangle are intentionally drawn just smaller than the physical screen size. After waiting for a keystroke, the program uses a for loop to make the rectangle jiggle up and down. The rectangle moves because fg_pan is called inside the loop to switch the screen origin between the rectangle's upper left corner and the original origin. Note also the use of fg_waitfor to cause slight delays after each call to fg_pan. If we didn't use fg_waitfor, the changing of the origin would occur so rapidly we wouldn't notice the effect. Finally, the program restores the original video mode and screen attributes before returning to DOS.
Example 13-6.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define DELAY 2 #define JUMP 4
void main() { int i; int old_mode;
fg_initpm(); � Chapter 13: Special Effects 295
old_mode = fg_getmode(); fg_setmode(fg_automode());
fg_setcolor(15); fg_move(0,JUMP); fg_draw(fg_getmaxx(),JUMP); fg_draw(fg_getmaxx(),fg_getmaxy()-JUMP); fg_draw(0,fg_getmaxy()-JUMP); fg_draw(0,JUMP); fg_waitkey();
for (i = 0; i < 6; i++) { fg_pan(0,JUMP); fg_waitfor(DELAY); fg_pan(0,0); fg_waitfor(DELAY); }
fg_setmode(old_mode); fg_reset(); }
The real power of fg_pan becomes clear when it is used with fg_resize to
perform smooth panning. Recall from Chapter 8 that fg_resize changes the video page dimensions in native EGA and VGA graphics modes (modes 13 to 18), the extended VGA graphics modes (20 to 23), and the SVGA graphics modes (24 to 29). We'll now present an example that shows how to use these two routines to perform panning in the low-resolution EGA graphics mode (mode 13). The method it uses also would work in any mode that supports video page resizing.
Example 13-7 begins by establishing the video mode and then immediately
calls fg_resize to increase the video page size to 640x400 pixels. Thus, the video page is now four times its original size. Following this, the program fills the page (the entire page, not just what is displayed) with a bright green rectangle with a white border around it. It then displays the message "Press arrow keys to pan" in the center of the 640x400 page.
The main part of the program is a loop that accepts keystrokes and calls
fg_pan to perform the panning one pixel at a time. When you press any of the four arrow keys, the program adjusts the x and y coordinates for the screen origin as directed. For example, pressing the up arrow key scrolls the screen upward one pixel. When we reach the edge of the video page, the program prevents further scrolling in that direction. This process continues until you press the Escape key, at which time the program restores the original video mode and screen attributes before exiting.
Example 13-7.
#include <fastgraf.h> void main(void);
void main() { unsigned char key, aux; int old_mode; �
296 Fastgraph User's Guide
int x, y;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(13); fg_resize(640,400);
fg_setcolor(2); fg_rect(0,fg_getmaxx(),0,fg_getmaxy()); fg_setcolor(15); fg_box(0,fg_getmaxx(),0,fg_getmaxy()); fg_justify(0,0); fg_move(320,200); fg_print("Press arrow keys to pan.",24);
x = 0; y = 0;
do { fg_getkey(&key,&aux); if (aux == 72 && y < 200) y++; else if (aux == 75 && x < 320) x++; else if (aux == 77 && x > 0) x--; else if (aux == 80 && y > 0) y--; fg_pan(x,y); } while (key != 27);
fg_setmode(old_mode); fg_reset(); }
Panning With Virtual Buffers
The fg_pan routine is not suitable for panning a large image through a
small window because it affects the entire screen. However, you can achieve this type of panning by storing the large image on an off-screen video page or in a virtual buffer and then copy the appropriate portions of it to the fixed window on the visual page. Example 13-8 illustrates this technique using a virtual buffer.
Example 13-8.
#include <fastgraf.h> void main(void);
#ifdef FG32 char buffer[64000]; #else char huge buffer[64000]; #endif � Chapter 13: Special Effects 297
void main() { unsigned char key, aux; int handle; int old_mode; int x, y;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(19);
fg_vbinit(); handle = fg_vbdefine(buffer,320,200); fg_vbopen(handle); fg_loadpcx("CORAL.PCX",0); fg_vbclose();
fg_setcolor(2); fg_fillpage(); fg_setcolor(15); fg_box(111,208,69,130); fg_locate(3,8); fg_text("Press arrow keys to pan.",24);
x = 112; y = 129; fg_vbpaste(x,x+95,y-59,y,112,129);
do { fg_getkey(&key,&aux); if (aux == 72 && y < 199) y++; else if (aux == 75 && x < 223) x++; else if (aux == 77 && x > 0) x--; else if (aux == 80 && y > 59) y--; fg_vbpaste(x,x+95,y-59,y,112,129); } while (key != 27);
fg_setmode(old_mode); fg_reset(); }
Example 13-8 loads our familiar CORAL.PCX image into a 320x200 virtual
buffer. It then sets up a 96x60 region in the middle of the visual page that will serve as a window into the larger CORAL.PCX image (this region is bounded horizontally by x=112 and x=207 and vertically by y=70 and y=129). The first call to fg_vbpaste copies the 96x60 center portion of the virtual buffer to the visual page window. The panning loop is similar to that of example 13-7, except it uses fg_vbpaste to update the window contents. Pressing the arrow keys increments or decrements the coordinates defining the source region in � 298 Fastgraph User's Guide
the virtual buffer. Also, note how we've adjusted the if statements to prevent
fg_vbpaste from accessing pixels outside the virtual buffer.
Split Screen
Fastgraph provides split screen support for EGA, VGA, MCGA, and XVGA
graphics modes (modes 13 through 23) for applications running on VGA or SVGA systems. When a split screen is enabled, the top portion of the screen (rows 0 through n-1, where n is the pixel row at which the split screen takes effect) will contain a subset of the visual video page. The bottom portion (starting at row n) will contain the first fg_getmaxy()-n+1 rows of video page 0. For example, suppose we're using a 200-line graphics mode and we enable a split screen at row 180. If page 1 is the visual video page, the first 180 lines of the screen would be displayed from rows 0 to 179 from page 1, and the last 20 lines would be displayed from rows 0 to 19 of page 0. A split screen environment is useful for maintaining a static image, such as a scoreboard or status box, at the bottom of the screen while scrolling the top portion.
Example 13-9 demonstrates a typical split screen operation in the 320x200
XVGA graphics mode (mode 20). In this example, we'll assume we want to have a status box occupying the last 20 rows (rows 180 to 199) of the screen, while the upper 180 rows (0 to 179) will be scrolled vertically. The program begins by setting the video mode and then calling fg_measure to compute a processor- dependent delay value for slowing down the scrolling (this technique is further explained in Chapter 16).
In mode 20, video memory is structured as four 320x200 physical pages.
Page 1 is not visible when we draw the blue box with the white border, so we don't see it until call fg_setvpage to make page 1 the visual page. This of course also makes page 0 invisible, so we don't see the 20-pixel high red hollow box when we draw it on page 0.
Once we've drawn what we've needed on pages 0 and 1, we activate the
split screen by calling fg_split. The single parameter passed to fg_split is the screen row at which the split screen takes effect, or put another way, the number of rows in the top portion of the screen. In example 13-9 we call fg_split(180), so the first 180 rows of page 1 will appear at the top of the screen, and the first 20 rows of page 0 will appear at the bottom.
Now we're ready to scroll the upper part of the screen (which is now page
1). Fastgraph's fg_pan routine is suitable for this purpose. We achieve the upward scrolling by incrementing the fg_pan y coordinate in a loop. We achieve the downward scrolling by decrementing the y coordinate. We must call fg_stall (or use another similar method) to force a brief delay between iterations. If we didn't do this, the full 20-row scrolling would appear almost instantly, thus losing the scrolling effect. Note that we couldn't use fg_pan to scroll the upper part of the screen in this manner without setting up a split screen environment. That's because by default fg_pan applies to the entire screen. Using the split screen provides us with two independent video pages, and when page 1 is the active video page, fg_pan doesn't touch page 0.
Example 13-9.
#include <fastgraf.h> void main(void); � Chapter 13: Special Effects 299
void main() { int delay, y;
/* initialize the video environment */
fg_initpm(); fg_setmode(20);
/* define a processor-dependent panning delay */
delay = fg_measure() / 16;
/* draw a blue box with a white border on page 1 */
fg_setpage(1); fg_setcolor(9); fg_fillpage(); fg_setcolor(15); fg_box(0,319,0,199); fg_move(160,100); fg_justify(0,0); fg_print("This is page 1",14);
/* display what we just drew on page 1 */
fg_setvpage(1); fg_waitkey();
/* draw a red hollow box at the top of page 0 (now invisible) */
fg_setpage(0); fg_setcolor(12); fg_box(0,319,0,19); fg_setcolor(15); fg_move(160,10); fg_print("SPLIT SCREEN",12);
/* activate the split screen environment, making the first */ /* 20 lines of page 0 appear at the bottom of the screen, */ /* and making the first 180 lines of page 1 appear at the top */
fg_split(180); fg_waitkey();
/* pan upward in one-line increments, displaying the rest of */ /* page 1 */
fg_setpage(1); for (y = 0; y <= 20; y++) { fg_pan(0,y); fg_stall(delay); } fg_waitkey(); �
300 Fastgraph User's Guide
/* pan back down in one-line increments to the original position */
for (y = 20; y >= 0; y--) { fg_pan(0,y); fg_stall(delay); } fg_waitkey();
/* restore 80x25 text mode and exit */
fg_setmode(3); fg_reset(); }
To switch from a split screen environment back to a "single page"
environment, call fg_split with a row parameter equal to the vertical screen resolution for the current video mode.
Summary of Special Effects Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_FADEIN incrementally replaces the visual page contents with the hidden
page contents. This routine has no effect in text video modes and is not applicable to virtual buffers.
FG_FADEOUT incrementally replaces the visual page contents with pixels of
the current color. This routine has no effect in text video modes and is not applicable to virtual buffers.
FG_PAN changes the screen origin (the upper left corner of the screen) to
the specified screen space coordinates. This routine has no effect in text video modes and is not applicable to virtual buffers.
FG_PANW is the world space version of the fg_pan routine.
FG_RESIZE changes the dimensions of a video page in EGA and VGA graphics
modes. This routine is disabled when a virtual buffer is active.
FG_SCROLL vertically scrolls a region of the active video page. The
scrolling may be done either up or down, using either an end-off or circular method. Circular scrolling uses part of the hidden page as a temporary workspace. This routine is not functional when a virtual buffer is active.
FG_SPLIT enables or disables a split screen environment in EGA, VGA,
MCGA, and XVGA graphics modes.
Chapter 14
Input Device Support � 302 Fastgraph User's Guide
Overview
The selection of application input devices is an important part of
designing a program for the IBM PC and PS/2 family of systems. The keyboard and mouse are the most popular, and in fact more and more applications, especially those that use a graphical interface, actually require a mouse to use the product. Another input device, primarily used in entertainment software, is the joystick. Although not as popular as the mouse, joysticks nevertheless can simplify the use of certain applications. Fastgraph provides support for these three types of input devices, and this chapter will discuss this in detail.
Keyboard Support
Fastgraph's keyboard support includes routines to read keystrokes, check
the state of certain keys, and set the state of these keys. In addition, Fastgraph provides a low-level keyboard handler that replaces the BIOS keyboard handler to increase keyboard responsiveness. These routines are independent of the other parts of Fastgraph and thus do not require that you call fg_setmode. All keyboard-related routines work in text and graphics video modes.
The IBM PC and PS/2 keyboards produce two types of character codes --
standard codes and extended codes (extended codes are sometimes called auxiliary codes). The standard codes correspond to the 128 characters in the ASCII character set. In general, pressing keys on the main part of the keyboard, or on the numeric keypad with NumLock turned on, will generate a standard code. The 128 extended codes are specific to the IBM PC and PS/2 keyboards. Some common keystrokes that produce extended codes are keys on the numeric keypad with NumLock turned off, the function keys, or pressing Alt with another key. The following tables show the standard and extended keyboard codes.
Table of standard keyboard codes
key code key code key code key code
(none) 0 space 32 @ 64 ` 96 Ctrl+A 1 ! 33 A 65 a 97 Ctrl+B 2 " 34 B 66 b 98 Ctrl+C 3 # 35 C 67 c 99 Ctrl+D 4 $ 36 D 68 d 100 Ctrl+E 5 % 37 E 69 e 101 Ctrl+F 6 & 38 F 70 f 102 Ctrl+G 7 ' 39 G 71 g 103 Ctrl+H 8 ( 40 H 72 h 104 Ctrl+I 9 ) 41 I 73 i 105 Ctrl+J 10 * 42 J 74 j 106 Ctrl+K 11 + 43 K 75 k 107 Ctrl+L 12 , 44 L 76 l 108 Ctrl+M 13 - 45 M 77 m 109 Ctrl+N 14 . 46 N 78 n 110 Ctrl+O 15 / 47 O 79 o 111 Ctrl+P 16 0 48 P 80 p 112 � Chapter 14: Input Device Support 303
Ctrl+Q 17 1 49 Q 81 q 113 Ctrl+R 18 2 50 R 82 r 114 Ctrl+S 19 3 51 S 83 s 115 Ctrl+T 20 4 52 T 84 t 116 Ctrl+U 21 5 53 U 85 u 117 Ctrl+V 22 6 54 V 86 v 118 Ctrl+W 23 7 55 W 87 w 119 Ctrl+X 24 8 56 X 88 x 120 Ctrl+Y 25 9 57 Y 89 y 121 Ctrl+Z 26 : 58 Z 90 z 122 Ctrl+[ 27 ; 59 [ 91 { 123 Ctrl+\ 28 < 60 \ 92 | 124 Ctrl+] 29 = 61 ] 93 } 125 Ctrl+^ 30 > 62 ^ 94 ~ 126 Ctrl+- 31 ? 63 _ 95 Ctrl+BS 127
Table of extended keyboard codes
code key
3 Ctrl+@ 15 Shift+Tab (back tab) 16-25 Alt+Q to Alt+P (top row of letters) 30-38 Alt+A to Alt+L (middle row of letters) 44-50 Alt+Z to Alt+M (bottom row of letters) 59-68 F1 to F10 71 Home 72 up arrow 73 PgUp 75 left arrow 77 right arrow 79 End 80 down arrow 81 PgDn 82 Ins 83 Del 84-93 Shift+F1 to Shift+F10 94-103 Ctrl+F1 to Ctrl+F10 104-113 Alt+F1 to Alt+F10 114 Ctrl+PrtSc 115 Ctrl+left arrow 116 Ctrl+right arrow 117 Ctrl+End 118 Ctrl+PgDn 119 Ctrl+Home 120-131 Alt+1 to Alt+= (top row of keys) 132 Ctrl+PgUp
In addition, four keys generate the same standard codes as other control key
combinations. These keys are:
key same as code
Backspace Ctrl+H 8 �
304 Fastgraph User's Guide
Tab Ctrl+I 9 Enter Ctrl+M 13 Escape Ctrl+[ 27
The CapsLock, NumLock, and ScrollLock keys do not generate a standard or
extended code when pressed. Instead, they toggle between off and on states.
Reading Keystrokes
When you press a key or key combination, the standard or extended code
representing that keystroke is stored in the ROM BIOS keyboard buffer. This buffer can hold up to 16 keystrokes and thus provides a type-ahead capability. Fastgraph includes three routines for reading keystroke information from the keyboard buffer. The fg_getkey routine reads the next item in the keyboard buffer if one is available (that is, if a key has been pressed). If the keyboard buffer is empty (meaning no key has been pressed), fg_getkey waits for a keystroke and then reports information about it. Another routine, fg_intkey, reads the next keystroke from the keyboard buffer if one is available. If the keyboard buffer is empty, fg_intkey immediately returns and reports this condition. The fg_intkey routine is useful when a program must continue performing a task until a key is pressed. We've already seen the third routine, fg_waitkey, which flushes the keyboard buffer and then waits for another keystroke. Unlike fg_getkey and fg_intkey, fg_waitkey does not return any keystroke information. It is most useful in "press any key to continue" situations.
Both fg_getkey and fg_intkey require two one-byte arguments passed by
reference. If the keystroke is represented by a standard keyboard code, fg_getkey and fg_intkey return its code in the first argument and set the second argument to zero. Similarly, if the keystroke generates an extended code, the routines return its code in the second argument and set the first argument to zero. If fg_intkey detects an empty keyboard buffer, it sets both arguments to zero.
Example 14-1 is a simple program that uses fg_getkey. It solicits
keystrokes and then displays the two values returned by fg_getkey, one of which will always be zero. The variable key receives the key's standard code, while aux receives its extended code. Note that fg_initpm and fg_getkey are the only Fastgraph routines in the program; this can be done because the keyboard support routines are logically independent from the rest of Fastgraph. The program returns to DOS when you press the Escape key.
Example 14-1.
#include <fastgraf.h> #include <stdio.h> void main(void);
#define ESC 27
void main() { unsigned char key, aux;
fg_initpm(); � Chapter 14: Input Device Support 305
do { fg_getkey(&key,&aux); printf("key = %3d aux = %3d\n",key,aux); } while (key != ESC); }
Example 14-2 reads keystrokes using fg_intkey at half-second intervals
(18.2 fg_waitfor units equal one second). As in the previous example, the program displays the standard and extended codes for each keystroke. However, example 14-2 will continuously execute the while loop even if no keystrokes are available, in which case the key and aux values will both be zero. The program returns to DOS when you press the Escape key.
Example 14-2.
#include <fastgraf.h> #include <stdio.h> void main(void);
#define ESC 27
void main() { unsigned char key, aux;
fg_initpm(); do { fg_waitfor(9); fg_intkey(&key,&aux); printf("key = %3d aux = %3d\n",key,aux); } while (key != ESC); }
When you use fg_intkey in a "tight" loop that does little else, you
should force a small delay within the loop by calling fg_waitfor as in example 14-2. Typically a delay of one or two clock ticks is enough. Without this delay, the BIOS may not be able to handle all keyboard activity, and thus some keystrokes may not be available to your program.
Testing and Setting Key States
As mentioned earlier, the CapsLock, NumLock, and ScrollLock keys do not
generate a standard or extended code when pressed but instead toggle between off and on states. Fastgraph includes routines for checking the state of these keys, as well as setting the state of the CapsLock and NumLock keys.
The Fastgraph routines fg_capslock, fg_numlock, and fg_scrlock
respectively read the state of the CapsLock, NumLock, and ScrollLock keys. Each routine has no arguments and returns the key state as its function value. A return value of 0 means the associated key is in the off state, while 1 � 306 Fastgraph User's Guide
indicates the key is in the on state. If the keyboard does not have a
ScrollLock key, fg_scrlock considers the key off and returns a value of zero.
Example 14-3 is a simple program that uses fg_capslock, fg_numlock, and
fg_scrlock to print messages describing the current state of these three keys.
Example 14-3.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { fg_initpm(); if (fg_capslock()) printf("CapsLock is on.\n"); else printf("CapsLock is off.\n");
if (fg_numlock()) printf("NumLock is on.\n"); else printf("NumLock is off.\n");
if (fg_scrlock()) printf("ScrollLock is on.\n"); else printf("ScrollLock is off.\n"); }
You also can set the state of the CapsLock and NumLock keys within a
program. Fastgraph includes two routines, fg_setcaps and fg_setnum, for this purpose. Each routine requires an integer argument that specifies the new key state. If the argument value is 0, the key will be turned off; if the value is 1, the key will be turned on. Example 14-4 uses fg_setcaps and fg_setnum to turn off CapsLock and NumLock.
Example 14-4.
#include <fastgraf.h> void main(void);
void main() { fg_initpm(); fg_setcaps(0); fg_setnum(0); }
On most keyboards, changing key states with fg_setcaps or fg_setnum also
will change the keyboard state light to reflect the new key state. However, some older keyboards, especially when used on PC, PC/XT, or Tandy 1000 �
Chapter 14: Input Device Support 307
systems, do not update the state light. This makes the state light
inconsistent with the true key state.
Low-Level Keyboard Handler
Fastgraph includes a low-level keyboard handler that replaces the BIOS
keyboard handler. The replacement handler intercepts keystrokes ahead of the BIOS and thus eliminates the annoying beep that sounds upon filling the BIOS keyboard buffer. Fastgraph's keyboard handler is especially well-suited to game development because it increases keyboard responsiveness in high-speed action games. However, when the low-level keyboard handler is enabled, it is not possible to use fg_getkey, fg_intkey, fg_waitkey, or any third party functions that use BIOS or DOS services for keyboard activity. For this reason, a program that enables the low-level keyboard handler must disable it before exiting to DOS.
The low-level keyboard handler can be enabled and disabled at any time.
The fg_kbinit routine is provided for this purpose. To enable Fastgraph's low- level keyboard handler, pass the value 1 to fg_kbinit. To disable Fastgraph's handler and re-enable the BIOS keyboard handler, pass the value zero. No harm is caused if you try to enable Fastgraph's keyboard handler when it is already active, or if you try to disable it when the BIOS handler is active.
When the low-level keyboard handler is enabled, you can use fg_kbtest to
check if keys are currently pressed or released. This routine provides the only mechanism for accessing the keyboard when the low-level handler is enabled. It specifies the keys through scan codes. If the corresponding key is pressed, fg_kbtest returns 1. If it is released, the routine returns zero. The fg_kbtest routine can test if any key is pressed if you pass it the value 0 instead of a specific scan code. The following table lists the scan codes corresponding to the keys on a standard PC keyboard.
Table of scan codes
scan scan scan scan key code key code key code key code
Esc 1 I 23 X 45 F9 67 1 2 O 24 C 46 F10 68 2 3 P 25 V 47 NumLock 69 3 4 [ 26 B 48 ScrLock 70 4 5 ] 27 N 49 Home 71 5 6 Enter 28 M 50 Up arrow 72 6 7 Ctrl 29 , 51 PgUp 73 7 8 A 30 . 52 KP- 74 8 9 S 31 / 53 L arrow 75 9 10 D 32 R shift 54 KP5 76 0 11 F 33 KP* 55 R arrow 77 - 12 G 34 Alt 56 KP+ 78 = 13 H 35 Space 57 End 79 BS 14 J 36 CapsLock 58 Dn arrow 80 Tab 15 K 37 F1 59 PgDn 81 Q 16 L 38 F2 60 Ins 82 W 17 ; 39 F3 61 Del 83 E 18 ' 40 F4 62 (unused) 84 �
308 Fastgraph User's Guide
R 19 ` 41 F5 63 (unused) 85 T 20 L shift 42 F6 64 (unused) 86 Y 21 \ 43 F7 65 F11 87 U 22 Z 44 F8 66 F12 88
There are actually more scan codes defined for PC keyboards than listed
in this table. Such scan codes are generated when a key is pressed as a combination of one or more keys, such as when the shift and slash keys are pressed together to produce a question mark (?) character. Fastgraph's low- level keyboard handler is designed to report the pressing or releasing of keys themselves, as opposed to reporting the actual characters so produced. It is thus not possible for the keyboard handler to report the scan code for a multi-key character. If needed, such characters can be identified by the scan codes generated for each key in the sequence. For example, a question mark character would be reported as a forward slash (scan code 53) generated while pressing the left shift (42) or right shift (54) keys.
Example 14-5 illustrates the use of Fastgraph's low-level keyboard
handler. It first uses fg_kbinit to enable Fastgraph's keyboard handler and displays a message stating this. Then, at approximately one second intervals, the program calls fg_kbtest to check which of the four arrow keys are pressed and displays an appropriate message. Pressing Escape restores the BIOS keyboard handler and exits to DOS.
Example 14-5.
#include <fastgraf.h> #include <stdio.h> void main(void);
#define ESC 1 #define LEFT 75 #define RIGHT 77 #define UP 72 #define DOWN 80
void main() { fg_initpm(); fg_kbinit(1); printf("Keyboard handler enabled.\n");
do { printf("keys pressed: "); if (fg_kbtest(LEFT)) printf("Left "); if (fg_kbtest(RIGHT)) printf("Right "); if (fg_kbtest(UP)) printf("Up "); if (fg_kbtest(DOWN)) printf("Down "); printf("\n"); fg_waitfor(18); } while (fg_kbtest(ESC) == 0);
fg_kbinit(0); printf("Keyboard handler disabled.\n"); } � Chapter 14: Input Device Support 309
Fastgraph includes two other routines for the low-level keyboard handler.
The fg_kblast function returns the scan code for the most recent keypress processed by the low-level keyboard handler. If there have been no key presses since calling fg_kbinit, the return value will be zero. The fg_kbreset routine resets the state of Fastgraph's low-level keyboard handler to what it was after being initialized with fg_kbinit(1). This has the effect of "flushing" the keyboard handler. Neither of these two functions has any arguments.
Mouse Support
The mouse is a very popular input and pointing device, especially in
graphically-oriented programs. Fastgraph contains several routines to support mice. These routines perform such tasks as mouse initialization, controlling and defining the mouse cursor, and reporting information about the mouse position and button status.
The underlying software that controls the mouse is called the mouse
driver. Fastgraph's mouse support routines provide a high-level interface to this driver. The Microsoft Mouse and its accompanying mouse driver have become an industry standard, and other manufacturers of mice have also made their mouse drivers Microsoft compatible. For this reason, the Fastgraph mouse support routines assume you are using a Microsoft or compatible mouse driver.
Unfortunately, not all mouse drivers are created equal. That is, some
drivers are not Microsoft compatible, even though they may be advertised as such. In some cases, these incompatibilities are rather trivial, but others are significant. For example, early versions of some third party mouse drivers had real problems in the EGA graphics modes. The Microsoft mouse driver, the Logitech mouse driver (version 3.2 or above), and the DFI mouse driver (version 3.00 or above) are known to work well with Fastgraph's mouse support routines. Any other Microsoft compatible mouse driver also should work properly.
Initializing the Mouse
There are two steps required to use Fastgraph's mouse support routines
within an application program. First, you must install the mouse driver. This is done before running the application, typically by entering the command MOUSE at the DOS command prompt. Second, you must use Fastgraph's fg_mouseini function to initialize the mouse within the program.
The fg_mouseini function has no arguments and returns a "success or
failure" indicator as its function value. If the return value is -1, it means fg_mouseini could not initialize the mouse (either because the mouse driver is not installed, or the driver is installed but the mouse is physically disconnected). The return value will also be -1 if fg_mouseini is called when a virtual buffer is active. If fg_mouseini returns a positive integer value, the mouse initialization was successful. The value itself indicates the number of buttons (either 2 or 3) on the mouse. If you don't call fg_mouseini, or if � 310 Fastgraph User's Guide
fg_mouseini can't initialize the mouse, none of Fastgraph's other mouse
support routines will have any effect.3
Example 14-6 illustrates how to initialize the mouse. Unlike the keyboard
support routines, Fastgraph's mouse support routines require that fg_setmode be called first. In this example, we simply pass fg_setmode the value -1 to initialize Fastgraph for whatever video mode is in effect when we run the program. The program then calls fg_mouseini and prints a message indicating whether or not the initialization was successful. If it was, the message includes the number of buttons on the mouse.
Example 14-6.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int status;
fg_initpm(); fg_setmode(-1); status = fg_mouseini();
if (status < 0) printf("Mouse not available.\n"); else printf("%d button mouse found.\n",status); }
You should be aware that certain mouse drivers do not fully initialize
the mouse when a program changes video modes. This problem most frequently occurs when you restore the original video mode at the end of a program that has called fg_mouseini. When changing video modes, you must first make the mouse cursor invisible (this is described in the next section), change the video mode, and then call fg_mouseini again to initialize the mouse for the new video mode.
XVGA and SVGA Mouse Considerations
Mouse drivers cannot directly display the mouse cursor in XVGA and SVGA
graphics modes (modes 20 to 29). Hence, Fastgraph must display the mouse cursor through an interrupt handler that is activated whenever the mouse moves. The handler is automatically installed when you call fg_mouseini in modes 20 to 29.
____________________
(3) If you use another mouse library or communicate directly with the mouse
driver, you must still call fg_mouseini if your program runs in modes 13 through 18. Otherwise, Fastgraph won't know that your program is using a mouse and may display graphics incorrectly. �
Chapter 14: Input Device Support 311
If you do not disable this handler before your program exits, it will
remain "hooked" to the mouse driver. This will most likely hang your system the next time you try doing anything of consequence. The fg_mousefin routine removes Fastgraph's mouse interrupt handler from the mouse driver. In XVGA and SVGA graphics modes, you should call fg_mousefin just before restoring the original video mode, as shown here:
fg_mousefin(); fg_setmode(old_mode); fg_reset();
Again, calling fg_mousefin is required only in XVGA and SVGA graphics modes.
Calling it in other video modes is not applicable, though it causes no
problems.
In the standard VGA/MCGA 256-color mode (mode 19), white pixels in the
mouse cursor are displayed in color 15. This is inconsistent with other graphics modes, where the mouse cursor's white pixels are displayed in the highest-numbered color value available in that mode. Fastgraph corrects this inconsistency in XVGA and SVGA 256-color graphics modes by displaying white mouse cursor pixels in color 255. Like color 15, color 255 is white by default. This allows you to redefine color 15 in your 256-color applications without interfering with the mouse cursor colors.
Controlling the Mouse Cursor
The mouse cursor indicates the current position of the mouse. By default,
the cursor is a small white arrow in graphics modes and a one-character rectangle in text modes. After you use fg_mouseini to initialize the mouse, the mouse cursor is invisible. To make it visible, you must use fg_mousevis. This routine has a single integer argument that defines the mouse cursor visibility. If it is 0, the mouse cursor will be invisible; if it is 1, the mouse cursor becomes visible. If the mouse cursor is already in the requested state, fg_mousevis does nothing.
If the mouse cursor is in an area of the screen being updated, or if it
moves into this area during the update process, you must make the mouse cursor invisible or freeze it at its current position. You must also do this when performing any video output in the native EGA and VGA graphics modes (modes 13 through 18). Instead of checking for these conditions, it is often more convenient and efficient to make the mouse cursor invisible during all screen updates and then make it visible again when the updating is finished. An alternative to making the mouse cursor invisible is freezing it at its current position using fg_mousepos and fg_mouselim (these routines will be described shortly) during screen updates and then restoring the default mouse limits. Note, however, that this method only works if the mouse cursor is outside the area being updated. You must also make the mouse cursor invisible when changing the visual page number with fg_setvpage.
After you initialize the mouse, the cursor is positioned in the center of
the screen. Moving the mouse of course changes the cursor position, but you also can position the mouse cursor with the Fastgraph routine fg_mousemov. This routine has two arguments that specify the new horizontal and vertical � 312 Fastgraph User's Guide
cursor position. The position is expressed in screen space units for graphics
modes, while it is expressed in character cells for text modes. The
fg_mousemov routine moves the cursor whether or not it is visible.
Sometimes it is useful to restrict the mouse cursor to a specific area of
the screen. The Fastgraph routine fg_mouselim prevents the mouse cursor from moving outside the specified rectangular area. It requires four arguments that specify the minimum horizontal coordinate, maximum horizontal coordinate, minimum vertical coordinate, and maximum vertical coordinate of this area. Again, the coordinates are expressed in screen space units for graphics modes and character cells for text modes.
One of the most important functions of the mouse driver is to translate
the horizontal and vertical mouse movements into a position on the screen. The mouse reports these movements to the mouse driver in units called mickeys (one mickey is about 1/200 of an inch, though for some mouse drivers it is 1/400 of an inch). By default, moving the mouse 8 mickeys in the horizontal direction moves the mouse cursor one horizontal pixel. Similarly, moving the mouse 16 mickeys vertically moves the cursor one vertical pixel. Fastgraph provides a routine named fg_mousespd that can change these values, which effectively allows you to control the speed at which the mouse cursor moves relative to the movement of the mouse itself. The fg_mousespd routine requires two arguments that define the number of mickeys required for eight pixels of mouse cursor movement. The first argument specifies this for the horizontal direction, and the second for the vertical direction.
Example 14-7, which runs in any graphics mode, demonstrates fg_mousevis,
fg_mousemov, fg_mouselim, and fg_mousespd. The program first establishes the video mode, initializes the mouse, and fills the screen with a white rectangle. Next, the program calls fg_mousevis to make the mouse cursor visible and then calls fg_mouselim to restrict the mouse cursor to an area one-fourth the size of the screen, centered in the middle of the screen. At this point you should move the mouse cursor around the screen to see the effect of fg_mouselim and note the speed at which the cursor moves relative to the mouse itself. The program continues when you press any key.
The program then uses fg_mousemov to move the mouse cursor to each corner
of the region established by fg_mouselim. The call to fg_waitfor keeps the cursor in each corner for two seconds, unless you move the mouse. Note how the program tries to move the mouse cursor to each corner of the screen, but since doing so would move the cursor outside the defined region of movement, fg_mousemov just positions the cursor at the nearest point possible within this region. The last call to fg_mousemov moves the cursor back to the middle of the screen. After doing this, the program calls fg_mousespd to change the mouse cursor speed. The values passed to fg_mousespd (16 and 32) are twice the defaults and therefore make you move the mouse twice as far as before to move the mouse cursor the same distance. When you run the program, compare the mouse sensitivity to the original speed. After a keystroke, the program returns to DOS.
Example 14-7.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void); � Chapter 14: Input Device Support 313
void main() { int maxx, maxy; int old_mode;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(fg_automode());
if (fg_mouseini() < 0) { fg_setmode(old_mode); fg_reset(); exit(1); }
maxx = fg_getmaxx(); maxy = fg_getmaxy(); fg_setcolor(15); fg_rect(0,maxx,0,maxy);
fg_mousevis(1); fg_mouselim(maxx/4,3*maxx/4,maxy/4,3*maxy/4); fg_waitkey();
fg_mousemov(0,0); fg_waitfor(36); fg_mousemov(maxx,0); fg_waitfor(36); fg_mousemov(maxx,maxy); fg_waitfor(36); fg_mousemov(0,maxy); fg_waitfor(36); fg_mousemov(maxx/2,maxy/2); fg_mousespd(16,32); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
Reporting the Mouse Status
It is obviously important to be able to track the mouse position and
button status. The Fastgraph routines fg_mousepos and fg_mousebut enable you to do this.
The fg_mousepos routine returns information about the current mouse
cursor position and button status. It requires three integer arguments, all passed by reference. The first two arguments respectively receive the horizontal and vertical coordinates of the mouse cursor. These values are expressed in screen space units for graphics modes and character cells for text modes. The third argument receives a three-bit mask containing the button status as shown here: � 314 Fastgraph User's Guide
bit number meaning
0 1 if left button pressed, 0 if not 1 1 if right button pressed, 0 if not 2 1 if middle button pressed, 0 if not
For example, if both the left and right buttons are pressed, the button status will be set to 3. If the mouse only has two buttons, bit 2 will always be zero.
Another routine, fg_mousebut, is available for returning the number of
button press or release counts that have occurred since the last check, or since calling fg_mouseini. Each mouse button maintains its own separate counters, so fg_mousebut returns this information for a specific button. Additionally, fg_mousebut returns the horizontal and vertical position of the mouse cursor at the time the specified button was last pressed or released.
The fg_mousebut routine takes four integer arguments, of which the last
three are passed by reference. The absolute value of first argument specifies the button of interest (1 means the left button, 2 is the right button, and 3 is the middle button), while its actual value determines if we're checking presses or releases. If the value is positive, button press counts will be reported. If it is negative, release counts will be reported. The second, third, and fourth arguments respectively receive the press or release count, the horizontal mouse cursor position at the time of the last press or release, and the vertical position at that same time. If the press or release count is zero, the mouse cursor position is returned as (0,0). The coordinate positions are expressed in screen space units for graphics modes and character cells for text modes.
Example 14-8 runs in any graphics video mode and illustrates the use of
fg_mousepos and fg_mousebut. The program first establishes the video mode and then initializes the mouse (the program exits if the initialization fails). It next fills the entire screen with a white rectangle and then calls fg_mousevis to make the mouse cursor visible.
The main part of example 14-8 is a while loop that polls the mouse at
three-second intervals (the call fg_waitfor(54) delays the program for three seconds). Within the loop, the program first uses fg_mousebut to get the number of times the left mouse button was pressed in the last three seconds. Following this, the fg_mousepos routine gets the current mouse position. The program then displays this information in the upper left corner of the screen; note how fg_mousevis is used to make the cursor invisible during graphics operations. The program continues until you press the right mouse button, checked by the call to fg_mousebut at the end of the loop.
Example 14-8.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() � Chapter 14: Input Device Support 315
{ int old_mode; int buttons, count; int x, y; char string[25];
fg_initpm(); old_mode = fg_getmode(); fg_setmode(fg_automode());
if (fg_mouseini() < 0) { fg_setmode(old_mode); fg_reset(); exit(1); }
fg_setcolor(15); fg_rect(0,fg_getmaxx(),0,fg_getmaxy()); fg_mousevis(1);
do { fg_waitfor(54); fg_mousebut(1,&count,&x,&y); fg_mousepos(&x,&y,&buttons); sprintf(string,"X=%3d Y=%3d count=%4d",x,y,count); fg_mousevis(0); fg_setcolor(15); fg_rect(0,fg_xconvert(25),0,fg_yconvert(1)); fg_setcolor(0); fg_locate(0,0); fg_text(string,24); fg_mousevis(1); fg_mousebut(2,&count,&x,&y); } while (count == 0);
fg_setmode(old_mode); fg_reset(); }
Defining the Mouse Cursor
By default, the mouse cursor is a small white arrow in graphics modes and
a one-character rectangle in text modes. In graphics modes, you can change the mouse cursor to any 16 by 16 pixel image with the Fastgraph routine fg_mouseptr (in the CGA four-color graphics modes, the cursor size is 8 by 16 pixels). You cannot change the mouse cursor shape in text modes, but you can use the Fastgraph routine fg_mousecur to define how it interacts with existing characters on the screen. � 316 Fastgraph User's Guide
Text Modes
To change the mouse cursor in text modes, you must first define two 16-
bit quantities called the screen mask and cursor mask. The following figure defines the format of each mask.
bits meaning
0 to 7 ASCII character value 8 to 11 foreground color 12 to 14 background color 15 blink
Notice how this structure parallels the character and attribute bytes associated with each character cell. The default screen mask is 77FF hex, and the default cursor mask is 7700 hex.
When you position the mouse over a specific character cell, the mouse
driver uses the current screen and cursor masks to determine the mouse cursor's appearance. First, the mouse driver logically ANDs the screen mask with the existing contents of that character cell. It then XORs that result with the cursor mask to display the mouse cursor.
For example, consider how the mouse cursor is produced in the 80-column
color text mode (mode 3). Suppose a specific character cell contains the ASCII character 0 (48 decimal, 30 hex) and an attribute byte that specifies a white (color 15) foreground on a blue background (color 1) and does not blink (blink bit 0). The binary structure of the character and its attribute are:
attribute character
0 001 1111 00110000
Now let's see what happens when we apply the screen and cursor masks to the
character and its attribute.
attribute/character 0001 1111 0011 0000 (1F30 hex) default screen mask 0111 0111 1111 1111 (77FF hex) ------------------- result of AND 0001 0111 0011 0000 (1730 hex) default cursor mask 0111 0111 0000 0000 (7700 hex) ------------------- result of XOR 0110 0000 0011 0000 (6030 hex)
The resulting character (30 hex) is the original character, but the new
attribute (60 hex) represents a black foreground with a brown background and
does not blink. As long as the mouse cursor remains positioned on this
character cell, it would appear black on brown.
When we use the default screen and cursor masks, the mouse cursor will
always display the original character and it will not blink. The cursor foreground color will be 15-F, where F is the displayed character's foreground color. Similarly, the cursor background color will be 7-B, where B is the �
Chapter 14: Input Device Support 317
displayed character's background color. The default masks will virtually
always produce a satisfactory mouse cursor.
It is possible, however, to change the appearance of the mouse cursor in
text modes by using your own screen and cursor masks. The Fastgraph routine fg_mousecur does just that. It expects two arguments, the first being the cursor mask and the second the screen mask. Example 14-9 demonstrates the use of fg_mousecur. The program displays some text and uses the default mouse cursor. After waiting for a keystroke, the program calls fg_mousecur to define a new mouse cursor. The new cursor is similar to the default cursor, but it displays the foreground colors in the opposite intensity as the default cursor. The program then waits for another keystroke before returning to DOS.
Example 14-9.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int old_mode; int row;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(3);
if (fg_mouseini() < 0) { fg_setmode(old_mode); fg_reset(); exit(1); }
fg_setattr(7,0,0); fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
fg_setattr(12,7,0); for (row = 0; row < 25; row++) { fg_locate(row,34); fg_text("example 14-9",12); }
fg_mousevis(1); fg_waitkey(); fg_mousecur(0x7FFF,0x7F00); fg_waitkey();
fg_setmode(old_mode); fg_reset(); } �
318 Fastgraph User's Guide
Graphics Modes
Defining the mouse cursor in graphics video modes also requires creating
a screen mask and cursor mask, but as one might expect, the structure of these masks is vastly different from text modes. In fact, it closely resembles the mode-independent bitmap format used by fg_drawmap. Although their structure differs, the way the mouse driver applies the masks is the same as in the text modes. That is, the driver displays the mouse cursor by first logically ANDing video memory with the screen mask, and then XORing that result with the cursor mask.
Let's begin by looking at the masks for the default mouse cursor in
graphics modes. The size of each mask (and hence the mouse cursor) is 16 pixels wide and 16 pixels high. As mentioned earlier, the default cursor is a small white arrow with a black outline around it. Here are its screen and cursor masks expressed as binary values.
screen cursor cursor mask mask appearance
1001111111111111 0000000000000000 ** 1000111111111111 0010000000000000 *x* 1000011111111111 0011000000000000 *xx* 1000001111111111 0011100000000000 *xxx* 1000000111111111 0011110000000000 *xxxx* 1000000011111111 0011111000000000 *xxxxx* 1000000001111111 0011111100000000 *xxxxxx* 1000000000111111 0011111110000000 *xxxxxxx* 1000000000011111 0011111111000000 *xxxxxxxx* 1000000000001111 0011111000000000 *xxxxx***** 1000000011111111 0011011000000000 *xx*xx* 1000100001111111 0010001100000000 *x* *xx* 1001100001111111 0000001100000000 ** *xx* 1111110000111111 0000000110000000 *xx* 1111110000111111 0000000110000000 *xx* 1111111000111111 0000000000000000 ***
The mouse driver first ANDs the screen mask with video memory at the
mouse cursor position. This means the screen mask 1 bits leave video memory intact, while the 0 bits change the corresponding pixels to black. Next, the mouse driver XORs the result with the cursor mask. This time the cursor mask 0 bits leave video memory unchanged, while the 1 bits change the corresponding pixels to white. This produces a mouse cursor as shown above on the right, where a dot ( ) represents an unchanged pixel, an asterisk (*) a black pixel, and an x a white pixel. The following table summarizes the cursor appearance for all possible combinations of mask bits.
screen mask bit cursor mask bit resulting cursor pixel
0 0 black 0 1 white 1 0 unchanged 1 1 inverted
The color of an "inverted" pixel is n-k, where n is the maximum color
number in the current video mode, and k is the color of the pixel being �
Chapter 14: Input Device Support 319
replaced. Also, "black" and "white" pixels are not necessarily these colors in 16-color and 256-color modes. More correctly, "black" pixels are displayed in the color assigned to palette 0, and "white" pixels are the displayed in the color assigned to palette 15 (255 in XVGA and SVGA 256-color modes). If you're using the CGA color modes, "black" pixels are displayed in the background color, and "white" pixels appear in color 3 (whose actual color is determined by the selected CGA palette).
With an understanding of the way the default mouse cursor works in
graphics modes, we're now ready to define our own mouse cursor. Shown here are the screen mask, cursor mask, and resulting appearance for a solid plus-shaped cursor. The hexadecimal equivalents of the binary mask values are also given.
----- screen mask ---- ----- cursor mask ---- cursor binary hex binary hex appearance
1110000000111111 E03F 0000000000000000 0000 ...*******...... 1110000000111111 E03F 0000111110000000 0F80 ...*xxxxx*...... 1110000000111111 E03F 0000111110000000 0F80 ...*xxxxx*...... 0000000000000111 0007 0000111110000000 0F80 ****xxxxx****... 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*... 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*... 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*... 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*... 0000000000000111 0007 0111111111110000 7FF0 *xxxxxxxxxxx*... 0000000000000111 0007 0000111110000000 0F80 ****xxxxx****... 1110000000111111 E03F 0000111110000000 0F80 ...*xxxxx*...... 1110000000111111 E03F 0000111110000000 0F80 ...*xxxxx*...... 1110000000111111 E03F 0000000000000000 0000 ...*******...... 1111111111111111 FFFF 0000000000000000 0000 ................ 1111111111111111 FFFF 0000000000000000 0000 ................ 1111111111111111 FFFF 0000000000000000 0000 ................
If we wanted to make the mouse cursor hollow rather than solid, the masks and resulting cursor appearance would look like this.
----- screen mask ---- ----- cursor mask ---- cursor binary hex binary hex appearance
1110000000111111 E03F 0000000000000000 0000 ...*******...... 1110111110111111 EFBF 0000000000000000 0000 ...*.....*...... 1110111110111111 EFBF 0000000000000000 0000 ...*.....*...... 0000111110000111 0F87 0000000000000000 0000 ****.....****... 0111111111110111 7FF7 0000000000000000 0000 *...........*... 0111111111110111 7FF7 0000000000000000 0000 *...........*... 0111111111110111 7FF7 0000001000000000 0200 *.....x.....*... 0111111111110111 7FF7 0000000000000000 0000 *...........*... 0111111111110111 7FF7 0000000000000000 0000 *...........*... 0000111110000111 0F87 0000000000000000 0000 ****.....****... 1110111110111111 EFBF 0000000000000000 0000 ...*.....*...... 1110111110111111 EFBF 0000000000000000 0000 ...*.....*...... 1110000000111111 E03F 0000000000000000 0000 ...*******...... 1111111111111111 FFFF 0000000000000000 0000 ................ 1111111111111111 FFFF 0000000000000000 0000 ................ 1111111111111111 FFFF 0000000000000000 0000 ................ �
320 Fastgraph User's Guide
Note that the center bit defined in the cursor mask causes the corresponding
pixel in video memory to be inverted.
There is one more item needed to define a graphics mode mouse cursor
completely. That item is the hot spot, or the actual screen position used or reported by the mouse driver. For the plus-shaped cursors just constructed, it would make sense to define the hot spot in the center of the plus. The hot spot is specified relative to the upper left corner of the cursor, so its position within the cursor would be (6,6) -- that is, six pixels to the right and six pixels below the upper left corner. You can specify the hot spot offsets using negative values or values above 15 to position it outside the mouse cursor matrix if desired.
The Fastgraph routine fg_mouseptr defines a mouse cursor in graphics
modes. The first of its three arguments is a 32-element 16-bit integer array, passed by reference. The array's first 16 elements contain the screen mask, and its second 16 elements contain the cursor mask. The remaining two arguments respectively specify the horizontal and vertical offsets for the hot spot. The fg_mouseptr routine has no effect in a text video mode. In C or C++ programs, we recommend using the short data type for the mask array because short means a 16-bit integer for both 16-bit and 32-bit environments. Similarly, FORTRAN programmers should define the mask array as an INTEGER*2 item.
Example 14-10 is similar to example 14-9. It shows how to define a
graphics mode mouse cursor using fg_mouseptr. The values stored in the solid and hollow arrays define the screen and cursor masks for the solid and hollow plus-shaped mouse cursors discussed earlier. After making the mouse cursor visible, the program uses the default mouse cursor until a key is pressed. Following this, it changes to the solid cursor. After another keystroke, the program changes to the hollow cursor. When you run example 14-10, compare the differences between the three mouse cursors.
Example 14-10.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
short solid[] = {0xE03F,0xE03F,0xE03F,0x0007, 0x0007,0x0007,0x0007,0x0007, 0x0007,0x0007,0xE03F,0xE03F, 0xE03F,0xFFFF,0xFFFF,0xFFFF, 0x0000,0x0F80,0x0F80,0x0F80, 0x7FF0,0x7FF0,0x7FF0,0x7FF0, 0x7FF0,0x0F80,0x0F80,0x0F80, 0x0000,0x0000,0x0000,0x0000};
short hollow[] = {0xE03F,0xEFBF,0xEFBF,0x0F87, 0x7FF7,0x7FF7,0x7FF7,0x7FF7, 0x7FF7,0x0F87,0xEFBF,0xEFBF, 0xE03F,0xFFFF,0xFFFF,0xFFFF, 0x0000,0x0000,0x0000,0x0000, � Chapter 14: Input Device Support 321
0x0000,0x0000,0x0200,0x0000, 0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000};
void main() { int old_mode; int column, row, last_row;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(fg_automode());
if (fg_mouseini() < 0) { fg_setmode(old_mode); fg_reset(); exit(1); }
fg_setcolor(15); fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
fg_setcolor(12); column = fg_xalpha(fg_getmaxx()/2) - 6; last_row = fg_yalpha(fg_getmaxy()) + 1;
for (row = 0; row < last_row; row++) { fg_locate(row,column); fg_text("example 14-10",13); }
fg_mousevis(1); fg_waitkey(); fg_mouseptr(solid,6,6); fg_waitkey(); fg_mouseptr(hollow,6,6); fg_waitkey();
fg_setmode(old_mode); fg_reset(); }
CGA Considerations
The mouse driver treats the screen and cursor masks differently in the
CGA four-color graphics modes (modes 4 and 5) than in the other graphics modes. In the CGA modes, each pair of mask bits corresponds to one pixel. This means the masks more closely resemble the mode-specific format used by fg_drwimage instead of the mode-independent format of fg_drawmap.
Fastgraph uses a different default mouse cursor for modes 4 and 5. Its
screen and cursor masks, as well as the resulting cursor appearance, are shown in the following diagram. � 322 Fastgraph User's Guide
screen cursor cursor mask mask appearance
0000111111111111 0000000000000000 ** 0000001111111111 0011000000000000 *** 0000000011111111 0011110000000000 **** 0000000000111111 0011111100000000 ***** 0000000000001111 0011111111000000 ****** 0000000000000011 0011111111110000 ******* 0000000000000011 0011111100000000 ******* 0000000000111111 0011111110000000 ***** 0000000000001111 0011000011000000 ****** 0000110000001111 0000000011000000 ** *** 1111111100000011 0000000000110000 *** 1111111100000011 0010000000110000 *** 1111111111000011 0000000000000000 ** 1111111111111111 0000000000000000 1111111111111111 0000000000000000 1111111111111111 0000000000000000
As you can see, the resulting mouse cursor is eight pixels wide instead of 16.
Another important point concerning mouse cursors in modes 4 and 5 is the
chance of pixel bleeding, or the changing of colors within the mouse cursor as it moves horizontally. Bleeding will occur if you use the bit pairs 01 or 10 in either mask to represent a pixel. In the default masks for modes 4 and 5, note that only the binary values 00 and 11 appear as bit pairs. Keep this in mind if you create your own masks in these video modes.
XVGA and SVGA Considerations
In XVGA graphics modes and 256-color SVGA graphics modes (20 to 27), it's
possible to create a multicolored mouse cursor. To do this, use fg_mouse256 instead of fg_mouseptr to define the mouse cursor's shape and appearance. The fg_mouse256 routine uses the same arguments as fg_mouseptr, but the masks are passed in a 512-byte array consisting of a 256-byte screen mask followed by a 256-byte cursor mask. As with fg_mouseptr, each mask is structured as a 16x16 pixel grid, but each pixel is represented by a byte value rather than a single bit.
The mouse driver displays the mouse cursor by logically ANDing video
memory with the screen mask, and then XORing that result with the cursor mask. This normally means the screen mask values are either 0 or 255, while cursor mask values are between 0 and 255. For example, consider again the default graphics mode mouse cursor (the arrow). If we wanted to display the cursor in yellow (color 14) instead of its default white, you would expand the screen mask from 16 to 256 bytes, replacing the zero bits in the "standard" mask with zero bytes and replacing the one bits with the value 255. You would similarly expand the cursor mask, replacing the zero bits with zero bytes and the one bits with the value 14. �
Chapter 14: Input Device Support 323
Joystick Support
The third type of input device supported by Fastgraph is the joystick.
Although joysticks are not as popular as mice, they are often preferable when a user's reactions are critical, such as in an arcade-style game. Fastgraph includes routines for initializing a joystick, reading a joystick's position or button status, and making a joystick behave analogously to the keyboard. These routines are independent of the rest of Fastgraph and thus do not require that you first call fg_setmode.
Joysticks are connected to a system through a game port. The PCjr and
Tandy 1000 systems come equipped with two game ports, and hence support two joysticks. On other systems in the IBM family, you can install a game card with one or two game ports. If the card only has one game port, you can use a splitter cable to fork two joysticks into the port.
Initializing Joysticks
Before you can use any of Fastgraph's joystick support routines with a
specific joystick, you must initialize that joystick. The fg_initjoy routine performs this task. This routine requires a single integer argument that specifies which joystick to initialize, either 1 or 2. If successful, fg_initjoy returns 0 as the function value. If the machine has no game port, or if the requested joystick is not connected to the game port, fg_initjoy returns -1. When you use fg_initjoy, the joystick being initialized must be centered (that is, the stick itself must not be tilted in either direction).
Example 14-11 uses the fg_initjoy routine to try to initialize both
joysticks. For each joystick, the program prints a message stating whether or not the initialization was successful.
Example 14-11.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { fg_initpm(); if (fg_initjoy(1) < 0) printf("Joystick 1 not available.\n"); else printf("Joystick 1 found.\n");
if (fg_initjoy(2) < 0) printf("Joystick 2 not available.\n"); else printf("Joystick 2 found.\n"); } �
324 Fastgraph User's Guide
Reporting Joystick Status
Each joystick can report three items: its horizontal position, its
vertical position, and the button status. Fastgraph includes routines for obtaining each of these quantities.
The fg_getxjoy and fg_getyjoy routines respectively return the horizontal
and vertical position of the indicated joystick. Both routines require a single integer argument, whose value is either 1 or 2, to identify the joystick. The requested position is returned as the function value. Horizontal coordinates increase as the joystick moves to the right, while vertical coordinates increase as the joystick moves downward. If fg_initjoy did not initialize the specified joystick, or if your program hasn't yet called fg_initjoy, both fg_getxjoy and fg_getyjoy will return -1.
Joystick characteristics vary more than those of any other input device.
The values returned by fg_getxjoy and fg_getyjoy depend on the system's processor speed and the brand of joystick used. It often suffices to know the joystick position relative to its previous position, in which case the actual coordinate values do not matter. However, if you must rely on specific coordinate values, your program must perform some type of manual joystick calibration and then scale the coordinates reported by fg_getxjoy and fg_getyjoy as needed.
The other piece of information joysticks provide is the button status.
Most joysticks have two buttons, called the top and bottom buttons. Others have three buttons, but one of them duplicates the functionality of another (for example, a joystick might have one bottom button on its left side and another on its right side). The Fastgraph routine fg_button returns the joystick button status as its function value. Like fg_getxjoy and fg_getyjoy, fg_button requires a single argument that specifies the joystick number. The meaning of the return value is shown here:
value meaning
0 neither button pressed 1 top button pressed 2 bottom button pressed 3 top and bottom buttons pressed
You don't need to call fg_initjoy before using fg_button. If the
specified joystick is not present, fg_button will return a value of 0.
Example 14-12 uses fg_getxjoy, fg_getyjoy, and fg_button to poll both
joysticks at half-second intervals. It then displays the joystick number (1 or 2), horizontal position, vertical position, and button status for each joystick. As the program runs, you can move the joysticks and watch how the movements affect the displayed coordinate values. The program continues doing this until you press Ctrl/C or Ctrl/Break to stop it.
Example 14-12.
#include <fastgraf.h> #include <stdio.h> void main(void); � Chapter 14: Input Device Support 325
void main() { int b, x, y;
fg_initpm(); fg_initjoy(1); fg_initjoy(2);
while (1) { x = fg_getxjoy(1); y = fg_getyjoy(1); b = fg_button(1); printf("1: %3d %3d %1d\n",x,y,b); x = fg_getxjoy(2); y = fg_getyjoy(2); b = fg_button(2); printf("2: %3d %3d %1d\n\n",x,y,b); fg_waitfor(9); } }
There are two ways of effectively monitoring joystick button status. One
is to call fg_button at many places in your program and then take the necessary action depending on the button status. However, the preferable method is to extend the BIOS time-of-day interrupt to check the button status at each clock tick (there are 18.2 clock ticks per second), set a flag if a button is pressed, and then check the flag as needed in your program. Information on changing the BIOS time-of-day interrupt appears in Appendix C.
Keyboard Emulation
Although we can use fg_getxjoy and fg_getyjoy to monitor relative
joystick movements, it is usually easier to do this with another Fastgraph routine, fg_intjoy. This routine is similar to fg_intkey in that it returns two values equivalent to the standard or extended keyboard codes for analogous keystrokes.
The fg_intjoy routine needs three arguments. The first argument specifies
the joystick number, either 1 or 2. The second and third arguments, both one- byte quantities passed by reference, receive the standard and extended keyboard codes analogous to the joystick movement and button status. The second argument receives a value of 13 (the standard keyboard code for the Enter key) if any joystick button is pressed; it receives a value of 0 if not. The third argument receives a value corresponding to the extended keyboard code for one of the directional keys on the numeric keypad, as summarized in the following table.
joystick position corresponding key extended key code
up and left Home 71 up up arrow 72 up and right PgUp 73 left left arrow 75 �
326 Fastgraph User's Guide
centered (no action) 0 right right arrow 77 down and left End 79 down down arrow 80 down and right PgDn 81
The fg_intjoy routine will set both key code arguments to zero if the specified joystick has not yet been initialized.
Example 14-13 is similar to example 14-11, but it uses fg_intjoy in place
of fg_getxjoy and fg_getyjoy to report relative joystick position. This program does not report the joystick button status as example 14-11 does, but you could readily add this feature to it.
Example 14-13.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { char key, aux;
fg_initpm(); fg_initjoy(1); fg_initjoy(2);
while (1) { fg_intjoy(1,&key,&aux); printf("1: %2d %2d\n",key,aux); fg_intjoy(2,&key,&aux); printf("2: %2d %2d\n\n",key,aux); fg_waitfor(9); } }
Special Joystick Considerations
If you develop a program that supports only one joystick, you should use
joystick 1. The reasons for this are twofold. First, it will make your program consistent with most other products that support joysticks. Second, many Tandy 1000 series machines cannot determine if joystick 2 is present when neither joystick is connected. This means if you use joystick 2 instead of joystick 1 in a single joystick program, you won't be able to tell if a joystick is available when running on a Tandy 1000.
Summary of Input Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual. �
Chapter 14: Input Device Support 327
FG_BUTTON returns information about the state of either joystick's
buttons.
FG_CAPSLOCK determines the state of the CapsLock key.
FG_GETKEY waits for a keystroke (or reads the next entry from the BIOS
keyboard buffer). It returns the keystroke's standard or extended keyboard code.
FG_GETXJOY and FG_GETYJOY return the horizontal and vertical coordinate
position of the specified joystick. The actual coordinates depend on the processor speed and brand of joystick used.
FG_INITJOY initializes joystick 1 or 2 and must be called before using
fg_getxjoy, fg_getyjoy, or fg_intjoy. It returns a status code indicating whether or not the initialization was successful.
FG_INTJOY returns the standard and extended keyboard codes analogous to
the current position and button status of the specified joystick.
FG_INTKEY reads the next entry from the BIOS keyboard buffer and returns
the keystroke's standard or extended keyboard code. It is similar to fg_getkey, but it does not wait for a keystroke if the keyboard buffer is empty.
FG_KBINIT enables or disables Fastgraph's low-level keyboard handler. If
the keyboard handler is already in the requested state, nothing happens.
FG_KBLAST returns the scan code for the most recent keypress processed by
Fastgraph's low-level keyboard handler.
FG_KBRESET resets the state of Fastgraph's low-level keyboard handler to
what it was after being enabled with fg_kbinit.
FG_KBTEST determines if the key having the specified scan code is now
pressed or released. The low-level keyboard handler must be enabled for this routine to work properly.
FG_MOUSE256 defines the shape and appearance of a multicolored mouse
cursor in XVGA and 256-color SVGA graphics modes.
FG_MOUSEBUT returns information about mouse button press or release
counts, as well as the mouse cursor position at the time of the last button press or release.
FG_MOUSECUR defines the appearance of the mouse cursor in text video
modes.
FG_MOUSEFIN unhooks Fastgraph's XVGA or SVGA mouse handler from the mouse
driver. This routine should be used just before reverting to text mode in programs that have called fg_mouseini in XVGA or SVGA graphics modes. It has no effect in other video modes.
FG_MOUSEINI initializes the mouse and must be called before any of
Fastgraph's other mouse support routines. It returns an error status if the � 328 Fastgraph User's Guide
mouse driver has not been loaded, if the mouse is not connected, or if a
virtual buffer is active.
FG_MOUSELIM defines the rectangular area in which the mouse cursor may
move.
FG_MOUSEMOV moves the mouse cursor to the specified character cell (in
text modes) or screen space position (in graphics modes).
FG_MOUSEPOS returns the current mouse position and button status.
FG_MOUSEPTR defines the shape and appearance of the mouse cursor in
graphics video modes.
FG_MOUSESPD defines the number of mickey units per eight pixels of cursor
movement. This effectively controls the speed at which the mouse cursor moves relative to the movement of the mouse itself.
FG_MOUSEVIS makes the mouse cursor visible or invisible.
FG_NUMLOCK determines the state of the NumLock key.
FG_SCRLOCK determines the state of the ScrollLock key (which is not
present on some keyboards).
FG_SETCAPS controls the state of the CapsLock key.
FG_SETNUM controls the state of the NumLock key.
FG_WAITKEY flushes the BIOS keyboard buffer (that is, removes any type-
ahead characters) and then waits for another keystroke.
Chapter 15
Sound Effects � 330 Fastgraph User's Guide
Overview
In the realm of the IBM PC and PS/2 family of systems, a sound is defined
by its frequency, duration, and volume. The frequency of a sound is measured in units called Hertz. While the PC and PS/2 can produce sounds ranging from 18 to more than one million Hertz, the average human can hear sounds between 20 and about 20,000 Hertz. The length of a sound, called its duration, is expressed in clock ticks; there are either 18.2 of 72.8 clock ticks per second, depending on the method used to produce the sound. Finally, the volume determines the loudness of the sound. As we'll see in this chapter, we can control a sound's volume only on the PCjr and Tandy 1000 systems.
Fastgraph offers several different methods for producing sound effects.
These include single tones, a series of tones expressed numerically, or a series of tones expressed as musical notes. The sound effects may be discrete, continuous, or performed at the same time as other activity. The sound-related routines are independent of the other parts of Fastgraph and do not require any initialization routines be called.
Sound Sources
All members of the PC and PS/2 families can produce sounds using the
8253-5 programmable timer chip and the internal speaker. This method is limited to producing single sounds of given frequencies and durations, although we can combine these sounds to create interesting audio effects or play music. When we use this technique, we have no control over the sound volume. In fact, sound volumes often vary slightly on different systems because the physical properties of the speaker and its housing are not always the same.
The PCjr and Tandy 1000 systems have an additional, more powerful chip
for producing sounds. This is the Texas Instruments SN76496A sound chip, called the TI sound chip for short. The TI sound chip has three independent voice channels for producing pure tones, and a fourth channel for generating periodic or white noise. Each voice channel has a separate volume control that allows us to control the loudness of the sound it emits.
Synchronous Sound
A sound effect is said to be synchronous if it is produced while no other
activity is being performed. In other words, a program makes a synchronous sound by starting the sound, waiting for a specified duration, and then stopping the sound. The program must wait for the sound to complete before doing anything else. As long as the duration is relatively short, the fact that the sound is synchronous has little or no effect on the program's execution speed. Fastgraph includes routines for producing synchronous sound using either the 8253-5 programmable timer or the TI sound chip.
The fg_sound routine uses the programmable timer to produce a sound of a
given frequency and duration. The frequency, defined by the first argument, is expressed in Hertz and must be an integer value between 18 and 32,767. The second argument defines the duration and is expressed in clock ticks; there �
Chapter 15: Sound Effects 331
are 18.2 clock ticks per second. If the duration is zero or negative, the
sound will continue until it is stopped with fg_quiet.
Example 15-1 uses fg_sound to create different sound effects, pausing for
one second between each. It first produces three distinct sounds of 20, 100, and 1,000 Hertz. Each of these sounds lasts for approximately 1/6 of a second (three clock ticks). The program then makes a warbling noise by quickly alternating sounds of similar frequencies. Finally, the program creates a sliding tone of increasing frequencies between 100 and 500 Hertz. Each tone in this sequence lasts for two clock ticks, so it takes about 4.5 seconds to play the entire sequence. In all cases, example 15-1 displays an identifying message just before each sound.
Example 15-1.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int freq;
fg_initpm(); printf("20 Hz tone...\n"); fg_sound(20,3); fg_waitfor(18);
printf("100 Hz tone...\n"); fg_sound(100,3); fg_waitfor(18);
printf("1000 Hz tone...\n"); fg_sound(1000,3); fg_waitfor(18);
printf("warble...\n"); fg_sound(400,1); fg_sound(410,1); fg_sound(400,1); fg_sound(410,1); fg_waitfor(18);
printf("sliding tone from 100 to 500 Hz...\n"); for (freq = 100; freq <= 500; freq+=10) fg_sound(freq,2); }
The fg_voice routine is analogous to fg_sound, but it uses the TI sound
chip rather than the programmable timer to create sound. For this reason, fg_voice can only be used on the PCjr or Tandy 1000 systems. The TI sound chip allows us to control the volume of a sound, and it also offers four distinct voice channels. Thus, fg_voice requires two additional arguments besides frequency and duration to define the voice channel and sound volume. � 332 Fastgraph User's Guide
The first argument to fg_voice defines the voice channel, as shown here:
value meaning
1 voice channel #1 2 voice channel #2 3 voice channel #3 4 voice channel #4, periodic noise 5 voice channel #4, white noise
If we use voice channels 1, 2, or 3, the second argument defines the sound frequency in Hertz, between 18 and 32,767. If we use voice channel 4, however, the second argument instead is a value that represents a specific frequency, as shown in this table:
value frequency
0 512 Hertz 1 1024 Hertz 2 2048 Hertz
The third argument defines the sound volume. It must be between 0 and 15, where 0 is silent and 15 is loudest. The fourth argument defines the sound duration in clock ticks. As with fg_sound, there are 18.2 clock ticks per second, and if the duration is zero or negative, the sound will continue until stopped with fg_quiet.
Example 15-2 uses fg_voice to create different sound effects using the TI
sound chip. As in example 15-1, there is a pause of one second between each. The program first calls fg_testmode to be sure it is running on a PCjr or Tandy 1000 system (video mode 9 is only available on these systems). If so, the program uses voice channel #4 to produce a 2,048 Hertz periodic noise, followed by white noise of the same frequency. Both sounds are emitted at the maximum volume level (15) and last for about 1/6 of a second each (three clock ticks). After these noises, example 15-2 produces a 500 Hertz tone of increasing volume. In all cases, the program displays an identifying message just before each sound.
Example 15-2.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { int volume;
fg_initpm(); if (fg_testmode(9,0) == 0) { printf("This program requires a PCjr or "); printf("a Tandy 1000 system.\n"); exit(1); } � Chapter 15: Sound Effects 333
printf("2048 Hz periodic noise...\n"); fg_voice(4,2,15,3); fg_waitfor(18);
printf("2048 Hz white noise...\n"); fg_voice(5,2,15,3); fg_waitfor(18);
printf("500 Hz tone of increasing volume...\n"); for (volume = 1; volume <= 15; volume++) { fg_voice(1,500,volume,0); fg_waitfor(4); }
fg_quiet(); }
Note how example 15-2 uses a duration of zero (continuous sound) and
fg_waitfor to specify the duration for each volume level the 500 Hertz tone sequence. This causes the transition between changes in volume to blend better with each other. The fg_quiet routine, which stops continuous sound started with fg_sound or fg_voice, ends the sound after the final volume level.
Both fg_sound and fg_voice produce a single sound. We've seen how to
combine sounds to produce sound effects, but still the individual sounds are defined numerically -- that is, by a certain frequency and duration. It is often easier to create sounds from musical notes, and for this reason Fastgraph includes a routine fg_music that produces such sounds. The fg_music routine uses the programmable timer to produce synchronous sound; it does not support the TI sound chip.
The fg_music routine has a single argument called the music string,
passed by reference as a byte array or character string. The music string is simply a variable-length sequence of music commands, followed by a dollar-sign ($) terminator. Music commands are summarized in the following table.
command meaning
A thru G Play the specified note in the current octave.
- May be appended to a note character (A through G) to make that note
sharp.
. May be appended to a note character (A through G) or a sharp (#) to
extend that note by half its normal length. Multiple dots may be used, and each will again extend the note by half as much as the previous extension.
Ln Set the length of subsequent notes and pauses. The value of n is an
integer between 1 and 64, where 1 indicates a whole note, 2 a half note, 4 a quarter note, and so forth. If no L command is present, L4 is assumed.
On Set the octave for subsequent notes. The value of n may be an
integer between 0 and 6 to set a specific octave. It also can be a �
334 Fastgraph User's Guide
plus (+) or minus (-) character to increment or decrement the current octave number. Octave 4 contains middle C, and if no O command is present, O4 is assumed.
P Pause (rest) for the duration specified by the most recent L
command.
Sn Set the amount of silence between notes. The value of n is an
integer between 0 and 2. If n is 0, each note plays for the full period set by the L command (music legato). If n is 1, each note plays for 7/8 the period set by the L command (music normal). If n is 2, each note plays for 3/4 the period set by the L command (music staccato). If no S command is present, S1 is assumed.
Tn Set the tempo of the music (the number of quarter notes per minute).
The value of n is an integer between 32 and 255. If no T command is present, T120 is assumed.
The fg_music routine ignores any other characters in the music string. It also ignores command values outside the allowable range, such as T20 or O8.
Example 15-3 illustrates some uses of fg_music. The program plays the
first few bars of "Mary Had a Little Lamb", followed by the musical scale (including sharps) in two octaves, and finally the introduction to Beethoven's Fifth Symphony. There is a pause of one second between each piece of music, and the program displays the titles before playing the music. Blank characters appear in the music strings to help make them more readable.
Example 15-3.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { { fg_initpm(); printf("Mary Had a Little Lamb...\n"); fg_music("T150 L8 EDCDEEE P DDD P EGG P EDCDEEE L16 P L8 EDDEDC$"); fg_waitfor(18);
printf("up the scale in two octaves...\n"); fg_music("L16 CC#DD#EFF#GG#AA#B O+ CC#DD#EFF#GG#AA#B$"); fg_waitfor(18);
printf("Beethoven's Fifth Symphony...\n"); fg_music("T180 O2 L2 P L8 P GGG L2 D# L24 P L8 P FFF L2 D$"); } � Chapter 15: Sound Effects 335
Asynchronous Sound
Sounds made concurrently with other activity in a program are said to be
asynchronous. Fastgraph's routines that produce asynchronous sound just start the sound and then immediately return control to the calling program. The sounds will automatically stop when the end of the sequence is reached, and you also can suspend or stop it on demand before that time. None of Fastgraph's asynchronous sound routines have any effect if there is already asynchronous sound in progress. In addition, the asynchronous sound routines temporarily disable the synchronous sound routines (fg_sound, fg_voice, and fg_music) while asynchronous sound is in progress.
To expand the range of sound effects and to play fast-tempo music,
Fastgraph temporarily quadruples the clock tick interrupt rate from 18.2 to 72.8 ticks per second while producing asynchronous sound. Because many disk controllers rely on the 18.2 tick per second clock rate to synchronize disk accesses, your programs should not perform any disk operations when asynchronous sound is in progress.
The fg_sounds routine is the asynchronous version of fg_sound. It uses
the programmable timer to play a sequence of tones simultaneous to other operations. This routine expects as its first argument a variable-length integer array, passed by reference, containing pairs of frequency and duration values. As with fg_sound, each frequency is expressed in Hertz and must be between 18 and 32,767. The durations are also measured in clock ticks, but because the interrupt rate is quadrupled, there are 72.8 instead of 18.2 ticks per second.
The format of the frequency and duration array passed to fg_sounds is
shown here:
[0] frequency of sound 1
[1] duration of sound 1
[2] frequency of sound 2
[3] duration of sound 2
. . .
[2n-2] frequency of sound n
[2n-1] duration of sound n
[2n] terminator (0)
Note that a null character (that is, a zero byte) terminates the array. The
second argument passed to fg_sounds is an integer value indicating the number
of times to cycle through the frequency and duration array. If this value is
negative, the sounds will continue until stopped with fg_hush or fg_hushnext. �
336 Fastgraph User's Guide
Example 15-4 uses fg_sounds to play the 100 to 500 Hertz sliding tone
sequence of example 15-1. To prove the sounds are being made concurrently with other operations, messages are displayed while the sequence is playing. This is controlled by the Fastgraph routine fg_playing, which returns a value of 1 if asynchronous sounds are in progress, and 0 if not. Note how the duration must be specified as 8 clock ticks (instead of 2 as in example 15-1) to compensate for the quadrupled clock tick interrupt rate.
Example 15-4.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int i; int freq; int sound_array[83];
i = 0; for (freq = 100; freq <= 500; freq+=10) { sound_array[i++] = freq; sound_array[i++] = 8; } sound_array[i] = 0;
fg_initpm(); fg_sounds(sound_array,1);
while(fg_playing()) printf("Still playing...\n"); }
Just as fg_sounds is analogous to fg_sound, there is a Fastgraph routine
fg_voices that is similar to fg_voice. That is, fg_voices uses the TI sound chip to play an asynchronous sequence of tones. Its arguments are the same as those of fg_sounds, but the structure of the sound array is different. Its structure is:
[0] channel # of sound 1
[1] frequency of sound 1
[2] volume of sound 1
[3] duration of sound 1
. . .
[4n-4] channel # of sound n � Chapter 15: Sound Effects 337
[4n-3] frequency of sound n
[4n-2] volume of sound n
[4n-1] duration of sound n
[4n] terminator (0)
The channel numbers, frequencies, volumes, and durations must be in the same
ranges as discussed in the description of fg_voice, except the durations are
quadrupled because of the accelerated clock tick interrupt rate. Again, note
that a null character (that is, a zero byte) terminates the array.
Example 15-5 uses fg_voices to play the 500 Hertz tone sequence of
increasing volume introduced in example 15-2. As in example 15-4, the program displays messages while the tone sequence is playing to demonstrate the sounds are being made concurrently with other operations. Note how the duration is now 16 clock ticks (instead of 4 as in example 15-2) because of the quadrupled clock tick interrupt rate.
Example 15-5.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int voice_array[61]; int i; int volume;
fg_initpm(); if (fg_testmode(9,0) == 0) { printf("This program requires a PCjr or "); printf("a Tandy 1000 system.\n"); exit(1); }
i = 0; for (volume = 1; volume <= 15; volume++) { voice_array[i++] = 1; /* use channel 1 */ voice_array[i++] = 500; /* 500 Hz frequency */ voice_array[i++] = volume; /* variable volume */ voice_array[i++] = 16; /* duration */ } voice_array[i] = 0;
fg_voices(voice_array,1);
while(fg_playing()) printf("Still playing...\n"); } �
338 Fastgraph User's Guide
There is also an asynchronous version of fg_music. It is called
fg_musicb, and it uses the same format music string as fg_music does. However, fg_musicb has a second argument that specifies the number of times to cycle through the music string. If this value is negative, the music will play repetitively until you stop it with fg_hush or fg_hushnext.
Example 15-6 plays the same three pieces of music as example 15-3, but it
does so concurrently with other operations. As the music plays, the program continuously displays the title of each piece. Note how we can take advantage of the repetition in the music string for the "up the scale" sequence by playing the sequence twice.
Example 15-6.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { fg_initpm(); fg_musicb("T150 L8 EDCDEEE P DDD P EGG P EDCDEEE L16 P L8 EDDEDC$",1); while (fg_playing()) printf("Mary Had a Little Lamb...\n"); fg_waitfor(18);
fg_musicb("L16 CC#DD#EFF#GG#AA#B O+$",2); while (fg_playing()) printf("up the scale in two octaves...\n"); fg_waitfor(18);
fg_musicb("T180 O2 L2 P L8 P GGG L2 D# L24 P L8 P FFF L2 D$",1); while (fg_playing()) printf("Beethoven's Fifth Symphony...\n"); }
The next example demonstrates the effects of the Fastgraph routines
fg_hush and fg_hushnext, which stop sounds started with fg_sounds, fg_voices, or fg_musicb. The fg_hush routine immediately stops asynchronous sound, while fg_hushnext does so when the current cycle finishes. Neither routine has any arguments, and neither routine has any effect if no asynchronous sound is in progress. Furthermore, note that fg_hushnext has no effect unless the asynchronous sound is continuous.
Example 15-7 runs in any text or graphics video mode. It displays
rectangles in up to 16 colors while playing continuous asynchronous music. The program periodically checks for keystrokes with fg_intkey, and it continues to play the music while there is no keyboard activity. If you press the Escape key, the program uses fg_hush to stop the music immediately; this causes an exit from the while loop. If you press any other key, the program uses fg_hushnext to stop the music as soon as the current repetition finishes. Once it does, the program exits the while loop because fg_playing will return a value of zero. �
Chapter 15: Sound Effects 339
Example 15-7.
#include <fastgraf.h> void main(void);
#define ESC 27
void main() { int color; int old_mode; unsigned char key, aux;
fg_initpm(); old_mode = fg_getmode(); fg_setmode(fg_automode()); color = 0;
fg_musicb("O4 L16 CC#DD#EFF#GG#AA#B O+ CC#DD#EFF#GG#AA#B$",-1);
while (fg_playing()) { color = (color + 1) & 15; fg_setcolor(color); fg_rect(0,fg_getmaxx(),0,fg_getmaxy());
fg_waitfor(4); fg_intkey(&key,&aux); if (key == ESC) fg_hush(); else if (key+aux != 0) fg_hushnext(); }
fg_setmode(old_mode); fg_reset(); }
Example 15-7 also demonstrates an important side-effect of fg_musicb when
playing continuous music. Any length, octave, silence, or tempo values changed within the string are not reset to their original values at the beginning of each repetition. If we did not include the O4 command at the beginning of the string, the later O+ command would cause the music to play in octaves 4 and 5 during the first repetition, 5 and 6 during the second repetition, and octave 6 for all subsequent repetitions (because you cannot increase the octave number above 6).
The final two routines relating to asynchronous sound are fg_resume and
fg_suspend. The fg_suspend routine suspends music previously started by fg_musicb, while fg_resume restarts the music from the point where it was suspended. Example 15-8 plays the first few bars of "Mary Had a Little Lamb". If you press any key while the song is playing, it stops. Then, after another keystroke, the music resumes and continues until finished. � 340 Fastgraph User's Guide
Example 15-8.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { fg_initpm(); fg_musicb("T150 L8 EDCDEEE P DDD P EGG P EDCDEEE L16 P L8 EDDEDC$",1); fg_waitkey();
fg_suspend(); printf("Music suspended. Press any key to resume.\n"); fg_waitkey();
fg_resume(); printf("Music resumed.\n"); while (fg_playing()); printf("Music finished.\n"); }
The fg_suspend routine has no effect if there is no asynchronous music in
progress. Similarly, fg_resume has no effect if there is no suspended music.
If you call fg_suspend and then need to cancel the music or exit to DOS
instead of restarting the music, call fg_hush instead of fg_resume.
Summary of Sound Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_HUSH immediately stops asynchronous sound started with fg_sounds,
fg_voices, or fg_musicb.
FG_HUSHNEXT is similar to fg_hush, but it does not stop the asynchronous
sound until the current repetition finishes.
FG_MUSIC uses the programmable timer to play a sequence of musical tones.
FG_MUSICB is the asynchronous version of fg_music. It uses the
programmable timer to play a sequence of musical tones, concurrent with other activity.
FG_PLAYING determines whether or not there is any asynchronous sound in
progress.
FG_QUIET stops continuous synchronous sound started with fg_sound or
fg_voice.
FG_RESUME restarts asynchronous music previously suspended by fg_suspend. � Chapter 15: Sound Effects 341
FG_SOUND produces a tone of a specified frequency and duration using the
programmable timer.
FG_SOUNDS is the asynchronous version of fg_sound. It can play a series
of tones of specified frequencies and durations, concurrent with other activity.
FG_SUSPEND suspends asynchronous music previously started by fg_musicb.
FG_VOICE produces a tone of a specified frequency, duration, and volume
using one of the TI sound chip's four voice channels.
FG_VOICES is the asynchronous version of fg_voice. It can play a series
of tones of specified frequencies, durations, and volumes, concurrent with other activity. � 342 Fastgraph User's Guide
Chapter 16
Program Timing � 344 Fastgraph User's Guide
Overview
It is occasionally necessary to delay a program's execution for a brief
period, or to determine how long it takes to execute specific sections of a program. Fastgraph includes routines to accomplish these tasks. Some of these routines are said to be real-time, which means they are independent of a system's processor speed, while the speed of others is processor-specific. This chapter describes both classes of timing routines, all of which are independent of the other parts of Fastgraph.
Real-Time Routines
Real-time operations center around the BIOS time-of-day clock, which is
nothing more than a counter that the system automatically increments 18.2 times per second. This number is often called the clock tick interrupt rate because an interrupt routine performs the incrementing. In addition, each increment is usually called a clock tick.
The Fastgraph routine fg_waitfor delays a program's execution by the
number of clock ticks specified as its argument. Because fg_waitfor uses clock ticks, the actual length of the delay is the same, regardless of the system's processor speed. Even when Fastgraph's asynchronous sound routines quadruple the clock tick interrupt rate, Fastgraph compensates for this internally so fg_waitfor always works as though the actual rate were still 18.2 times per second.
Example 16-1 displays a message every five seconds that states how long
the program has been running. The fg_waitfor routine produces the five-second delay by pausing 91 (18.2 times 5) clock ticks before the program displays each message. The program returns to DOS when you press any key.
Example 16-1.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { unsigned int seconds; unsigned char key, aux;
fg_initpm(); seconds = 0; do { fg_waitfor(91); seconds += 5; printf("%u seconds have elapsed.\n",seconds); fg_intkey(&key,&aux); } while (key+aux == 0); } � Chapter 16: Program Timing 345
Another common application of fg_waitfor is to slow down a loop that uses
fg_intkey to check for keystrokes. In loops that do little else, we may call fg_intkey too rapidly without this delay, and it is then possible that the BIOS may not be able to store characters in its keyboard buffer fast enough. A small delay, even one clock tick, often helps such "tight" loops.
The fg_getclock routine provides an efficient way to measure time,
especially differences in time. This routine has no arguments and returns a 32-bit unsigned integer (as its function value) representing the number of clock ticks since midnight. Example 16-2 demonstrates fg_getclock. In response to any keystroke (except Escape, which returns control to DOS), the program displays the number of clock ticks since midnight, and the number of ticks since the program started.
Example 16-2.
#include <fastgraf.h> #include <stdio.h> void main(void);
#define ESC 27
void main() { unsigned long start, ticks; unsigned char key, aux;
fg_initpm(); start = fg_getclock(); do { ticks = fg_getclock(); printf("%lu ticks since midnight.\n",ticks); printf("%lu ticks since start of program.\n\n",ticks-start); fg_getkey(&key,&aux); } while (key != ESC); }
Routines Dependent on the System Speed
The fg_waitfor routine described in the previous section is independent
of the system's processor speed. This means the actual length of its delay is the same on any system. Another routine, fg_stall, is similar to fg_waitfor, but its delay is proportional to the processor speed. Like fg_waitfor, fg_stall has a single integer argument that specifies the length of the delay. However, instead of being expressed in clock ticks, fg_stall measures the delay in delay units. The fg_stall routine treats the length as an unsigned quantity, so in 16-bit modes the maximum number of delay units we can specify is 65,535. The following table lists the approximate number of delay units per clock tick on three typical systems. � 346 Fastgraph User's Guide
system delay units type per clock tick
Tandy 1000 HX 280 25 MHz 80386 3,400 40 MHz 80386 7,100
Fastgraph includes a routine that determines the number of delay units
per clock tick for the processor being used. This is the fg_measure routine, which has no arguments and returns the number of delay units per clock tick as its function value. Once we determine this value, we can use fg_stall to delay a program's execution in real time. This provides a much more refined delay than the clock tick unit used by fg_waitfor.
Example 16-3 is functionally identical to example 16-1, but it uses
fg_stall instead of fg_waitfor to delay the program execution. The program first calls fg_measure to determine number of delay units equivalent to one clock tick. It then passes this value to fg_stall, called 91 times inside the for loop to create the five-second delay (because 91 clock ticks equals five seconds). The program returns to DOS when you press any key.
Example 16-3.
#include <fastgraf.h> #include <stdio.h> void main(void);
void main() { int i; int units_per_tick; unsigned int seconds; unsigned char key, aux;
fg_initpm(); seconds = 0; printf("Benchmarking system speed...\n"); units_per_tick = fg_measure(); printf("Benchmark completed.\n\n");
do { for (i = 0; i < 91; i++) fg_stall(units_per_tick); seconds += 5; printf("%u seconds have elapsed.\n",seconds); fg_intkey(&key,&aux); } while (key+aux == 0); }
One final point: fg_measure takes a few seconds to benchmark the system
speed accurately. For this reason, you should only call fg_measure once (typically at the beginning of the program) and use its return value instead of calling fg_measure throughout the program. �
Chapter 16: Program Timing 347
Summary of Timing Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_GETCLOCK returns the number of clock ticks since midnight as its
function value. This quantity is a 32-bit unsigned integer.
FG_MEASURE returns the approximate number of delay units per clock tick
as its function value. This quantity is proportional to the system's processor speed.
FG_STALL delays a program's execution for a given number of processor-
specific delay units.
FG_WAITFOR delays a program's execution for a given number of clock
ticks. There are 18.2 clock ticks per second, regardless of the system's processor speed. � 348 Fastgraph User's Guide
Chapter 17
Miscellaneous Routines � 350 Fastgraph User's Guide
Overview
There are a few remaining Fastgraph routines that really don't fit into
any of the categories discussed so far. For this reason, we'll describe them separately in this chapter.
Determining Available Memory
The fg_memavail routine returns the amount of free conventional memory
(in bytes) available to DOS. It returns the amount of memory as its function value, which is a 32-bit unsigned integer, and it has no arguments.
Example 17-1 uses fg_memavail to show the effects of creating and
releasing virtual pages. When run in a video mode in which video pages 1 and 2 are physical pages, the amount of free memory remains the same because these pages use memory that is resident on the video adapter. However, in modes where pages 1 and 2 are virtual pages, the amount of free memory decreases after each call to fg_allocate and returns to its original value after the calls to fg_freepage. Note how the program requests and validates the video mode.
Example 17-1.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
void main() { long original, mem0, mem1, mem2; int mode, old_mode;
printf("Which video mode? "); scanf("%d",&mode);
fg_initpm(); if (fg_testmode(mode,0) == 0) { printf("Your system does not support that video mode.\n"); exit(1); } if (fg_testmode(mode,3) == 0) { printf("Your system does not have enough memory.\n"); exit(1); }
original = fg_memavail(); old_mode = fg_getmode(); fg_setmode(mode); mem0 = fg_memavail(); fg_allocate(1); mem1 = fg_memavail(); fg_allocate(2); mem2 = fg_memavail(); � Chapter 17: Miscellaneous Routines 351
fg_freepage(1); fg_freepage(2); fg_setmode(old_mode); fg_reset();
printf("originally = %ld\n",original); printf("after setmode = %ld\n",mem0); printf("after 1st page = %ld\n",mem1); printf("after 2nd page = %ld\n",mem2); printf("at end = %ld\n",memavail()); }
Choosing the Video Memory Update Function
In Chapter 12, we saw how to use the fg_setfunc routine to perform XOR
animation in native EGA and VGA graphics modes (modes 13 to 18). In these video modes, fg_setfunc controls the logical operation applied when the contents of video memory change. The specific operation is defined by its argument, as shown here:
value of logical argument operation
0 replacement 1 and 2 or 3 exclusive or
If a program does not call fg_setfunc, replacement mode is always used. That is, information written to video memory replaces whatever was there before. The fg_setfunc routine applies only to video memory, even if a virtual buffer is active, and is meaningful only in 16-color EGA, VGA, and SVGA graphics modes.
Example 17-2 demonstrates the fg_setfunc routine. The program is similar
to example 6-11, which displays 200 random rectangles on the screen. However, example 17-2 displays the rectangles in XOR mode, which makes the rectangle intersections appear in different colors.
Example 17-2.
#include <fastgraf.h> #include <stdio.h> #include <stdlib.h> void main(void);
#define RECTANGLES 200 #define SWAP(a,b,temp) { temp = a; a = b; b = temp; }
void main() { int i; int minx, maxx, miny, maxy; �
352 Fastgraph User's Guide
int old_mode; int temp; int xres, yres;
fg_initpm(); if (fg_egacheck() == 0) { printf("This program requires EGA or VGA.\n"); exit(1); }
old_mode = fg_getmode(); fg_setmode(fg_automode()); fg_setfunc(3);
xres = fg_getmaxx() + 1; yres = fg_getmaxy() + 1;
for (i = 0; i < RECTANGLES; i++) { minx = rand() % xres; maxx = rand() % xres; miny = rand() % yres; maxy = rand() % yres; if (minx > maxx) SWAP(minx,maxx,temp); if (miny > maxy) SWAP(miny,maxy,temp); fg_setcolor(rand()%16); fg_rect(minx,maxx,miny,maxy); }
fg_setmode(old_mode); fg_reset(); }
Controlling Vertical Retrace Synchronization
The vertical retrace is the brief period when the monitor's electron beam
travels from the bottom of the screen back to the upper left corner to begin a new display refresh cycle. Depending on the monitor, the vertical retrace typically occurs between 50 and 60 times per second.
Certain graphics operations must be performed during a vertical retrace
interval to avoid potential screen flickering or snow. These include page flipping, panning, and reading or writing a block of video DAC registers or palettes. By default, Fastgraph's routines that perform these operations automatically provide the necessary vertical retrace synchronization. In most applications, these vertical retrace controls are completely sufficient. There are times, however, when you may wish to disable Fastgraph's vertical retrace checking and perform the vertical retrace synchronization at the application level.
This is the purpose of Fastgraph's fg_waitvr routine. To disable all
internal vertical retrace synchronization within Fastgraph, call fg_waitvr with a zero argument. If you want to re-enable it, pass a non-zero value to �
Chapter 17: Miscellaneous Routines 353
fg_waitvr (note that this is the default state). The Fastgraph routines
relevant to the vertical retrace are fg_getdacs, fg_palettes, fg_pan,
fg_setdacs, and fg_setvpage; and in 256-color modes, fg_getrgb, fg_palette,
and fg_setrgb. The vertical retrace is also applicable to Fastgraph's routines
for displaying or creating PCX, GIF, or flic files in 16-color and 256-color
graphics modes when the palette or DAC values are manipulated.
As an example of why you might want to do disable Fastgraph's vertical
retrace controls, consider page flipping. After fg_setvpage defines the display start address for the new visual page, it waits for a vertical retrace interval so the new starting address can take effect. If fg_setvpage didn't do this, graphics displayed before the next vertical retrace would sometimes appear on the screen before the old visual page is completely removed. Suppose, though, that immediately after the page flip you did some calculations or other work that didn't affect the video display. If you disable Fastgraph's vertical retrace synchronization, you might achieve a faster frame rate because you can perform the post-page-flip calculations while the system is normally waiting for the vertical retrace. Depending on the extent of these calculations, you may find that it's not even necessary to wait for the vertical retrace following a page flip.
External SVGA Bank Switching
One of the most important features that occurs during Fastgraph's SVGA
kernel initialization is the setup of chipset-specific bank switching functions. When a bank switch is needed, the current Fastgraph routine performs the bank switch through pre-defined entry points in the SVGA kernel. This removes the low-level details of knowing when and how to bank switch from an application's high-level code.
If you have an application that performs some or all of its SVGA graphics
outside of Fastgraph, you can still use Fastgraph's extensive SVGA chipset autodetection and bank switching functions. After successfully initializing the SVGA kernel with fg_svgainit and establishing an SVGA graphics video mode, the read and write bank numbers will be set to zero. When you need to change SVGA banks, call the fg_setbanks routine; its two arguments specify the new read and write bank numbers. Note that fg_setbanks doesn't tell you when to perform a bank switch, it merely handles the details of how to do it. A complementary routine, fg_getbanks, returns the SVGA kernel's current read and write bank numbers.
Saving and Restoring the Video State
If you call Fastgraph routines from an interrupt service routine (ISR) in
a VGA, XVGA, or SVGA graphics mode, the ISR is responsible for saving and restoring the VGA state. This is required because an interrupt might occur while performing other graphics operations, and the Fastgraph routines called from the ISR will almost certainly change the VGA state. When control returns to the point of interruption, the VGA will likely be in a different state than expected.
The fg_vgastate routine saves and restores the VGA registers that
Fastgraph expects to be in specific states. These registers are: � 354 Fastgraph User's Guide
* Graphics Controller index * Graphics Controller registers 0-8 * Sequence Controller index * Sequence Controller register 2
To save the state of these registers, call fg_vgastate(0). To restore them to their previously saved values, call fg_vgastate(1). If you request a fg_vgastate save operation before performing a restore operation, nothing happens. The fg_vgastate routine is meaningful only in video modes numbered 13 and above when running on a VGA or SVGA system.
If you need to save and restore the VGA state in an SVGA graphics mode,
you should use fg_vgastate to preserve the VGA registers plus fg_getbanks and fg_setbanks (described in the previous section) to preserve the SVGA bank numbers.
Summary of Miscellaneous Routines
This section summarizes the functional descriptions of the Fastgraph
routines presented in this chapter. More detailed information about these routines, including their arguments and return values, may be found in the Fastgraph Reference Manual.
FG_GETBANKS returns the current SVGA read and write bank numbers. These
values will be correct only if set through the SVGA kernel, or with fg_setbanks.
FG_MEMAVAIL returns the amount of memory available to DOS.
FG_SETBANKS defines the SVGA read and write bank numbers. This routine is
not usually called in an application but is provided as a high-level interface to Fastgraph's SVGA kernel.
FG_SETFUNC specifies the logical operation (replacement, or, and,
exclusive or) applied when video memory changes in the 16-color EGA, VGA, and SVGA graphics modes. This routine has no effect in other video modes and does not apply to information written to virtual buffers.
FG_VGASTATE saves or restores the state of the VGA Graphics Controller
and Sequence Controller registers used by Fastgraph.
FG_WAITVR disables or enables vertical retrace synchronization within
Fastgraph.
Appendix A
Fastgraph Utilities � 356 Fastgraph User's Guide
Overview
This appendix describes the utility programs supplied with Fastgraph. By
default, the Fastgraph installation procedure places these utilities in the \FG directory. To use these utilities, you must either (1) copy the EXE file from \FG to your current directory, (2) make \FG your current directory, or (3) include the \FG directory in your DOS path specification.
SNAPSHOT Utility
The SNAPSHOT utility is a terminate and stay resident program (TSR) to
capture graphic images. It stores the image in Fastgraph's standard pixel run (SPR) format. To load SNAPSHOT, just enter the command SNAPSHOT at the DOS prompt, and you'll see messages similar to the following if SNAPSHOT loads successfully.
C> SNAPSHOT
SNAPSHOT Version 1.04 Copyright (c) 1993 Ted Gruber Software. All Rights Reserved.
Press <alt>-<left shift> to activate.
After SNAPSHOT loads, control returns to the DOS prompt. At this point,
you can use any method whatsoever to display a graphic image and then press the Alt and left shift keys at the same time to capture the image. You don't need to load SNAPSHOT for each image capture, just once per system boot. SNAPSHOT uses about 24,000 bytes of conventional memory once loaded.
To illustrate the use of SNAPSHOT, suppose you have drawn and saved an
image with a commercial paint program, and you want to incorporate this image into a Fastgraph application. Once you load SNAPSHOT, start the paint program and retrieve your image. Then press the Alt and left shift keys simultaneously and wait for the success tone (three quick medium-pitched sounds). Finally, exit the paint program to return to the DOS prompt.
The sequence described in the preceding paragraph will store the captured
image in Fastgraph's standard pixel run format, in a file named SNAPSHOT.nnn in the current directory. The file type nnn will be the first sequence of digits that does not result in a duplicate file name. That is, if there are no captured image files in the current directory, SNAPSHOT will use the file name SNAPSHOT.000. The next time you capture an image, SNAPSHOT will store it in SNAPSHOT.001, then SNAPSHOT.002, and so forth. If you rename or delete one of these files, SNAPSHOT will again use that file name. For example, if you delete SNAPSHOT.000 but keep SNAPSHOT.001, SNAPSHOT will store the next image it captures in SNAPSHOT.000.
If SNAPSHOT is unable to capture the image, it will produce its error
tone (a single low-pitched sound). The most common cause of this is trying to capture an image from a text video mode, but it also will occur if there is not enough disk space or if all 1,000 image file names are already being used. �
Appendix A: Fastgraph Utilities 357
CLIP Utility
The SNAPSHOT utility described in the previous section captures the
entire screen. While this might be desirable in some cases, other times you'll just need a portion of the screen. CLIP is an interactive utility that you can use to reduce the size of any image stored in Fastgraph's standard or packed pixel run format. The syntax of the command for invoking the CLIP utility from the DOS prompt is
CLIP input_file output_file options
where input_file is the name of the original image file, and output_file is the name of the new image file. CLIP does not modify the input_file in any way, but it will overwrite the output_file if an identically named file exists in the current directory. The options list specifies one or more optional switches as shown here:
option meaning
/M:mode Specifies the video mode number in which to display the image. The
mode value must be an integer between 0 and 29. If that video mode is a text mode, an unsupported graphics mode, or an unavailable graphics mode, CLIP displays an error message stating this. If the /M switch is not present, CLIP uses the first available video mode from the list 18, 16, 15, 19, 13, 9, 4, 12.
/P Indicates the input_file is in Fastgraph's packed pixel run format.
If the /P switch is not present, CLIP assumes it is in standard pixel run format. The output_file will be in the same format as the input_file.
/W:width Specifies the image width in pixels. The width value must be an
integer between 1 and the horizontal resolution of the selected video mode. If the /W switch is not present, CLIP uses the horizontal resolution of the selected video mode.
For example, if you wanted to create the image file PARTIAL.PPR from the packed pixel run file SCREEN.PPR, and use the native 320x200 EGA graphics video mode (mode 13), you would start CLIP with the following command.
CLIP PARTIAL.PPR SCREEN.PPR /P /M:13
Because no /W switch appears in the above command and the horizontal resolution of mode 13 is 320 pixels, CLIP assumes the image width is 320 pixels.
When CLIP displays the image and the plus-shaped cursor, you are ready to
define one corner of the clipping region (that part of the image used to create the output_file). To do this, use the directional keys on the numeric keypad to move the cursor to the desired position, then press the Enter key. You are then ready to define the clipping region's opposite corner. Again, use the directional keys to move the cursor to the desired position. When defining the second corner, however, CLIP uses a rectangular box instead of the plus- shaped cursor to simplify marking the clipping region's boundaries. After you press Enter to define the second corner, CLIP creates the output_file and � 358 Fastgraph User's Guide
displays the resulting image width and the number of pixel runs the image
contains.
CLIP includes other features to help define the clipping region. You can
change the distance the cursor moves in response to the directional keys, display the current (x,y) pixel coordinates of the cursor, and change the cursor color. The following table explains the keystrokes that CLIP recognizes when you are defining the clipping region.
key meaning
F1 Displays the (x,y) coordinate bar at the top of the screen. If the
coordinate bar is already on, F1 removes it.
F2 Displays the (x,y) coordinate bar at the bottom of the screen. If
the coordinate bar is already on, F2 removes it.
F3 Changes the cursor or box color from white to black, or from black
to white.
F4 Displays a summary of the keys CLIP recognizes when defining the
clipping region.
KP1 Moves the cursor one unit down and to the left. KP2 Moves the cursor one unit down. KP3 Moves the cursor one unit down and to the right. KP4 Moves the cursor one unit to the left. KP6 Moves the cursor one unit to the right. KP7 Moves the cursor one unit up and to the left. KP8 Moves the cursor one unit up. KP9 Moves the cursor one unit up and to the right. + Increases the unit of cursor movement by one pixel. The default
cursor movement is one pixel.
- Decreases the unit of cursor movement by one pixel. Enter Defines a corner of the clipping region at the cursor position. Esc Exits to DOS without creating the output_file. CLIP will first issue
an "Exit to DOS?" prompt in case you pressed the Esc key accidentally.
CONVERT Utility
The CONVERT utility lets you translate files between Fastgraph's SPR and
PPR image file formats. The syntax of the command for invoking CONVERT from the DOS prompt is
CONVERT input_file output_file
where input_file is the name of the original image file, and output_file is the name of the new translated image file. CONVERT does not modify the input_file in any way, but it will overwrite the output_file if an identically named file exists in the current directory.
By default, the file type of the input_file and output_file determine the
image format of that file. If the file type is PPR, CONVERT assumes the image is in Fastgraph's packed pixel run format. If the file type is SPR, CONVERT assumes it is in the Fastgraph's standard pixel run format. If your image files use other file types, you can explicitly specify the file's image format by appending one of the switches /PPR or /SPR to the file name. The input_file �
Appendix A: Fastgraph Utilities 359
and output_file must not both specify the same image format (CONVERT will
display an error message if this is so).
The following command will translate the standard pixel run file
PICTURE.SPR to packed format. The packed image will be stored in the file PICTURE.IMG, so we must append the switch /PPR to tell CONVERT that it will be a packed file.
CONVERT PICTURE.SPR PICTURE.IMG/PPR
EDITSPR Utility
The EDITSPR utility changes all pixel runs of one color to another color
in an image file stored in Fastgraph's standard pixel run (SPR) format. The syntax of the command for invoking the EDITSPR utility from the DOS command prompt is
EDITSPR input_file output_file
where input_file is the name of the original image file, and output_file is the name of the new image file. EDITSPR does not modify the input_file in any way, but it will overwrite the output_file if an identically named file exists in the current directory.
After it reads the pixel runs from the input_file, EDITSPR will perform
the requested color changes. It does this iteratively by asking for an old color value followed by a new color value (each value must be between 0 and 255). EDITSPR then finds the pixel runs of the old color value and changes them to the new color value. Following this, EDITSPR displays a message stating how many pixel runs it changed. This process repeats until you enter a negative number for either color value.
EDITSPR will next combine adjacent pixel runs of like colors. For
example, suppose the original image file contained a color 1 pixel run of length 50, followed by a color 2 pixel run of length 20, followed by another color 1 pixel run of length 10. If you changed all color 2 pixel runs to color 1, EDITSPR will combine these three pixel runs into a single run of length 80.
GrabRGB Utility
The GrabRGB utility is a terminate and stay resident program (TSR) to
capture the current red, green, and blue color components of video DAC registers in 256-color graphics modes. You can use GrabRGB together with Fastgraph's SNAPSHOT utility to preserve the original colors of a captured image.
To load GrabRGB, just enter the command GRABRGB at the DOS prompt. After
GrabRGB loads, control returns to the DOS prompt. At this point, you can use any method whatsoever to display a 256-color graphic image and then press the Alt and right shift keys at the same time to capture the current DAC values. You don't need to load GrabRGB for each image, just once per system boot. GrabRGB uses about 28,000 bytes of conventional memory once loaded. � 360 Fastgraph User's Guide
To illustrate the use of GrabRGB, suppose you have drawn and saved a 256-
color image with a commercial paint program, and you want to incorporate this image into a Fastgraph application. Once you load SNAPSHOT and GrabRGB, start the paint program and retrieve your image. Then press the Alt and left shift keys to capture the image with SNAPSHOT. After SNAPSHOT's success tone (three quick medium-pitched sounds), press Alt and right shift to capture the RGB components of each DAC register with GrabRGB, and wait for GrabRGB's success tone. Finally, exit the paint program and return to the DOS prompt.
The sequence described in the preceding paragraph will write the RGB
color components for each DAC register to a file named GRABRGB.nnn in the current directory. The file type nnn will be the first sequence of digits that does not result in a duplicate file name. That is, if there are no GrabRGB output files in the current directory, GrabRGB will use the file name GRABRGB.000. The next time you use GrabRGB, it will store the RGB information in GRABRGB.001, then GRABRGB.002, and so forth. If you rename or delete one of these files, GrabRGB will again use that file name. For example, if you delete GRABRGB.000 but keep GRABRGB.001, GrabRGB will next use the file name GRABRGB.000.
If GrabRGB is unable to obtain the RGB components of each DAC register,
it will produce its error tone (a single low-pitched sound). The most common cause of this is trying to capture an image from a text video mode, or from a graphics video mode with fewer than 256 colors. It also will occur if there is not enough disk space or if all 1,000 output file names are already being used.
Each line in the output file created by GrabRGB is of the form
nnn,rr,gg,bb,
where nnn is a DAC register index (between 0 and 255), rr is the red component of that DAC register, gg is the green component, and bb is the blue component. Each color component is between 0 and 63. You can edit and reformat these lines as necessary for inclusion in a C or C++ initializer list, a BASIC or FORTRAN data statement, or a Pascal array-type constant list. Such an array of RGB components, but without the nnn indices, is in the format expected by fg_setdacs.
By default, GrabRGB captures information for all 256 DAC registers. If
you want to consider only the DAC registers with color components different from their default values, just include the /D option when you load GrabRGB (that is, use the command GRABRGB /D). If you specify the /D option and all 256 DACs use their default values, the output file will contain a message stating this.
HERCFIX Utility
The HERCFIX utility allows you to use SNAPSHOT (and possibly other TSRs)
with programs that do not update the BIOS data area when establishing the 720x348 Hercules graphics mode. If you use SNAPSHOT with such a program, it will think the monochrome text mode (video mode 7) is active and will produce its low-pitched error tone when activated. �
Appendix A: Fastgraph Utilities 361
If this occurs, use HERCFIX to load the application from which you are
trying to capture the image. To do this, enter
HERCFIX command
at the DOS prompt, where command is the command that starts the application. For example, suppose you use the command PAINTER /H to run a commercial paint program in Hercules graphics mode. To load the paint program with HERCFIX, you would enter the command HERCFIX PAINTER /H.
PCXHEAD Utility
The PCXHEAD utility displays the most important information from the
header of a PCX file. This consists of the PCX version number, the number of bits per pixel, the number of bit planes, the scan line width, and the image dimensions and screen position. It also proposes the optimal video mode for displaying the PCX file. By optimal, we mean the compatible video mode having the lowest resolution larger than or equal to the image dimensions. For 256- color PCX images, PCXHEAD displays the extended color palette if one is present.
The syntax of the command for invoking the PCXHEAD utility from the DOS
command prompt is
PCXHEAD pcx_file
where pcx_file is the name of the PCX file to examine. PCXHEAD does not modify the pcx_file in any way. If the PCX file includes an extended color palette, you may prefer to direct the PCXHEAD output to a file using the DOS redirection operator (>). � 362 Fastgraph User's Guide �
Appendix B
Using Fastgraph from Assembly Language � 364 Fastgraph User's Guide
The information in this appendix provides information about calling
Fastgraph routines from assembly language programs. It is not intended to be a complete tutorial on the subject, but it should provide experienced assembly language programmers with enough details to call Fastgraph routines in their applications.
Fastgraph uses the same naming and stack-based calling conventions used
by Borland, Microsoft, and other companies in their C and C++ compilers. The details of these conventions important to assembly language programming are summarized below. If you're calling Fastgraph routines from an assembly language program, the program must follow these conventions.
* All arrays and pointers are passed by reference. * All other items are passed by value. * Arguments are pushed onto the stack in reverse order. * The calling program is responsible for removing the arguments from the stack. * 16-bit function values are returned in the AX register. * 32-bit function values are returned in the DX:AX register pair in 16-bit environments, or the EAX register in 32-bit environments. * Fastgraph routine names are prefixed with an underscore.
The small and medium model real mode Fastgraph libraries pass arrays and pointers by near reference (an offset into DGROUP), while the large model and 16-bit protected mode libraries do so by far reference (a segment:offset or selector:offset pair). The 32-bit protected mode libraries use a flat model architecture, meaning arrays and pointers are passed as 32-bit offsets into DGROUP. This is consistent with the conventions and run-time libraries for the supported compilers.
All Fastgraph routines preserve the (E)BP, (E)DI, (E)SI, and DS
registers. In the 32-bit protected mode libraries, the EBX and ES registers are also preserved. The contents of any other registers are unknown upon return from a Fastgraph routine (except for the (E)AX register, which will either contain zero or the routine's return value).
Example B-1 calls fg_getmode, fg_setmode, fg_reset, and fg_version from
an assembly language program. The fg_getmode routine returns its function value in the (E)AX register. The fg_setmode routine has a single argument, while fg_reset has no arguments. The fg_version routine has two arguments, both passed by reference. Notice how they are pushed on the stack in reverse order. This example is written for the medium memory model. To make it work with the large model libraries, add 8 instead of 4 to the (E)SP register following the call to fg_version (because large model items passed by reference are 32-bit segmented values). To make it work with the small model library, change the word "far" to "near" in the EXTRN declarations, and change the name of the code segment from "main_TEXT" to "_TEXT".
This example is in the file BB-01.ASM in the \FG\EXAMPLES directory. The
following commands show how to use MASM or TASM to assemble this program and link it with the medium model real mode Fastgraph library. �
Appendix B: Using Fastgraph from Assembly Language 365
Microsoft Macro Assembler (MASM) version 5: MASM BB-01.ASM; LINK /CP:4096 BB-01,,NUL,FGM;
Microsoft Macro Assembler (MASM) version 6: ML /c /Cx /Zm BB-01.ASM LINK /CP:4096 BB-01,,NUL,FGM;
Turbo Assembler (TASM): TASM BB-01.ASM TLINK BB-01.OBJ FGM.LIB
Example B-1.
EXTRN _fg_getmode:far ; Fastgraph's GETMODE routine EXTRN _fg_reset:far ; Fastgraph's RESET routine EXTRN _fg_setmode:far ; Fastgraph's SETMODE routine EXTRN _fg_version:far ; Fastgraph's VERSION routine
stackseg SEGMENT stack db 1024 dup (?) ; use a 1K stack stackseg ENDS
_DATA SEGMENT word public 'DATA' major dw ? ; major version number minor dw ? ; minor version number old_mode dw ? ; original video mode _DATA ENDS
dgroup GROUP _DATA ASSUME cs:main_TEXT,ds:dgroup
main_TEXT SEGMENT byte public 'CODE'
start: mov ax,_DATA ; load segment location mov ds,ax ; into DS register
call _fg_getmode ; AX = current video mode mov old_mode,ax ; save it
mov ax,4 ; use video mode 4 push ax ; pass argument fg_setmode call _fg_setmode ; establish CGA four-color mode add sp,2 ; remove fg_setmode argument
push old_mode ; pass argument to fg_setmode call _fg_setmode ; restore original video mode add sp,2 ; remove fg_setmode argument
call _fg_reset ; restore screen attributes
lea ax,minor ; get address of minor variable push ax ; pass argument #2 to fg_version lea ax,major ; get address of major variable push ax ; pass argument #1 to fg_version �
366 Fastgraph User's Guide
call _fg_version ; get the Fastgraph version number add sp,4 ; remove fg_version arguments
mov ah,76 ; function 76: terminate process xor al,al ; errorlevel 0 int 21h ; exit to DOS
main_TEXT ENDS END start �
Appendix C
Interrupts and Fastgraph � 368 Fastgraph User's Guide
Interrupts Used by Fastgraph
DOS maintains an interrupt vector table where it stores the addresses of
256 interrupt handlers, or routines, that perform various functions. The handlers are usually referenced by their hexadecimal interrupt number, between 00 and FF. Of these, only interrupts 60 through 66 and F1 through FF are not used by DOS, the ROM BIOS, or other software and are thus available for user applications.
Certain Fastgraph routines use some of the available interrupts. All
Fastgraph/Light routines use interrupt 62. In addition, Fastgraph's low-level keyboard handler replaces interrupt 09. If your program defines its own interrupt handlers, it must not use any interrupts reserved for Fastgraph (unless, of course, it doesn't use any Fastgraph routines that would create a conflict).
Extending the Time-of-Day Interrupt
As mentioned in Chapter 16, the BIOS time-of-day clock is incremented by
an interrupt handler. The routine that does this is interrupt 08, a hardware interrupt automatically activated 18.2 times per second. After incrementing the clock, interrupt 08 invokes interrupt 1C, which by default references a "do-nothing" interrupt handler. While changing interrupt 08 can be tricky, it is fairly straightforward to define our own handler for interrupt 1C. This handler also will be executed automatically 18.2 times per second. Example C-1 illustrates how to do this.
When we discussed joysticks in Chapter 14, we said there were two ways to
monitor joystick button status. One is to intersperse calls to fg_button at strategic places in your program and then take necessary action depending on the button status. However, the problem with this scheme is the chance of missing a button press -- if you press the joystick button and then release it between calls to fg_button, the program will not detect the joystick activity. A preferable method is to call fg_button from a handler for interrupt 1C, which essentially provides continuous monitoring of the joystick buttons. When we need the button status within our program, all we need to do is examine a global variable.
Example C-1 consists of a main program (written in C) and an assembly
language subroutine named int1C (suitable for the real mode medium memory model). The main program calls int1C to define a handler for interrupt 1C. In response to any keystroke (except Escape), the program displays the button press information for each joystick since the previous keystroke (refer to the discussion of fg_button for the meanings of the status values). When you press the Escape key, the program exits to DOS, but not before calling int1C to restore the original interrupt 1C handler.
Example C-1 (main program).
#include <fastgraf.h> #include <stdio.h> void main(void);
#define ESC 27 � Appendix C: Interrupts and Fastgraph 369
int status1, status2;
void main() { unsigned char key, aux;
int1C(1);
status1 = 0; status2 = 0;
do { printf("\n"); printf("Joystick 1 status: %d\n",status1); printf("Joystick 2 status: %d\n",status2); status1 = 0; status2 = 0; fg_getkey(&key,&aux); } while (key != ESC);
int1C(0); }
We'll now examine the int1C assembly language subroutine. It actually
consists of three parts: a portion to enable our interrupt handler, our handler itself, and a portion to disable the handler. When we call int1C with a nonzero argument, it saves the original data segment (so we can access the global variables within the handler), saves the original handler's address (called the vector) for interrupt 1C, and then enables our handler, which takes the form of a far procedure.
The handler routine then begins to be activated 18.2 times per second.
After saving all the important registers, the handler calls the Fastgraph routine fg_button twice, once for each joystick. The return values are logically ORed with the status1 and status2 C global variables to update the button status information. Finally, the handler restores the original registers and returns control to the point of the interrupt.
Before the main program exits, it calls int1C with a zero argument to
restore the original handler for interrupt 1C. No provision is made in the program to check if we had previously defined our own handler (and hence saved the original interrupt 1C vector), but this could be added with little difficulty.
Example C-1 (assembly language subroutine).
EXTRN _status1:word ; C global variable for button 1 status EXTRN _status2:word ; C global variable for button 2 status EXTRN _fg_button:far ; Fastgraph routine
int1C_TEXT SEGMENT byte public 'CODE'
ASSUME cs:int1C_TEXT �
370 Fastgraph User's Guide
int1C_CS dw ? ; holds original INT 1C segment address
int1C_IP dw ? ; holds original INT 1C offset
orig_DS dw ? ; holds original data segment
_int1C PROC far
PUBLIC _int1C
push bp ; save caller's BP register mov bp,sp ; make BP point to argument list push si ; save caller's SI register push di ; save caller's DI register
mov dx,[bp+6] ; get the flag parameter or dx,dx ; replace the old interrupt handler? jz replace ; yes, branch to that processing
- define a new handler for INT 1C
define: mov ax,ds ; put current data segment in AX
mov cs:orig_DS,ax ; save it in the control information area
mov al,1Ch ; interrupt vector to save mov ah,53 ; function 53: get interrupt vector int 21h ; get the interrupt vector mov cs:int1C_CS,es; save the segment mov cs:int1C_IP,bx; save the offset
push ds ; save our DS register mov dx,offset handler ; get offset of interrupt handler mov ax,seg handler; get segment of interrupt handler mov ds,ax ; put it in DS mov al,1Ch ; interrupt vector to change mov ah,37 ; function 37: set interrupt vector int 21h ; change the INT 1C vector to our handler pop ds ; restore our DS register
jmp short return ; return to the caller
- replace the original handler for INT 1C
replace: push ds ; save our DS register
mov dx,cs:int1C_IP; put original INT 1C offset in DX mov ds,cs:int1C_CS; put original INT 1C segment in DS mov ah,37 ; function 37: set interrupt vector mov al,1Ch ; interrupt vector 1C int 21h ; restore original INT 1C vector pop ds ; restore our DS register
return: xor ax,ax ; in case int1C was called as a function
pop di ; restore our DI register pop si ; restore our SI register pop bp ; restore our BP register ret
_int1C ENDP �
Appendix C: Interrupts and Fastgraph 371
handler PROC far ; interrupt handler that replaces INT 1C
cli ; disable interrupts while handler active push ax ; save registers that may be altered push bx push cx push dx push di push si push ds push es
mov ds,cs:orig_DS ; retrieve the original data segment
mov ax,1 ; use joystick 1 push ax ; pass joystick number to button routine call _fg_button ; AX = button status for joystick 1 add sp,2 ; remove the argument or _status1,ax ; update status variable for joystick 1
mov ax,2 ; use joystick 2 push ax ; pass joystick number to button routine call _fg_button ; AX = button status for joystick 2 add sp,2 ; remove the argument or _status2,ax ; update status variable for joystick 2
pop es ; restore altered registers pop ds pop si pop di pop dx pop cx pop bx pop ax iret ; return from the interrupt routine
handler ENDP
int1C_TEXT ENDS
END
The example just presented is not meant to be a tutorial on interrupts;
there are many good references on DOS that explain them in detail. However, an example specific to Fastgraph should be helpful. � 372 Fastgraph User's Guide �
Appendix D
Contents of the Compiler-Specific Libraries � 374 Fastgraph User's Guide
For most compilers, Fastgraph provides a compiler-specific library (also
called the auxiliary Fastgraph library) that contains the following routines:
fg_boxw fg_drawxw fg_panw fg_setsize fg_boxxw fg_drectw fg_pointw fg_setsizew fg_circlew fg_ellipsew fg_pointxw fg_setworld fg_circlefw fg_ellipsfw fg_polygonw fg_swchar fg_clprectw fg_floodw fg_rectw fg_swlength fg_dashrw fg_getworld fg_restorew fg_swtext fg_dashw fg_initw fg_savew fg_xscreen fg_drawrw fg_moverw fg_setangle fg_xworld fg_drawrxw fg_movew fg_setclipw fg_yscreen fg_draww fg_paintw fg_setratio fg_yworld
These routines use the world space coordinate system, either directly or internally. None of them are included in Fastgraph/Light.
As mentioned in Chapter 1, if your program uses any of these routines,
you must link it with the general Fastgraph library and the corresponding auxiliary Fastgraph library. Some compilers, such as Microsoft Visual C++ 32- bit Edition, Microsoft FORTRAN PowerStation, and Fastgraph's supported BASIC compilers do not require an auxiliary library because the routines listed above are included directly in the Fastgraph library for those compilers. �
Appendix E
Contents of the Pascal Unit Files � 376 Fastgraph User's Guide
Borland Pascal and Turbo Pascal restrict the total size of all code
segments in a unit file 65,520 bytes. Because the size of Fastgraph's code exceeds this amount, the Fastgraph functions are split among several unit files. This appendix lists the contents of each Pascal unit file.
Fastgraph routines in FGBITMAP
fg_clipmap fg_flpimage fg_pack fg_scale fg_clipmask fg_getblock fg_print fg_shear fg_clpimage fg_getimage fg_printc fg_text fg_drawmap fg_getmap fg_putblock fg_textc fg_drawmask fg_imagebuf fg_putimage fg_unpack fg_drwimage fg_imagesiz fg_revimage fg_flipmask fg_invert fg_revmask
Fastgraph routines in FGFLIC
fg_flicdone fg_flicmode fg_flicplay fg_flicskip fg_flichead fg_flicopen fg_flicsize fg_showflic
Fastgraph routines in FGGIF
fg_gifhead fg_gifpal fg_makegif fg_showgif fg_gifmode fg_gifrange
Fastgraph routines in FGMISC
fg_button fg_kbinit fg_mousemov fg_setcaps fg_capslock fg_kblast fg_mousepos fg_setnum fg_cursor fg_kbreset fg_mouseptr fg_sound fg_getclock fg_kbtest fg_mousespd fg_sounds fg_getkey fg_measure fg_mousevis fg_suspend fg_getxjoy fg_memavail fg_music fg_voice fg_getyjoy fg_mouse256 fg_musicb fg_voices fg_hush fg_mousebut fg_numlock fg_waitfor fg_hushnext fg_mousecur fg_playing fg_waitkey fg_initjoy fg_mousefin fg_quiet fg_intjoy fg_mouseini fg_resume fg_intkey fg_mouselim fg_scrlock
Fastgraph routines in FGPCX
fg_loadpcx fg_pcxhead fg_pcxpal fg_showpcx fg_makepcx fg_pcxmode fg_pcxrange
Fastgraph routines in FGPR
fg_dispfile fg_displayp fg_makespr fg_showspr fg_display fg_makeppr fg_showppr
Fastgraph routines in FGSVGA
fg_defpages fg_memory fg_svgainit fg_svgaver fg_getbanks fg_setbanks fg_svgastat
Fastgraph routines in FGVB
fg_vbaddr fg_vbcut fg_vbinit fg_vbundef fg_vballoc fg_vbdefine fg_vbopen fg_vbclose fg_vbfree fg_vbpaste fg_vbcopy fg_vbhandle fg_vbtcxfer � Appendix E: Contents of the Pascal Unit FIles 377
The world space routines listed in Appendix D are in the FGWORLD unit. Any
other Fastgraph routine NOT listed in this appendix is in the FGMAIN unit.
As mentioned in Chapter 1, Pascal programs must include a uses statement listing all units referenced in the program. The fgmain unit is always required in all programs, as is the WinAPI unit in 16-bit protected mode programs. Other unit files are needed when you call the Fastgraph routines they contain. � 378 Fastgraph User's Guide �
Appendix F
Integrating Fastgraph With Other Graphics Software � 380 Fastgraph User's Guide
Sometimes you may want to use Fastgraph with other graphics software,
such as when converting an existing graphics application to Fastgraph. This appendix may clarify some points about doing this.
First, let the other graphics software establish the video mode, then
initialize Fastgraph for that mode by calling fg_setmode(-1). Passing -1 to fg_setmode does not physically change video modes but merely initializes Fastgraph's internal parameters for the current video mode.
Second, if you're using the EGA/VGA/SVGA 16-color graphics modes (modes
13 to 18, 28, and 29), you'll probably need to explicitly define the value of the EGA/VGA Enable Set/Reset register (port address 03CE hex, index 01). Fastgraph's functions expect this register to have the value 0F hex; this allows Fastgraph take advantage of a more efficient variant available in EGA/VGA write mode 0. The default value for the Enable Set/Reset register is zero.
After you've called fg_setmode(-1) and need to call a third party
graphics function, set the Enable Set/Reset register to its default value by including the following statement just before calling the third party function:
outport(0x03CE,0x0001); Borland C++, Turbo C/C++, or Power C outpw(0x03CE,0x0001); Microsoft C/C++, QuickC, WATCOM C/C++ OUT &h03CE,1 : OUT &h03CF,0 QuickBASIC, BASIC PDS, or Visual Basic
Just before you call the next Fastgraph function, restore the Enable Set/Reset register value with the following statement:
outport(0x03CE,0x0F01); Borland C++, Turbo C/C++, or Power C outpw(0x03CE,0x0F01); Microsoft C/C++, QuickC, WATCOM C/C++ OUT &h03CE,1 : OUT &h03CF,15 QuickBASIC, BASIC PDS, or Visual Basic �
Appendix G
Converting Programs to Protected Mode � 382 Fastgraph User's Guide
In this appendix we'll describe the steps necessary for porting real mode
Fastgraph applications to protected mode. We'll also cover common changes required when converting 16-bit applications to 32-bit protected mode.
Protected Mode Initialization
The first and most obvious step when converting programs to protected
mode is to call fg_initpm. This routine sets up protected mode features for each supported DOS extender and must be called before any other Fastgraph routine in protected mode programs. Failure to do this will result in a protection fault, usually immediately after setting the video mode. The fg_initpm routine has no arguments and no return value. It is included in the extender-specific support libraries (for example, in FG16DPMI.LIB) if Fastgraph supports more than one DOS extender for a given compiler.
Considerations for Logical Pages
In real mode, Fastgraph lets you create logical pages in conventional
memory (with fg_alloccms), expanded memory (with fg_allocems), or extended memory (with fg_allocxms). In protected mode, the distinction between conventional, expanded, and extended memory disappears because DOS extenders essentially treat all system memory as conventional memory. For this reason, the fg_initems and fg_initxms routines are not meaningful and thus always return -1 in the protected mode Fastgraph libraries. This effectively disables the fg_allocems and fg_allocxms routines, so you must create logical pages with fg_alloccms in protected mode.
If you have real mode Fastgraph applications that use logical pages, it's
very simple to convert them to protected mode -- just change all fg_allocems and fg_allocxms calls to fg_alloccms.
Considerations for Virtual Buffers
Chapter 8 describes the various methods available for allocating memory
for virtual buffers. Because some real mode compilers have limited support for huge arrays (blocks of memory greater than 64K bytes), Fastgraph's fg_vballoc and fg_vbfree routines are provided for allocating and releasing memory suitable for virtual buffers. All protected mode compilers provide full support for huge arrays, so these two functions aren't needed (in fact, they're not even included in the protected mode libraries). Thus, you must replace the fg_vballoc and fg_vbfree calls with your compiler's corresponding memory management functions as listed in Chapter 8 and use fg_vbdefine to create the virtual buffer.
Mouse Cursor Definition
The fg_mouseptr routine expects the screen and cursor masks to reside in
a 32-element array of 16-bit values. If you're converting a C or C++ Fastgraph application from a 16-bit to a 32-bit environment, you must change the data type of the screen/cursor mask array passed to fg_mouseptr from int to short. �
Appendix G: Converting Programs to Protected Mode 383
FORTRAN programmers should be sure to pass an INTEGER*2 array instead of an
ordinary INTEGER array.
FORTRAN Data Types
When converting FORTRAN programs to 32-bit protected mode, any INTEGER*2
quantities passed to Fastgraph functions must be changed to four-byte integers. For maximum portability, we recommend changing them to type INTEGER, which is equivalent to INTEGER*2 in 16-bit environments and equivalent to INTEGER*4 in 32-bit environments.
Incompatible Real Mode Behavior
After you've added the fg_initpm call and made the other changes
described so far, you should test your program to see if it runs in protected mode. Most high-level language programs will work at this point with no further changes required.
However, some programs include features that are acceptable in real mode
but not in protected mode (often this behavior is unintentional). These practices include loading physical addresses in segment registers, using physical segment addresses in far pointers, writing data to a code segment, referencing unspecified command line arguments, accessing memory beyond a segment's limit, and dereferencing null pointers. When a protected mode program encounters one of these problems during execution, it exits to DOS with a general protection fault, or GPF.
The documentation shipped with your DOS extender will likely provide
information on isolating protection faults and offer suggestions on how to fix them. Two other references, Extending DOS edited by Ray Duncan (Addison- Wesley, 1992) and DOS and Windows Protected Mode by Al Williams (Addison- Wesley, 1993) are valuable resources for protected mode programming. Both books include detailed information about the differences between real mode and protected mode and discuss common protected mode programming problems and solutions. � 384 Fastgraph User's Guide �
Appendix H
Image File Header Formats � 386 Fastgraph User's Guide
PCX, GIF, and FLI/FLC images include file headers that define the image
size, number of colors, and other information needed to display the image. Fastgraph provides routines for reading the image headers and retrieving their more useful items. However, there may be times when you need additional information stored in the file header. This appendix provides full details about the structure of the PCX, GIF, and flic file headers. In the tables that follow, we'll assume all offsets start at zero, all field sizes are in bytes, and all integer values are stored with the least significant byte first.
PCX files begin with a 128-byte header:
offset size description
0 1 manufacturer byte, must be 10 decimal 1 1 PCX version number 0 = PC Paintbrush version 2.5 2 = PC Paintbrush 2.8 with palette information 3 = PC Paintbrush 2.8 without palette information 4 = PC Paintbrush for Windows 5 = PC Paintbrush 3.0 or later, PC Paintbrush Plus 2 1 run length encoding byte, must be 1 3 1 number of bits per pixel per bit plane 4 8 image limits in pixels: Xmin, Ymin, Xmax, Ymax 12 2 horizontal dots per inch when printed (unreliable) 14 2 vertical dots per inch when printed (unreliable) 16 48 16-color palette (16 RGB triples between 0-255) 64 1 reserved, must be zero 65 1 number of bit planes 66 2 video memory bytes per image row 68 2 16-color palette interpretation (unreliable) 0 = color or b&w, 1 = grayscale 70 2 horizontal screen resolution - 1 (unreliable) 72 2 vertical screen resolution - 1 (unreliable) 74 54 reserved, must be zero
GIF files begin with a 13-byte global header and a 10-byte local header:
offset size description
0 6 GIF signature, must be GIF87a or GIF89a 6 2 horizontal resolution of creating video mode (unreliable) 8 2 vertical resolution of creating video mode (unreliable) 10 1 global flag byte bit 7 is set if global color map is present bits 0-3 are the number of colors (2**(n+1)) 11 1 background color 12 1 for GIF87a, must be zero for GIF89a, aspect ratio 13 0 reserved, must be 44 decimal (ASCII comma) 14 2 left edge of image in pixels 16 2 top edge of image in pixels 18 2 image width in pixels 20 2 image height in pixels 22 1 local flag byte bit 7 is set if local color map is present � Appendix H: Image File Header Formats 387
bit 6 is set if image is interlaced bits 0-3 are the number of colors (2**(n+1))
FLI and FLC files begin with a 128-byte header:
offset size description
0 4 file size in bytes 4 2 signature, AF11 hex for FLI files, AF12 hex for FLC files 6 2 number of frames 8 2 image width in pixels 10 2 image height in pixels 12 2 bits per pixel, must be 8 14 2 reserved, must be 3 16 4 time delay between frames units are 1/70 second for FLI files units are milliseconds for FLC files 20 2 reserved, must be zero 22 4 file creation date/time (MS-DOS format) 26 4 creator serial number (unreliable) 30 4 file revision date/time (MS-DOS format) 34 4 updater serial number (unreliable) 38 4 horizontal aspect ratio of creating video mode 40 2 vertical aspect ratio of creating video mode 42 38 reserved, must be zero 80 4 byte offset to start of first frame 84 4 byte offset to start of second frame 88 40 reserved, must be zero
The fields starting at offset 22 and above in the flic file header apply to FLC files only. For FLI files, they should all be zero. � 388 Fastgraph User's Guide �
Index 389