
			Skal's own GFX library
	
				or

		" Yet another Dig-If-You-Dare Paradigm "


                            test-version 0.4


	Yep, that's the sources of the library I use while doing graphics.
	It's (rather) fast, compiles (hopefully?) under Unix/X11,
	PC-Linux/X11/DGA, and DOS/DJGPP. Most portable version uses UNIX
	and X11Rx calls only. If you have DGA supported by your X11 
	server (e.g.: XFree86 >= 3.2), it'll be ok too. Also (hastily)
	supported is the interfacing with the SVGALIB.But it's still
	experimental...

	Under DOS, it compiles with DJGCC and uses as default VBE2.0 drivers.
	VESA1.2 will be OK too, but you won't take advantage of LFB speedup.
	Specific drivers for special video boards (S3/ET?000/etc...) are in
	progress... Use HIMEM only, as a configuration, for safety.
	It'll work under DOSemu too, at least only for VGA modes.
	Bank switch isn't implemented. And using LFB will probably fail
	because of physical mapping being denied by the kernel... With
	color convertion (see below), it'll run a little slower, though...

	The code is rather messy (too much use of copy-paste, you know :),
	but I'll clean that all soon... Moreover, it's only an excerpt of
	a bigger lib. Hence the obfuscation...:) Oh well... 

