            How to Make Games That Work With Graphics Boards

                    USING GRAPHICS BOARDS WITH GAMES
          
     by S.P. Haeuser EMail : haeuser@tick.informatik.uni-stuttgart.de


 I. Introduction

     As there are often questions in the way of "Does this AGA game run on
 my A3000 with Picasso II board ?" and as people with high end Amigas
 simply do not understand, why games do not support their graphics boards,
 I will talk in this article about the reasons, about what can be done,
 about what are the problems with TRUE AGA emulations and I will provide
 some example code for game programmers (under EGS and Cybergrafix here,
 as those probably will be the leading ones... and the ones to whom I am
 most familiar...) The article is mainly intended for programmers, and
 especially handles about the EGS system (as this is the system that I know
 best...)

     To introduce to the problem i will have some words about how
 Workbench-Emulations work, at least so far as it is needed for this
 article.  The Amiga Display is bitmap oriented, that is, each pixel is
 splitted in 8 bitplanes, and graphics boards are chunky graphics, that is,
 they save each pixel value in one Byte (or in some more Bytes for &gt;8 bit
 depths).  To do a workbench emulation there has to be some code that
 SPREADS these pixel values to the various planes (which is slow) or a
 special chip that does this job (like in the Cybervision64) which is fast,
 but needs a better technology (you can't just do a VGA board with
 ZORRO-interface then...)

     Further, you have to be clear, the Amiga OS extensively uses the
 copper and the blitter processors.  Of course those will get problems, if
 they had to deal with graphics memory on the board.  Therefore WB-Emus
 patch different OS-functions, and if you use WB-Emus for coding you have
 to know which calls are still compatible, and which not.

     Of course, a lot of code writes directly to the Amiga special chips.
 This code will NEVER run on a graphics board, and this is, sadly, for most
 games.  But this is the most efficent way to do a game, and game coders
 are very concrened with efficiency, as they want their games running on as
 many systems as possible.

II. Main problems

     Now it is the point to name the main problems using Workbench
 emulation for games :

