Bienvenue sur le wiki de Nuit debout, nous sommes le 2987 mars.




Villes/Montluçon/sciences/FastGraph

De NuitDebout
< Villes‎ | Montluçon‎ | sciences
Révision de 10 août 2016 à 21:54 par Esprit libre (discussion | contributions) (Page créée avec « Fastgraph (r) User's Guide � Copyright (c) 1991-1995 by Ted Gruber Software, Inc.... »)

(diff) ← Version précédente | Voir la version courante (diff) | Version suivante → (diff)
Aller à : navigation, rechercher









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.

  1. 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