home *** CD-ROM | disk | FTP | other *** search
- CBGI - C shell for BGI drivers
-
- This is the documentation for a shell that can be used to write BGI
- drivers using C. This documentation is not intended as a replacement
- for Borland's documentation and in fact will refer to it from time to
- time for further explanation.
-
- WHY USE CBGI?
-
- The CBGI library provides an interface layer that converts the
- register passing calling convention of the BGI interface to a
- 'normal' C stack based convention. It also switches to a local stack
- so that the driver routines may written in C and compiled with full
- optimization in a normal fashion. Also included with this library
- is a (are) sample working driver(s) with complete source code. Usually
- the quickest way to get a driver up and running is to modify this
- sample code to suit the adapter you are writing for. This code may
- then be improved to better suit the driver. Although it is possible
- to write the entire driver in C you may want to recode small sections
- in assembler to provide a performance boost, or to provide additional
- capabilities to the default driver.
-
- In case this sounds too good to be true there are a couple of
- limitations to using the shell. The working stack is quite small
- (~512 bytes). It can be adjusted by modifying and recompiling
- 'stack.asm'. This stack size should not usually be a problem (if it
- is you should probably consider making some of your automatic
- variables statics). The second limitation is that every call to the
- driver results in a stack switch. While this will be insignificant if
- each call does enough work it can add up. As a matter of practical
- use I haven't found it to add significantly to the overhead in
- performing the actual task and the overhead imposed by the BGI
- kernal.
-
- WHAT DOES IT COST?
-
- Under most circumstances nothing. The package is free to use under
- most circumstances. I am placing some restrictions on use, but they
- should not be too onerous. I am asking that you send me copies
- (preferably with source) of any drivers you make. I will collect
- them and include them in subsequent distributions of this kit. These
- will be available directly from me for a modest fee to cover disk
- copying and mailing (or just wait until they reach a Bulletin Board
- near you).
-
- Restrictions
-
- If you write a program that you wish to ship one of the drivers
- included in (or develop with) this kit with, you must include the
- entire kit or provide an easy way to get it (In the case of shareware
- it might be part of the benefit for registering). If for some reason
- you only wish to include one driver contact me and arrangments can be
- made.
-
- PURPOSE OF THIS DOCUMENTATION
-
- What it is not.
-
- This document is not meant to replace Borland's documentation on BGI
- drivers. It is also not meant to explain how various adapters work
- or how to program any adapter.
-
- What It is meant to be.
-
- This document is meant to explain the set of C shell routines that I
- wrote as result of my experiences with Borland's documentation and
- example driver. It explains the shell routines only sketchily. The
- main documentation for the purpose of these routines is Borland's
- documentation. I am only providing information on how the parameters
- passed to the driver are presented to the C routines you must write.
- I only provide additional documentation when I have run into points
- that I found needed clarification.
-
- The utility functions I have created are more fully documented.
-
- Since this documentation is being written in my spare time it will
- probably improve and grow more complete as time goes on. Suggestions
- on what points need to be clarified are welcome (as long as they are
- basically friendly).
-
- Documentation on the driver(s) accompianing this are with the
- driver(s) themselves. Note that the driver source code is an
- important source of documentation for this library in itself.
-
- USING THE CBGI LIBRARY
-
- The CBGI library consists of two distinct interface components.
- The startup object module c0cbgi.obj is a replacement for the
- c0x.obj's used by TC. It provides the tables used to branch to the
- appropriate routines and also the stack switcher. It used in the
- same manner as the c0x.obj's provided by Borland are. The second
- component of the CBGI library is the interface routines that convert
- the register based calling convention of the BGI to a stack based
- one. These are documented below.
-
- Some of the routines in a BGI driver may be emulated by the BGI
- kernal. The default startup shipped with this library sets up
- emulation for all the calls that can be handled that way. The
- assembly module c0cbgi.asm must be edited and recompiled in order to
- change this.
-
- All the interface routines are written using TASM's ideal mode.
- Some modifications will be necessary if you wish to compile them
- using another assembler.
-
- INTERFACE ROUTINES
-
- 1) Required functions -- These routines are required in any driver.
- See Borland's documentation and the example driver(s) for details on
- how these functions should be written. Most of the interface
- routines use the same names that Borland give the dispatch vectors in
- their documentation, so that cross referencing between their
- documentation and mine should be fairly simple.
-
- void allpalette( unsigned int pptr_offset, unsigned int pptr_segment);
-
- Restore the entire palette. The BGI kernal seems to restrict the
- use of this function to palettes that contain <= 16 colours.
-
- void *bitmaputil( void );
-
- Return a pointer to the bitmap utility table. Yes that is a regular
- pointer, it is converted to a far pointer by the interface routine.
- This table consists mainly of function pointers. A set of interface
- routines exist for these too, see the later documentation on these
- and the example driver(s) for more information.
-
- void clear( void );
-
- Clear the screen.
-
- void color( char new_fill_colour, char new_draw_colour );
-
- Set the colours used by the driver.
-
- long color_query( char command_type);
-
- Query the colour table. In the case of a palette size query the
- upper half of the long contains the maximum colour number and the
- lower the number of colour table entries. Otherwise only the lower
- half is used.
-
- void draw( int x, int y);
-
- Draw a line to x, y.
-
- void fillstyle( char pattern, unsigned int pptr_offset,
- unsigned int pptr_segment);
-
- Set the fillstyle for later fill operations.
-
- void floodfill( int x, int y, unsigned char boundary);
-
- Perform a floodfill. Note that this is not implemented in the
- example driver (it's a null function).
-
- char get_pixel( int x, int y);
-
- Read the pixel at x, y.
-
- void init( unsigned int dit_offset, unsigned int dit_segment);
-
- Initialize the driver to the mode requested. Initialize all
- varaibles that need it.
-
- IMPORTANT NOTE!! Do NOT! assume that uninitialized global variables
- will be zero. There is nothing in the startup to ensure that.
-
- long install( unsigned int mode, char command);
-
- Initialize the driver (and save requested mode). This is called
- before init.
-
- IMPORTANT NOTE!! Do NOT! assume that uninitialized global variables
- will be zero. There is nothing in the startup to ensure that.
-
- void linestyle( char style, int pattern, int width);
-
- Set the style for drawing lines.
-
- void move( int x, int y);
-
- Move to x, y.
-
- void palette( int flag_index, int red_colour, int blue, int green);
-
- Set a palette entry.
-
- void patbar( int x1, int y1, int x2, int y2);
-
- Pattern a rectangular area.
-
- void post( void );
-
- Exit from graphics mode. Essentially the inverse of init.
-
- void set_pixel( int x, int y, char colour);
-
- Draw a pixel.
-
- void restorebitmap( char mode, unsigned int segment, unsigned int offset,
- int x1, int y1, int x2, int y2);
-
- Restore a previously saved bitmap. Note that x1 & y1 do not mean
- anything. they were based on comments in Borland's documentation
- that implied that si & di contained usefull information for this
- function. Use x2 & y2 and the information stored in the bitmap to
- determine it's size. See the example(s) for more details.
-
- void savebitmap( unsigned int buff_segment, unsigned int buff_offset,
- int x1, int y1, int x2, int y2);
-
- Save a bitmap for later restoration. See previous comment about
- x1, y1. The BGI kernal appears to use the bits_per_pixel entry of the
- bitmap utility table to determine the size of the block for this.
-
- void setclip( int x1, int y1, int x2, int y2);
-
- Set the clipping area.
-
- void text( int length, unsigned int offset, unsigned int segment);
-
- Print bitmap text.
-
- long textsiz( int length, unsigned int offset, unsigned int segment);
-
- Determine the size of the text string (in pixels).
-
- long textstyle( char number, char path, int xsize, int ysize);
-
- Set the style to draw the text in.
-
- void vect( int x1, int y1, int x2, int y2);
-
- Draw a line.
-
- 1a) Required functions (Bit Map Utility Table) -- Contrary to the
- documentation these routines appear to be required in any driver. And
- they are not used to emulate ellipses. See Borland's documentation
- and the example driver(s) for details on how these functions should
- be written. Most of the interface routines use the same names that
- Borland give the dispatch vectors in their documentation, so that
- cross referencing between their documentation and mine should be
- fairly simple. The address loaded into the Bit Map Utility table
- should not be the addresses of these functions but of the assembly
- language interface functions. The interface functions have the same
- name except that they begin with dispatch_. So the entry in the
- table for bits_per_pixel will be dispatch_bits_per_pixel (see the
- example(s) for details.
-
- int bits_per_pixel( void)
-
- Yes, this is a function not a number.
-
- void enter_graphics( void);
-
- Enter special graphics mode for fast pixel drawing.
-
- char getpix( int x, int y);
-
- Get pixel colour.
-
- void leave_graphics( void );
-
- Leave special graphics mode.
-
- void putpix( int x, int y, char colour);
-
- Draw pixel.
-
- void set_page( char page);
-
- Set drawing page.
-
- void set_visual( char page);
-
- Set the visible page.
-
- void set_write_mode( int mode);
-
- Set the drawing mode.
-
- 2) Optional functions -- These are functions that can be emulated.
- The default startup shipped with the library does emulate these. In
- order to use these functions the startup will have to be modified.
- Note that these dispatch routines are not as throughly tested as the
- others. See Borland's documentation and the example driver(s) for
- details on how these functions should be written. Most of the
- interface routines use the same names that Borland give the dispatch
- vectors in their documentation, so that cross referencing between
- their documentation and mine should be fairly simple.
-
- void arc( int start_angle, int end_angle, int x_radius, int y_radius);
-
- Draw an arc.
-
- void bar( int x, int y, int depth, int top);
-
- Draw a 3D bar.
-
- void filled_ellipse( int x_radius, int y_radius);
-
- Draw a filled ellipse.
-
- void pieslice( int start_angle, int end_angle, int x_radius, int y_radius);
-
- Draw a pieslice.
-
-
- SUPPORT FUNCTIONS
-
- bgipline.h
-
- This is at one and the same time the most general and the most
- unusual of the support functions. It is in fact a header file that
- contains the source code for a line drawing function. It is written
- to use several macros to draw the points of the line. The main line
- drawing code itself is device independant. Macros are used rather
- than functions since the overhead of a function call in an inner loop
- can be substantial. The macros themselves are designed to take
- advantage of any speed increase available from knowing all address
- changes are + or - 1 in the row or column. The macros needed are:
-
- CALC_ADDR( x, y) Calculate the address of the point at x, y.
- X_INCREMENT_CALC() Calculate the address of a point one column
- further along (x++).
- Y_INCREMENT_CALC() Calculate the address of a point one row
- further along (y++).
- Y_DECREMENT_CALC() Calculate the address of a point one row
- less further along (y--).
- XOR_POINT( colour) Xor a point of colour at the current address.
- POINT( colour) Plot a point of colour at the current
- address.
-
- This routine also assumes the presence of 'current_line_style',
- 'current_write_mode' and 'line_style_mask' as defined in the example
- driver.
-
- There is also a set of block transfer functions that perform copies
- from a block of source memory to a block of destination memory. If
- the source is smaller than the destination the copy 'wraps around' to
- the beginning of the source until the destination is filled. These
- routines perform this copying using various logical operations
- between the source and the destination.
-
- These block operations are optimized to do 16 bit transfers on word
- boundaries in the destination. This should have little effect on 8
- bit adapters/buses but could mean up to a factor of 4 on 16 bit buses
- (on the other hand it may not help at all, but at least it won't
- hurt). These functions are strictly memory to memory operations,
- they do not attempt any adapter specific operations.
-
- In the following routine definitions the parameter names use the
- following conventions.
-
- source -- The area of memory serving as the source.
- destination -- The area of memory serving as the destination.
- src_size -- The size of the source memory area.
- dest_size -- The size of the destination memory area.
-
- void copy_mem( void far *source, int src_size, void far *destination,
- int dest_size);
-
- Copy the source to the destination.
-
-
- void xor_mem( void far *source, int src_size, void far *destination,
- int dest_size);
-
- Xor the source with the destination.
-
-
- void or_mem( void far *source, int src_size, void far *destination,
- int dest_size);
-
- Or the source with the destination.
-
-
- void and_mem( void far *source, int src_size, void far *destination,
- int dest_size);
-
- And the source with the destination.
-
-
- void neg_mem( void far *source, int src_size, void far *destination,
- int dest_size);
-
- Neg the source and copy to the destination. This does not modify
- the source.
-
-
- void set_mem( void far *destination, unsigned dest_size,
- unsigned value);
-
- Set the destination to the value contained in value. This function
- has several peculiar features. If the size to be set is passed as
- zero then a full 64K will be set. The second peculiarity is that the
- 'word' value is placed in memory not just it's lower byte. That
- means that a value of 0x0101 sets all the bytes to 1 but a value of
- 0x01 sets every second byte to 1 and the others to zero.
-
- Extended Memory Functions.
-
- A number of specialty boards designed for the AT are mapped into
- extended memory in order to avoid crowded regular memory. Since
- programs running in real mode under DOS cannot normally access this
- memory this presents a potential problem.
-
- There are two solutions. 1) Switch the driver to and from
- protected mode (difficult to do portably) or 2) use the BIOS calls
- to copy memory blocks to/from extended memory. Most AT class (or
- better) machines should support the BIOS calls so that approach
- should be more portable. Two library functions have been provided
- to call these BIOS functions properly.
-
- int copy_from_extended( void far *destination, unsigned long source,
- int words);
-
- Copy a block of memory from extended memory to conventional
- memory. The source address is an absolute address (number of bytes
- from the beginning of the precessors address space). Note that
- this function moves words (ints) not bytes.
-
- int copy_to_extended( unsigned long destination, void far *source,
- int words);
-
- Copy a block of memory from conventional memory to extented
- memory. The destination address is an absolute address (number of
- bytes from the beginning of the precessors address space). Note that
- this function moves words (ints) not bytes.
-
-
- WRITING A DRIVER
-
- The best way to write a driver is probably to use an existing driver
- as a template. Even if most of the adapter specific code has to be
- changed this will ensure that all the necessary routines have been
- written (and that all the conditions that are in effect have been
- taken into account).
-
- COMPILING THE DRIVER
-
- The driver is compiled in a normal fashion using tcc. It must be
- compiled in the tiny model and the floating point should be
- disabled. The floating point should be disabled since the driver
- startup lacks the necessary hooks required to support the emulator.
- See the makefile supplied for an example.
-
- Other than those two restrictions all the standard compiling options
- can be used.
-
- The link step is also very normal. The startup used is C0CBGI.OBJ
- and the floating point emulation, math and graphics libraries should
- not be linked in. The library CBGI.LIB contains the interface and
- helper routines used by the drivers.
-
- After creating the tiny model driver use the utilities supplied in
- Borland's BGI driver kit to create a driver from it.
-
- DEBUGGING A DRIVER
-
- There are several ways to debug the code for a driver. The first
- and easiest way is to write a shell program that calls the driver
- subroutines directly without putting them in a driver. The advantage
- of this approach is that none of the debugging information is lost
- and the resulting code can be easily debugged with 'printf()'
- statements or with TD. Although this approach works well for the
- initial debugging some bugs will only show up when the code is used to
- create an actual driver. Other approaches have to be used to deal
- with that.
-
- The basic problem with debugging a driver is that all the debugging
- information normally available is lost. Normal 'printf' functions no
- longer work since the C stdio library is not available. The program
- can be followed from the higher level BGI calls through the BGI
- kernal and into the driver using TD but the overhead in doing so is
- enormous. This is recommended only as a last resort. The easiest way
- to bypass this overhead is to hard code a break-point interrupt
- (using say geninterrupt(3) into the driver at the point you wish to
- debug the driver. An alternative is to write a low level I/O routine
- to perform the equivalent of 'printf()'. If you have used the first
- debugging approach (shell program), then relatively little debugging
- should be left to do in this fashion.
-
- Of course all of this begs the question of where the output of the
- debugger or the print statments is going during all of this. If you
- use TD it may work just fine recognize the switch to graphics mode
- itself. The best approachs when using TD are either to use a second
- monitor or use TD's remote debugging facility. If you are using print
- statements then they may be redirected to any output device that is
- available. TD is usually the easier approach.
-
- LIMITATIONS ON THE USE OF C LIBRARY FUNCTIONS
-
- While a number of the C library functions can be used in drivers
- and are useful, care must be taken in deciding which ones can be
- used. None of the functions that use memory allocation or depend on
- information gained from DOS during program startup can be used. This
- effectively eliminates most of the stdio functions. Note that a
- number of functions have hidden dependancies on memory allocation.
- Most of the machine specific functions (inport, outport, intr etc.)
- can be used. You can use the library functions productively but keep
- an eye out for hidden pitfalls.
-
- UNIVERSAL AUTODETECT
-
- Also included with this shell is an universal autodetection routine
- that allows a programmer to write a program to use any new drivers
- that will be written without having to know of their existance in
- advance. This routine uses an enviroment variable (BGIDRIVER) to
- determine the driver and mode to use. If the envoroment variable is
- not present then normal detection will be used. The routine provides
- two ways to override this autodection. First passing a driver_no
- other than DETECT will use the inicated driver. In this case the
- detection routine acts just like 'initgraph()'. Second the name of
- the user driver to be used can be passed to the routine directly. The
- rest of the arguments to 'universal_initgraph()' are the same as
- those passed to 'initgraph()'. The prototype of the routine is:
-
- int universal_initgraph( /* Initialize to (possible) user driver.*/
- char *driver_name, /* Name of user driver to use. */
- int *driver_no, /* Either DETECT (if autodetection is */
- /* wanted, or the # of the internal */
- /* driver to use. */
- int *mode, /* Mode to init driver to. */
- char *path /* Path containing the driver. */
- );
-
- This routine may be used as is or as a template for another routine.
-
- DRIVER COLLECTION & KIT AVAILABILITY
-
- This collection of BGI drivers and the CBGI library will be updated
- as I recieve drivers from other people who have created their own. I
- will accept drivers that have been created with or without the
- assistance of this library. I prefer that the source code be
- included but I will not insist upon it. These submitted drivers will
- be distributed under the same restrictions that this library is
- (include all drivers if you include one & make this library easily
- available to those who wish it). Additional restrictions may be
- placed on the drivers by the authours.
-
- I will also make an effort to collect other PD BGI drivers. They
- will be subject to the restrictions imposed by the original
- authours.
-
- These additional drivers will be presented as is. As I have a
- limited number of adapters available I cannot test many drivers. I
- will accept comments about bugs or unusual behaviour in any of the
- drivers and attempt to pass them on to the original authours for
- fixes. If fixes are sent I will also attempt to pass them along.
-
- If you wish a reply to any enquiry please enclose a SASE if mailing
- from CANADA or an International Reply Coupon if mailing from another
- country. Please include the version number both of the library and
- the driver collection.
-
- The most current version of the library and driver collection will
- be available from me for $10 (Canadian). This cost is only meant to
- cover the cost of sending a copy to you. Check the date on the
- collection you now have. Since I am not keeping any drivers out of
- the distribution if the date is recent it is probably not worth your
- money or my time simply to provide you with what you already have.
-
- The Borland BGI kit that provides the documentation on the BGI
- driver and utilities for creating them from '.com' files (which are
- necessary for using this library) are available from you local BBS or
- from Borland directly. I will NOT act as a source for them.
-
- Robert Adsett
- Apt. 2b
- 174 Moore Ave. S.
- Waterloo, Ontario, Canada
- N2J 1X6
-