1) Speed 2) Using copper 3) Using Double buffered displays 4) Directly using
special chips

     Blitter is no problem (as long as you do not access it directly,
 but use graphics.library...), the WB-Emus I know handle this well.

     As for #1, I have to say, of course the speed will be like in
 Amiga modes and better, but you won't get the speed that the graphics
 board is capable of.  I will provide another solution later.  If you NEED
 to use a WB-Emu, I recommend making the game compatible to Cybergrafix, as
 this one is a quite fast emulation and runs on nearly all boards.

     #2 is nearly unsolvable.  User-Copperlists will be a problem
 to a lot of WB-Emus, and the screen will stay invisible.  Better not to 
 use such a thing.

     Some WB-Emus take #3 okay, but others (like EGS), do not like double
 buffering methods other than those of their own graphics board specific
 libraries.  The buest guess is to use the doubble buffering methods around
 AllocScreenBuffer of 3.0... of course, then, the game only runs from 3.0
 upward.

     As to #4, there is no way to run such a code on a graphics board.
 But, strangely enough, this is the best solution of all.  Do not use the
 special chips of the Amiga, but use the special chips of some graphics
 boards you want to support.  This is a solution of 1) to 3) as well.  Of
 course, this is more work, as their is no "VGA-Standard" for Amiga... on
 PC the situation concerrning graphics boards is better...

 III. Solutions

 So, the possibilities are clear :

 A) Use a workbench emulation, but do not use Copper or Double Buffering
 B) Provide drivers for different graphics board, to access the video
    memory of these boards directly.

     There is currently a project running (Caution! Advertising! :) ), that
 is about creating a standard library called rtg.library that will do the
 job about B) for you, and will be Freeware in the future... providing
 support for most boards and even for ECS/AGA (with c2p code...).  The code
 will leave the possibility for the coder only to get the start adress
 of the video memory from the library, use doubble buffering from the
 library, and do the rest himself (as most game coders want to do...)
 But up to now, you will need to do that driver things yourself.

     At this point I will say something about games actually running on
 graphics boards.  That is ... ahem... Spaceward Ho!  I've heard some
 rumours about the Sim games running on gfx boards, but I do not know if
 these are true.  Sadly, apart from those and a few Shareware games, 
 those are all of them up to now. 
 
     Some games even have problems with the WB-Emu being activated (at
 least as far as EGS is concerned). So we have still a far way to go...

 IV. Coding section

     Now the coding section.  In this section I will give you some hints
 on how to write data directly to the video memory of EGS boards
 (the great thing about EGS is, the egs.library provides a function to
 get the base adress of the video memory of a display, and such a thing
 I did not find in any other WB-Emu).  Then I will give some hints about
 Cybergrafix (but I am not an expert there...)

 A. EGS

     Before you start opening a screen you should choose a screenmode. You
 only should use a screenmode that is available on this system (as you
 can never be sure, if it is...), and that is done in the following way :

 move.l egsbase,a6  ; Base Adress of egs.library jsr E_LockEGSVideo(a6) jsr
 E_GetHardInfo(a6) move.l d0,hardinfo ; info structure about this system
 jsr E_UnlockEGSVideo(a6)

     In the following i will discribe the HardInfo structure.  It is a
 modified structure, as there are only EGS V 5.x includes out for EGS, but
 you will need V 6.x at least... so I had to modify them oneselves... I
 would not try to use C, as I got some serious speed problems with Double
 Buffering with that language...And of course, this sort of code, as it is
 the most internal part of our game, should be FAST...

 STRUCTURE  E_HardInfo,0
        APTR    ehi_Product
        APTR    ehi_Manufact
        APTR    ehi_Name
        WORD    ehi_Version
        WORD    ehi_MaxFreq
        ULONG   ehi_Flags
        APTR    ehi_Modes
        WORD    ehi_ActPixClock
        WORD    ehi_frameTime
        APTR    ehi_MemBase
        LONG    ehi_MemSize
        APTR    ehi_LibDate
        APTR    ehi_Drivers
        APTR    ehi_Monitors
        APTR    ehi_VideoNodes
        APTR    ehi_Screen
        LABEL   ehi_SIZEOF       

     Most of the entries of these structure do not say anything... and have
 no valid information inside... interesting are :

 APTR ehi_Modes APTR ehi_Monitors APTR ehi_Drivers

     The drivers contain information of the supported EGS drivers, and will
 be useful to find out which screenmodes actually run on the graphics
 board.

 STRUCTURE E_DisplayDriver,0
        STRUCT edd_Node,LN_SIZE
        WORD   edd_Pad0
        APTR   edd_Prefix
        ULONG  edd_Depths
        STRUCT edd_Freqs,24*emm_SIZEOF
        STRUCT edd_Monitors,MLN_SIZE
        ULONG  edd_Flags
        APTR   edd_Default
        STRUCT edd_MaxPixel,24*4
        ULONG  edd_MemSize
        UWORD  edd_MouseSize
        UWORD  edd_Pad1
        APTR   edd_description
        LABEL  edd_SIZEOF     

     Now we get LN_NAME of the SECOND thing in that list of Drivers
 (the first one only contains rubbish...) We will examine the first
 four characters of the string we get then, and look for :

 PICO, LEGS, RB3a, RB3b or G110

 PICO      : Display driver for Piccolo/Piccolo SD64 LEGS      : Display
 driver for EGS Spectrum RB3a,RB3b : Display driver for Rainbow 3 G110 :
 Display driver for EGS 110

     I do not know what is about EGS Graffiti and A2410 EGS drivers...
 If someone knows, maybe he could send me a mail...

 Now we examine the screenmodes :

 STRUCTURE  E_ScreenMode,0
        STRUCT  esm_Node,LN_SIZE
        UWORD   esm_Horiz
        UWORD   esm_Vert
        UWORD   esm_Pad
        ULONG   esm_Depths
        APTR    esm_Driver
        STRUCT  esm_Specs,24*4
        LABEL   esm_SIZEOF     

     Here, LN_NAME contains the names of the screenmodes. We start with the
 SECOND element again...

     We look in this list for a screenmode that uses the driver we found
 before, and supports the Horiz, Vert and Depths values we want...
 Depths in this case is a bit-wise representation, so a set bit says
 this deptch is available.  By the way, we can assume every EGS board
 is capable of 24 Bit and 8 Bit displays...

     If you want to examine Synchs or Monitor Specs, you have to look
 at the array of E_MonitorSpec (esm_Specs), but I do not want to go
 THAT MUCH into detail.  You could use this to compare if this screenmode
 REALLY displayable on the given monitor, for example...

     So, lets assume we found a screenmode that fits... then, and only
 then, we can assume, we can open a Screen.  We will now open an
 E_EScreen which is basically some video memory allocated on the board.
 It does not support higher EGS constructs like Windows for example,
 but we want something FAST ...

     Now we need a E_ENewScreen structure...

 move.l #ens_SIZEOF,d0 move.l #MEMF_CLEAR,d1 move.l $4,a6 jsr -198(a6)
 move.l screenmodename,ens_Mode(a0) move.w Depth,ens_Depth(a0) move.l
 egsbase,a6 jsr E_OpenScreen(a6)

     As next thing we will allocate a doubble buffering bitmap. Be sure
 all fits in the display memory, if you use 24 Bit displays...
 for doubble buffering you need of course display memory for BOTH
 displays on your board...

 move.w Width,d0 move.w Height,d1 move.w Depth,d2 move.l type,d3 ; colour
 model, described below... move.l #0,d4 add.l #E_EB_DISPLAYABLE,d4 add.l
 #E_EB_BLITABLE,d4 add.l #E_EB_SWAPABLE,d4 add.l #E_EB_CLEARMAP,d4 move.l
 screen,a0 move.l esc_Map(a0),a0 ; The FRIEND BITMAP move.l egsbase,a6 jsr
 E_AllocBitMap(a6)

     Now we are nearly finished.  We still have to LOCK the screen (so
 EGS does not put the screen to Fast RAM while we are writing directly
 to video memory (there will be some strange results, if you switch back
 to the WB-Emu while our program runs... ghost pics... but do not
 bother...)

 move.l screen,a0 move.l esc_Map(a0),a0 add.b #1,ebm_Lock(a0) move.l
 BackBitMap,a0 add.b #1,ebm_Lock(a0)

     After locking the system needs some time to make the change happened.
 You should do a delay of about 0.1 seconds (for example dos.library
 Delay with a value of 5 ...), else you risk some crashes...

     After that you can write to the two bitmaps :

 move.l screen,a0 move.l esc_Map(a0),a0 move.l ebm_Plane(a0),a0 move.l
 #$ff000000,(a0)

     For example... the colour model used is RGBx per default, or, if
 you specify a custom bitmap, you can use xRGB too... in 8 Bit
 a standard chunky colour model (in 1 Byte) will be used...
 the x is for the Alpha channel... but sadly, I have no documentation
 for this, so ignore it... the constants for the type are found
 in the EGS autodocs (orion.etsu.edu is a site where they can be
 found... or contact INGENIEURBUERO HELFRICH, the makers of the Piccolo
 and Piccolo SD64 boards...

     To unlock, just subtract from the Lock values again... for unlocking
 you do not need to vaste processor time like it is done while locking.

     The next thing we do is Double Buffering.

 move.l screen,a0 move.l BackBitMap,a1 move.l egsbase,a6 jsr E_FlipMap(a6)
 move.l d0,BackBitMap

     The flip will happen after the next vertical blank interrupt.  And as
 I said before: In C I got some graphics errors, strange thing, but in
 Assembler it worked perfectly and consumed almost no time...

     Functions for EGS board blitter support are in the egsblit.library,
 but those are self explaining.  If you have difficulties, feel free
 to send me mail. In egsalphablit.library there are blitting functions
 for Alpha channel... but it seems nobody has documentations for
 them :((( Not even the coders of EGS ...

     Do not use any Pixelsetting functions of the libraries. If you do it
 yourself with this ebm_Plane-thing you will be MUCH faster...And,
 remember, you will need EGS V.6 includes... I will provide my EGS V.6
 Bitmap structure here (self-made :) )

 STRUCTURE  E_EBitMap,0
        WORD    ebm_Width
        WORD    ebm_Height
        UWORD   ebm_BytesPerRow
        BYTE    ebm_Depth
        UBYTE   ebm_Type

 * Enumeration type descriptor for access to union fields

        APTR    ebm_Plane
        BYTE    ebm_Lock
        UBYTE   ebm_Display
        UWORD   ebm_Pad0
        ULONG   ebm_Pad1

        STRUCT  ebm_BitPlanes,24*4  ; because Ptr size is 4 Bytes
                                    ; in C BitPlanes[24]
        APTR    ebm_Colors
        ULONG   ebm_Flags
        APTR    ebm_Class
        LABEL   ebm_SIZEOF   

     If you need another structure of EGS, and only have V.5 ASM-include,
 try to get the ASM-includes out of the V.6 C-Includes ... or send
 me mail, maybe i have the correct includes...

 Closing the Screen:

 move.l screen,a0 move.l egsbase,a6 jsr E_CloseScreen(a6)

 Closing the BackBitMap :

 move.l BackBitMap,a0 move.l egsbase,a6 jsr E_DisposeBitMap

     And remember : Before closing the screen, the CORRECT Bitmap has to be
 in front again... if not, perform an additional Double Buffering followed
 by a

 move.l screen,a0 move.l egsbase,a6 jsr E_WaitTOF(a6)

     Okay, that's all about EGS. All the examples are taken from my code
 about the EGS version of rtg.library.  So you will get a much easier
 interface, as soon as rtg.library is finished.

 B) Cybergrafix

     Cybergrafix supports a function to get some information about the 
 (modified) Bitmap structure, but (sadly) you do not get the adress of the
 video memory.  So you can't write directly to the video memory, if you do
 not have the specs of the used board, but you have to use Cybergrafix as
 WB-Emulation.  But, luckily, Cybergrafix is quite fast.

     Cybergrafix supports some very fine functions to select a screenmode,
 for example BestCModeIDTagList, which gets the best screenmode for a
 specified tag list of screen attributes.  In EGS you had to do this
 yourself (some additional advertising: In rtg.library you have not 
 to do it yourself, either... like in Cybergrafix, but with directly
 writing to the video memory...)

     For writing pixels, reading Pixels and blitting,  there are the 
 functions FillPixelArray, MovePixelArray, ReadPixelArray, ScalePixelArray,
 SwapPixelArray, WritePixelArray and WriteRGBPixel.  I think what they do 
 is quite clear.

     For double buffering you use standard Double Buffering functions
 like the functions around AllocScreenBuffer.  Cybergrafix is a very
 compatible and fast WB-Emu.

     As color models you are able to use a LOT of them (look at your 
 Cybergrafix developping docs).  As I am no expert in Cybergrafix, that is
 all about it now.  I do not know how good the graphics board blitter
 support for Cybergrafix is.

     So, at the end of this article, I wish you fun and success with your
 programming of Amiga graphics boards. And i hope, we soon will see some
 games or demos using graphics boards.  Support them...