COMPILATION:

	./lib contains pre-compiled .a libs for PC-Linux (lib_sll.a,
	compiled without the SVGALIB driver) and DJGCC (lib_sl.a). 
	(genuine-Unix lib will be named lib_slu.a - cf. makefile - 
	but isn't distributed in the archive...)
	You can use them directly, along with the ./example/sl.h
	header file.

	If you want to recompile (genuine Unix/X11, for instance),
	just type:

	   make dos		/* for DOS/DJGCC */
	or make unix		/* for genuine UNIX/X11 */
	or make linux		/* for PC-Linux/X11 */

	Under PC-Linux, if you want to use the SVGALIB, since the
	*.a lib files are not distributed here, then you'll have to:
	   * Make a link, in the ./lib directory, pointing to
	the libvga.a and libvgagl.a library files... Otherwise,
	you can change the references to these files in the
	main ./makefile
	   * In the ./lib_src, there is the vga.h, vgagl.h and vgamouse.h
	header files corresponding to the version 1.29 of the
	SVGALIB... If you're using a more recent one, replace
	them...
	   * type: make svgl

		----------------------------

	if it's ok, ./lib should now contain the right static lib.
	./example should contain some little examples ( named: testm
	vid vid3 vid4 and strange )
 
	Note: To compile under DOS, you need a complete DJGPP v2.1
	package: gcc + make ( + unix-like file utilities... otherwise,
	you'll have to dig into the makefile...)

	Note2: Color convertion (see below) isn't implemented for
	DOS/VBE2.0 and SVGALIB, because of laziness :) (actually,
	with those systems, you're not stuck with a fixed display
	depth, so, with a little bit of luck, there'll be a video
	mode corresponding to your desires... (unless you ask for
	some strange modes like 499:319:0x725)... Oh well...:)

HOW IT WORKS:

   Linking:

	* ./example/sl.h contains the public header for the lib. Make 
	sure gcc can find it (-I option).

	* The only thing you have to change in your source or your makefile
	when compiling is to #define the following:

	 #define DOS	/* if you're compiling under DOS/DJGCC */
	or
	 #define UNIX	/* if you're using genuine UNIX/X11 */
	or
	 #define LINUX  /* if you're running PC-Linux/X11 w/out DGA */

	Under LINUX, if you want the SVGALIB to be used, put an
	additional:
	 #define USE_SVGALIB

	The rest of your code won't need being changed. Cool, huh ?! :)

   Running:

	* Under DOS: just use HIMEM as configuration, for safety...

	* Under Linux/DOSemu: 

	Most probably, you'll need a 2.1.x kernel and a recent
        version of DOSemu (0.66.5?) to avoid problems.
	Don't forget to tune your /etc/dosemu.conf correctly !! I had
	most problems because of badly-set options in there. Just some
	hints to avoid problems:

	   - Turn the 'secure' option *OFF*. Otherwise no DPMI, no
	(wild :) far pointers, etc...
	   - Use rather big amount of dpmi mem (esp. for compilation). 
	For instance, my settings are:

		dpmi 16384
		xms 4096
		ems 4096

	A 'dosmem' value of 640 seems to be ok...

	  Last: don't forget to be root when running DOSemu !

	Note: I haven't tried it with the X11 version of DOSemu... At least,
	it runs ok in a Linux virtual console... well...


	* Under X11/DGA: If you want to use DGA, you'll have to be suid root...
	Therefore, log on as root, or use a s-bit'ed executable...


API:

   Structures:
   ###########

	* the struct _G_DRIVER_ contains methods about the graphic
	drivers. 4 are currently defined:

		_G_DGA_DRIVER_, _G_X11_DRIVER_,
		_G_SVGL_DRIVER_, and _G_VBE_DRIVER_.

	You can register the ones you want to use via Register_Video_Support()
	(see below).

	Note: If used, *do* declare the _G_SVGL_DRIVER_ (the SVGALIB
	driver) LAST, because the SVGBLIB is a bit rough concerning
	detection and will exit() if the program can't use it
	(e.g.: not suid root, not in a virtual console...)
	Moreover, SVGALIB seems to have problems with video
	modes greater than 640x480... Use with care :(


	* the type MEM_IMAGE is a shadow for a (very) general struct I
	use to manipulate data in my progs. In particular, it will contains
	the infos about your displayed bitmap. Everything is setup via
	the Driver_Call() call.


   Functions:
   ##########

	  void Register_Video_Support( INT Nb, ... );
          -------------------------------------------

	This will register the graphic drivers to be tested for, and used if
	available. They will be tested/used in the order they are passed to
	this function. The first argument 'Nb' indicates how many _G_DRIVER_ 
	arguments follows. 
	Ex:
	   Register_Video_Support( 3, _G_DGA_DRIVER_, _G_X11_DRIVER_, _G_VBE_DRIVER_ ); 

	   This means that you want X11/DGA, X11/windows and VBE2.0 to be
	   supported (in this order) when opening the display (in Driver_Call().
	   See below. )




	  MEM_IMAGE Driver_Call( _G_DRIVER_ Driver, ... );
          ------------------------------------------------

	This is the main (and only ?:) call for setting up everything.

	The first argument is a specific _G_DRIVER_ you want to use.
	If NULL, then the ones registered via Register_Video_Support() will
	be tested and used.
	After this first argument comes variable keywords list telling the
	driver what you want him to do. This list is determinated by
	the DRV_END_ARG keyword.
	The protocol is a bit akward, because of the demo-orientated-ness
	of my lib. You will have to tell the driver all the 'video-modes'
	you want being available. Driver_Call() will test if your
	request can satisfied, even at the price of a (slow) convertion
	between the video-mode you want and available display capabilities.

	* DRV_MODE keyword and video-mode specification:

	A 'video-mode' is given by its width, height, and pixel format.
	Pixel format can be either 'RGB' or 'Colormap'. It is coded with
	a 16bits number written in hexadecimal as 0xFRGB. 
	R, G, and B are number between 1 and 8 telling the number of bits
	used for the Red, Green and Blue channel respectively. F is a number
	between 0 and 4 telling how much bytes are used per pixel. If 0,
	then this information will deduced by adding the R,G, and B bits
	to find minimal bytes needed by a pixel. This is to circumvent
	some card specificities: for instance, my S3 uses 32bits to hold
	24bits RGB modes. 8 bits are unused, then. 
	For colormapped display, the format is 0x0, meaning that there
	is no RGB at stake here.
	The video modes (width+height+pixel format) are passed to
	Driver_Call() via a character string that will be parsed. I found
	this method more useful... well...
	Some examples, since the above isn't really clear: :)
	  . "640:480:0x565" is the string describing the 640x480 video mode,
	with 65536 RGB colors.
	  . "800:600:0x0" is the colormapped SVGA 800x600 mode 0x103.
	  . "320:200:0x4888" is the 320x200 mode with 24M colors coded
	with 32bits instead of common 24bits.

	Ok, now you can tell Driver_Call() which modes you like to be 
	available, by using the argument DRV_MODE followed by the,
	';'-separated, string of this modes. For instance, if you want
	the 320:200:0x0 (aka. VGA 0x13) and 640:480:0x555 mode to be
	tested for, use:
	   Driver_Call( NULL, DRV_MODE, "320:200:0x0;640:480:0x555;", DRV_END_ARG );

	Note: you can use the wild card '?' for the width, height, and
	pixel format... For instance, under X11, passing "320:200:?" will
	use as pixel format the one the X11-server was actually launched
	with... Up to you to take into account this format as it is
	returned...


        * DRV_DETECT: This keyword will tell Driver_Call() to only detect
	video mode availability, but not to switch to any of them.
	Otherwise, Driver_Call() will open the first video-mode you passed
	throught DRV_MODE keyword. 


	* DRV_CONVERT: This keyword will tell Driver_Call() to allow (slow)
	convertion if one of the requested video-mode isn't available.

	* DRV_PRINT_INFO: will output some infos about display and modes

	* DRV_NAME: (only under X11/windows) the window's name will be
	the character string just following this keyword.

	* DRV_DONT_USE: followed by a bitwise OR'ing of the following:

	    _INT_10h_	  /* DOS only: int( 0x10,..) call for bank switch */
	    _RM_BNK_SW_	  /* DOS only: Real mode call for bank switch */
	    _PM_BNK_SW_	  /* DOS only: Protected mode call for bank switch (VBE2.0) */
	    _SPEC_BNK_SW_ /* DOS only: specific bank switch (S3 driver, ...) */
	    _LFB_	  /* DOS only: Linear frame buffer (VBE2.0) */
	    _SPEC_LFB_	  /* DOS only: specific linear frame buffer (S3 driver, ...) */
	    _VGA_MODE_	  /* DOS only: VGA modes (and X-modes) */
            _SHM_	  /* X11/windows only: don't use shared memory */
	    _X_WINDOWS_   /* X11/windows only: don't use classic X11 windows */

	will tell which refresh method _not_ to use, even if available.

	* DRV_DISPLAY: (X11 only) followed by a string will tell which
	DISPLAY must be passed to XOpenDisplay(), instead of the 
	corresponding environment variable.

	Don't forget to terminate the keywords (+arguments) list by DRV_END_ARG !


	Hmm... maybe you should have a look at the ./example/*.c files
	files, for I doubt the above is very clear :))

	Upon success, Driver_Call() should return a MEM_IMAGE pointer to a 
	struct containing all the display infos. The required video-modes 
	are stored within in the order you passed them in the string 
	following the DRV_MODE keyword. You now will be able to switch from
	one mode to another with the Driver_Open_Mode() call (see below).


	  MEM_IMAGE Driver_Open_Mode( MEM_IMAGE M, INT Nb );
	  --------------------------------------------------

	This will switch to the video-mode number Nb that you requested in
	Driver_Call(). If you pass 0 as Nb, then you will switch back
	to text mode. M is the MEM_IMAGE pointer returned by Driver_Call().


	  void Driver_Close( MEM_IMAAGE M );
	  ---------------------------------

	Closes and clears everything. M is the MEM_IMAGE pointer
	returned by Driver_Call().


	  Driver_Print_Error( );
	  ----------------------
	if something went wrong you can call this function to print
	an error message. 



   Accessing MEM_IMAGE fields:
   ###########################

	The following functions can be used to access some of the fields in 
	the MEM_IMAGE pointer returned by Driver_Call():


	  Driver_Nb_Req_Modes( MEM_IMAGE M );
	  -----------------------------------
	Returns the number of requested video modes ( via DRV_MODE in
	Driver_Call() ) or -1 upon error.


	  Driver_Nb_Cur_Modes( MEM_IMAGE M );
	  -----------------------------------
	Returns the number of the current video mode or -1 upon error.

	  INT Zone_Width( MEM_IMAGE M );
          INT Zone_Height( MEM_IMAGE M );
	  FORMAT Zone_Format( MEM_IMAGE M );
	  ------------------------------
	Respectively returns Width, Height (in pixel, not bytes), and format
	of the MEM_IMAGE returned by Driver_Call();

	  INT Zone_BpS( MEM_IMAGE M );
	  INT Zone_Pad( MEM_IMAGE M );
	  INT Zone_Size( MEM_IMAGE M );
	  -------------------------
	Respectively returns the number of bytes per scanline, the number of
	pixels needed by each scanline to be, at least, padded to 8, and the
	total size in bytes, of the MEM_IMAGE returned by Driver_Call();

	  INT Zone_Quantum(MEM_ZONE*);
	  ----------------------------
	Returns the quantum, i.e. number of bytes, needed for 1 pixel.


	  ....

   Displaying something:
   #####################

	Q: All right, but how do I draw my nice 0.5-VBL effect in the
	MEM_IMAGE that Driver_Call() returned me, huh !?

	1) to get a pointer to j-th scanline of the MEM_IMAGE M, use the call:

		PIXEL *Zone_Scanline( MEM_IMAGE M, INT j );

	This will return NULL if j wasn't correct.

	Please, _do_ use this call before every drawing in MEM_IMAGE M, because
	the base pointer of M *may* change 'randomly'. This is especially true
	under DJGPP, because of whole memory un-protection (__djgpp_conventional_base
	may change after a malloc(), a system(), or a printf() call that
	scrolls the screen, for instance... ).

	2) Once you have the pointer returned by Ptr = Zone_Scanline( M, j ), 
	you can draw inside with `Ptr[x] = My_Nice_Pixel;` provided x ranges
	between 0 and Zone_Width( M )*Zone_Quantum( M );

	3) If you want to get to the next scanline, you can call again
	Zone_Scanline( M, j+1 ), or add to the previous pointer the
	number of bytes per scanline returned by Zone_BpS( M ).

	4) Once you're finished, call the:

			Zone_Flush( MEM_IMAGE M );

	function to put everything on the screen. Use this one only if you're
	sure that all the image lies on its destination one. Otherwise, call:

			Zone_Flush_Safe( MEM_IMAGE M );

	This will perform clipping if necessary. 

	You can also call

		Zone_Propagate( MEM_IMAGE M, INT X, INT Y, INT W, INT H );

	to only refresh the rectangle defined by the upper-left corner (X,Y)
	and by the width W and height H.



	  INT Driver_Change_CMap( MEM_IMAGE M, INT Nb, COLOR_ENTRY *CMap );
	  -----------------------------------------------------------------

	If your video-mode M is colormapped, this will set the color map.
	COLOR_ENTRY is structure typedef'd as an array of 4 bytes:

	. CMap[i][RED_F], CMap[i][GREEN_F] and CMap[i][BLUE_F] are the 3
	RGB component (between 0 and 255 ) of the i-th color entry of the
        colormap.
	. CMap[i][INDEX_F] is the index of the color (between 0 and 255)
	in the final colormap. For instance, if you only want to change
	the 49th color, call Driver_Change_CMap( M, 1, CMap ), where
	CMap points to a color entry having its INDEX_F field set to
	49.
	. Nb is the number of colors in CMap to be install in final colormap.



	Once again, better have a look at ./example/*.c    :)

STILL TO DO/BUGS:

	 * fix the makefile(s)
	 * a cool 'configure' script and/or Imakefile...
	 * make the library dynamic
         * With SHM, use the provided little script `ipc2` to remove pending
           shared segments, if `ipcs` says there are...
	 * Event management bugged...
	 * cvrt_col.c would appreciate being translated in ASM, for speed
	 * under DOS, X-Mode are crippled... Try modes < 320x200 at your
	   own risks. :) Gotta fix the outs in drv_vga.c
	 * Fix memory leak ( try compiling with DEBUG_MEM defined, for memory info... )
	 * there's Indians problems (under Unix)...
	 * ...

	 * Re-write this doc


CONTACT:
	e-mail: Pascal.Massimino@ens.fr
	WWW:    http://www.eleves.ens.fr:8080/home/massimin/
	IRC:    often on #demofr


			Hope it helps,

						Skal
