
	GFXlib 2 - FreeBASIC's gfx library
	----------------------------------

	Copyright (C) 2005 Angelo Mottola (a.mottola@libero.it)



Welcome to GFXlib 2. This library is meant to supply FB with an emulation of
the QB built-in gfx routines, but also to give users more possibilities than
QB provided, like high resolutions and hi/truecolor, MMX optimized routines,
mouse and keyboard (multiple keypresses) handling, transparent PUT support
with clipping done right, multiple offscreen pages in any gfx mode.
It also supports setting up an OpenGL mode so you can do your own OpenGL
coding without worrying about platform dependent initializations.

This document holds a reference of the available functions in alphabetical
order, together with small inline examples where appropriate and with remarked
differences with their QB counterparts. You'll also find some appendices for
special topics. Be sure to have a look at Appendix F, as it provides many
hints and shows some of the new features GFXlib comes with.

Some useful constants are defined in the fbgfx.bi include file for you to use,
you may want to have a look at it, it's in your FreeBASIC/inc directory.
Note that this include file is not mandatory for using GFXlib; it is just
provided to supply some useful constants, nothing more.

Happy coding!


Index
------------------------------------------------------------------------------

Functions reference:
	BLOAD		statement
	BSAVE		statement
	CIRCLE		statement
	COLOR		statement
	DRAW		statement
	FLIP		statement
	GET		statement
	GETJOYSTICK	statement
	GETMOUSE	statement
	IMAGECREATE	function
	IMAGEDESTROY	statement
	INP		function
	LINE		statement
	MULTIKEY	function
	OUT		statement
	PAINT		statement
	PALETTE		statement
	PCOPY		statement
	PMAP		statement
	POINT		function
	PSET		statement
	PUT		statement
	RGB		macro
	RGBA		macro
	SCREEN		statement
	SCREENCOPY	statement
	SCREENINFO	statement
	SCREENLIST	function
	SCREENLOCK	statement
	SCREENPTR	function
	SCREENRES	statement
	SCREENSET	statement
	SCREENSYNC	statement
	SCREENUNLOCK	statement
	SETMOUSE	statement
	VIEW		statement
	WAIT		statement
	WINDOW		statement
	WINDOWTITLE	statement
Appendix A: DOS keyboard scancodes
Appendix B: Default palettes
Appendix C: Internal pixel formats
Appendix D: About speed and size
Appendix E: Internal drivers
Appendix F: Hints



==============================================================================
FUNCTIONS REFERENCE
==============================================================================


+-------+---------------------------------------------------------------------
| BLOAD |
+-------+

Statement to load a block of binary data from a file.


Syntax:
	BLOAD filename[,addr]


Argument:	Description:

filename	Name of the file to load data from.

addr		Address where to load data. If omitted or 0 (NULL), data is
		loaded on the current work page.


Insights:

BLOAD can be used to save a block of binary data, and can be also used to load
raw pixel data to the screen: if you don't specify the addr argument, or you
set it to 0, the data will be treated as pixel data and loaded into the
current work page.

BLOAD "image.bsv", 0

is infact equivalent to:

SCREENLOCK
BLOAD "image.bsv", SCREENPTR
SCREENUNLOCK

Pay attention that the pixel data stored in the file is in the same pixel
format as the one used by the current video mode; see appendix C for details.
BLOAD can also be used to load BMP files; when this is the case, if addr is
zero, the BMP will be loaded on the screen, otherwise it'll be loaded in
GET/PUT format into the specified addr address. In both cases the BMP pixel
data will be converted to the current pixel format, and if the BMP has an
associated palette this will be loaded and set as current palette.
Loading a BMP will fail if a screen mode was not previously set, or if the
image is a truecolor bitmap and the current gfx mode is a paletted mode.


Example:

DIM image(64004) AS UBYTE
SCREEN 13
BLOAD "image.bmp", VARPTR(image(0))
PUT (0,0), image


Differences from QB:

FB version supports blocks of data with sizes bigger than 64K and BMP files
loading.


See also:

BSAVE, SCREEN, GET, PUT, Appendix C.



+-------+---------------------------------------------------------------------
| BSAVE |
+-------+

Statement to save a block of binary data into a file.


Syntax:
	BSAVE filename,addr,size


Argument:	Description:

filename	Name of the file where data will be saved.

addr		Address where to save data from. If 0 (NULL), data is taken
		from current work page.

size		Size of the data block to be saved, in bytes.


Insights:

BSAVE saves a block of binary data into a specified file. It can also be used
to save pixel data from current work page into a file, by specifying 0 as
addr argument:

BSAVE "image.bsv", 0, 64000

is infact equivalent to:

SCREENLOCK
BSAVE "image.bsv", SCREENPTR, 64000
SCREENUNLOCK

When saving pixel data, the data will be saved in the current gfx mode pixel
format; see appendix C for details. Also keep in mind a pixel may require
more than one byte, so the size argument will need to be adjusted accordingly.
BSAVE can also be used to save BMP image files; it is sufficient the specified
filename has a .bmp extension. In this case the size argument is ignored, and
the image dimensions will be deducted automatically from either the screen
mode, either the GET/PUT buffer, depending on if addr is 0 or not.


Example:

none


Differences from QB:

Files saved using the FB version of BSAVE are incompatible with files saved
using the QB BSAVE.


See also:

BLOAD, Appendix C.



+--------+--------------------------------------------------------------------
| CIRCLE |
+--------+

Statement to draw circles, ellipses or arcs.


Syntax:
	CIRCLE [buffer,][STEP](x,y),radius[,[color][,[start][,[end][,[aspect]
								[,F]]]]]


Argument:	Description:

buffer		Buffer were drawing takes place. If omitted, drawing occurs
		into current work page.

STEP		The STEP option specify that x and y are offsets relative to
		the current graphics cursor position.

x,y		Coordinates of the center

radius		Radius 

color		Color attribute. This is mode specific, see COLOR and SCREEN
		for details.

start,end	Start and end angles in radians. These can range -2PI to 2PI;
		if you specify a negative angle, its value is changed sign
		and a line is drawn from the center up to that point in the
		arc. End angle can be less than start angle. If you do not
		specify start and end, a full circle/ellipse is drawn; if
		you you specify start but not end, end is assumed to be 2PI;
		if you specify end but not start, start is assumed to be 0.

aspect		Aspect ratio, or the ratio of the y radius over the x radius.
		The default value is the value required to draw a perfect
		circle on the screen, keeping pixel aspect ratio in mind.
		So this value can be calculated as follows:

		ratio = (y_radius / x_radius) * pixel_aspect_ratio

		Where pixel_aspect_ratio is the ratio of the current mode
		width over the current mode height, assuming a 4:3 standard
		monitor.
		If aspect ratio is less than 1, radius is the x radius; if
		aspect is more or equal to 1, radius is the y radius.

F		If you specify this flag, the circle/ellipse will be filled
		with the selected color. This has no effect if you're drawing
		an arc.


Insights:

Use this function to draw circles, ellipses or arcs. Custom coordinates system
set up by WINDOW and/or VIEW affect the drawing operation; clipping set by
VIEW also applies.
When CIRCLE finishes drawing, the current graphics cursor position is set to
the supplied center.


Example:

' Set 640x480 mode and draws a circle in the center
SCREEN 18
CIRCLE (320, 240), 200, 15
' Draws a filled ellipse
CIRCLE (320, 240), 200, 2, , , 0.2, F
' Draws a small arc
CIRCLE (320, 240), 200, 4, 0.83, 1.67, 3


Differences from QB:

As this function uses a different algorithm from the one used in QB, circles,
ellipses and arcs may not be equal pixel-by-pixel to those produced by QB.
In addition, this version supports filled circles/ellipses via the F flag,
whereas QB doesn't.


See also:

SCREEN, COLOR.



+-------+---------------------------------------------------------------------
| COLOR |
+-------+

Statement to set current foreground/background colors.


Syntax:
	COLOR [foreground][,background]


Argument:	Description:

foreground	New foreground color value.

background	New background color value.


Insights:

The COLOR statement sets the current foreground and/or background colors.
CIRCLE, DRAW, LINE, CLS, PAINT, PRINT and PSET all use the last colors set
by this function when you don't specify a color to them, where applicable.
The color values COLOR accepts depend on the current gfx mode:

Mode 1:
	foreground is screen color (ranging 0-15).
	background modulo 4 is the emulated CGA palette to be used:
		0:	green, red, and brown.
		1:	cyan, magenta and white.
		2:	same as 0, but with bright colors.
		3:	same as 1, but with bright colors.
Modes 2 and 11:
	foreground is a color index in current palette (ranging 0-1).
	background is a color index in current palette (ranging 0-1).
Modes 7 and 8:
	foreground is a color index in current palette (ranging 0-15).
	background is screen color index in current palette (ranging 0-15).
Mode 9:
	foreground is a color index in current palette (ranging 0-63).
	background is screen color index in current palette (ranging 0-63).
Mode 12:
	foreground is a color index in current palette (ranging 0-15).
	background is a color index in current palette (ranging 0-15).
Modes 13 and up:
	foreground is a color index in current palette (ranging 0-255).	
	background is a color index in current palette (ranging 0-255).	

If you are using a color depth higher than 8bpp, foreground and background are
direct RGB color values in the form &hRRGGBB, where RR, GG and BB are the red,
green and blue components ranging &h00-&hFF (0-255 in decimal notation). While
in hi/truecolor modes, you can also use the RGB function to obtain a valid
color value.


Example:

' Sets 800x600 in 32bpp color depth
SCREEN 19, 32
' Sets orange foreground and dark blue background color
COLOR &hFF8000, &h000040
' Say hello
CLS
LOCATE 19, 44: PRINT "Hello World!"
SLEEP


Differences from QB:

FB version accepts direct color values in hi/truecolor modes; COLOR in screen
mode 1 accepts 4 different CGA palettes instead of the 2 supported by QB.


See also:

SCREEN, PALETTE.



+------+----------------------------------------------------------------------
| DRAW |
+------+

Statement for sequenced pixel plotting.


Syntax:
	DRAW [buffer,]commands


Argument:	Description:

buffer		Buffer were drawing takes place. If omitted, drawing occurs
		into current work page.

commands	String holding drawing commands, see below.


Insights:

The DRAW statement can be used to issue several drawing commands all at once;
it is useful to quickly draw figures. The command string accepts the following
commands:

	Command:	Description:
Commands to plot pixels:
	B		Optional prefix; move but do not draw.
	N		Optional prefix; draw but do not move.
	Mx,y		Move to specified screen location; if + or - precedes
			x, movement is relative to current cursor position.
	U[n]		Move n units up. If n is omitted, 1 is assumed.
	D[n]		Move n units down. If n is omitted, 1 is assumed.
	L[n]		Move n units left. If n is omitted, 1 is assumed.
	R[n]		Move n units right. If n is omitted, 1 is assumed.
	E[n]		Move n units up and right. If n is omitted, 1 is
			assumed.
	F[n]		Move n units down and right. If n is omitted, 1 is
			assumed.
	G[n]		Move n units down and left. If n is omitted, 1 is
			assumed.
	H[n]		Move n units up and left. If n is omitted, 1 is
			assumed.
Commands to color:
	Cn		Changes current foreground color to n.
	Pp,b		Flood fills region with border color b with color p.
Commands to scale and rotate:
	Sn		Sets the current unit length; default is 4 pixels per
			unit.
	An		Rotate n*90 degrees (n ranges 0-3).
	TAn		Rotate n degrees (n ranges 0-359).
Extra commands:
	Xp		Executes commands at address p. For example, you could
			do:

		down10$ = "D10" : DRAW "U10R5X" + VARPTR(down10$) + "L5"


Example:

none


Differences from QB:

none


See also:

none



+------+----------------------------------------------------------------------
| FLIP |
+------+

Alias for PCOPY and SCREENCOPY. See SCREENCOPY for details.



+-----+-----------------------------------------------------------------------
| GET |
+-----+

Statement to save a block of pixels data into an array for later use.


Syntax:
	GET [buffer,][STEP](x1,y1)-[STEP](x2,y2), arrayname[(idx)]


Argument:	Description:

buffer		Buffer were to get pixel data from. If omitted, data is taken
		from the current work page.

x1,y1,x2,y2	Coordinates of the opposite corners of the graphics blocks to
		retrieve.

STEP		STEP specifies a pair of coordinates is relative to the last
		graphics cursor position. STEP before the second pair of
		coordinates specifies those are relative to the first pair.

arrayname	Array where to save the graphical block

idx		Index into arrayname where to begin storing data. If idx is
		omitted, it is assumed to be 0.


Insights:

Use this function to save blocks of graphics so you can later use PUT to draw
them. The coordinates of the block are affected by the most recent WINDOW and
VIEW statements, and must be both inside the current clipping region set by
VIEW. If the enclosed region does not entirely fit into the clipping region
GET will have no effect and an illegal function call error will be thrown.
The supplied array must be large enough to hold the block you're going to
save; the required array size depends on both the block size in pixels and
the current color depth. Use the following formula to compute the right size
in bytes:

For color depths 1, 2, 4 and 8:
	size = 4 + (w * h)
For color depths 15 and 16:
	size = 4 + (w * h * 2)
For color depths 24 and 32:
	size = 4 + (w * h * 4)

Where w and h are the width and height of the graphics block you want to save.
Assuming you're working with INTEGER arrays, and as an INTEGER in FB is 4
bytes long, to save an 8bpp 32x32 block for example, you'll need an array of
(((4 + (w * h)) + 3) / 4) elements.


Example:

See PUT example.


Differences from QB:

Contrary to the QB version, this requested array size for an image does not
reduce if you are using a mode with color depth less than 8bpp; so your arrays
will need to be sized using the formula for 8bpp modes even if you're is 1, 2
or 4bpp modes.
Also pay attention when storing pixel data blocks in multidimensional arrays,
as QB stored arrays in column-order, whereas FB stores arrays in row-order, so
what in QB was achieved with PUT (100, 100), sprites(0, 7), in FB is achieved
with PUT (100, 100), sprites(7, 0).


See also:

PUT, SCREEN, WINDOW, VIEW.



+-------------+---------------------------------------------------------------
| GETJOYSTICK |
+-------------+

Statement to retrieve joystick position and buttons status


Syntax:
	GETJOYSTICK id,buttons[,[x][,[y][,[z][,[r][,[u][,v]]]]]]


Argument:	Description:

id		Joystick ID number. Valid IDs range 0-15.

buttons		On function termination, this will return a bitmask holding
		buttons status. Each bit is 1 if the corresponding button is
		currently pressed, 0 otherwise.

x,y		On function termination, these will hold the current x,y axes
		position of the given joystick, ranging -1.0 to 1.0.

z,r,u,v		Additional joystick axes for which to fetch current position.
		Returned values range -1.0 to 1.0.


Insights:

This function is used to get the status of a given joystick device, identified
by an unique numeric ID. Up to 16 joysticks are supported, with the ID ranging
0-15. Once GETJOYSTICK is called, it'll return the joystick buttons/axes
status in the parameters passed by reference to it. Buttons must be an integer
variable and will hold a bitmask specifying which joystick buttons are
currently pressed; up to 32 buttons are supported, and the first button status
is reported in the least significant bit. Axes information is returned in the
remaining single variables passed to the function; the returned axis value
will range -1.0 to 1.0, with 0.0 being the still position. A joystick will
always at least support the x,y axes, but it may also support other axes. If
an additional axis is available, its status will be returned in the
corresponding variable and will also range -1.0 to 1.0; if the axis is not
available, a value strictly less than -1.0 will be returned.
If the joystick with specified ID number is not available, buttons will hold
-1, and all axes will hold a value strictly less than -1.0.


Example:

' Set video mode and enter loop
DIM x AS SINGLE, y AS SINGLE, throttle AS SINGLE, buttons AS INTEGER
SCREEN 13
DO
	' Get buttons, x, y, and 3rd axis status of joystick 0; assumes
	' 3rd axis to be throttle. Discard other axes.
	GETJOYSTICK 0, buttons, x, y, throttle
	LOCATE 1, 1
	IF x < -1.0 THEN
		PRINT "Joystick 0 not available"
	ELSE
		PRINT "Joystick 0:"
		PRINT USING "   Position: ##.##:##.##"; x; y
		PRINT USING "   Throttle: ##.##"; throttle
		PRINT "   Buttons: " + BIN$(buttons) + SPACE$(32)
	END IF
LOOP WHILE INKEY$ = ""
END


Differences from QB:

Function new in FB.


See also:

GETMOUSE, MULTIKEY.



+----------+------------------------------------------------------------------
| GETMOUSE |
+----------+

Statement to retrieve mouse position and buttons status


Syntax:
	GETMOUSE x,y[,wheel,[buttons]]


Argument:	Description:

x,y		Mouse position in screen coordinates is stored in these
		variables on function termination. If mouse is not present or
		out of the program window, x and y will hold -1.

wheel		Mouse wheel counter. Rotating the wheel away from you makes
		the count to increase, rotating towards you makes it to
		decrease. If mouse is not present or out of the program
		window, wheel will hold -1.

buttons		On function termination, this will return a bitmask holding
		buttons status. Bit 0 is set if left mouse button is down;
		bit 1 is set if right mouse button is down; bit 2 is set if
		middle mouse button is down.


Insights:

Use this function to get mouse info while in gfx mode. Pay attention: GETMOUSE
does NOT work if a gfx mode is not set. Pass x, y, wheel and buttons variables
by reference, so this function will store result values in them. If mouse is
not present or out of the program window, all returned values will be -1.


Example:

' Set video mode and enter loop
DIM x AS INTEGER, y AS INTEGER, buttons AS INTEGER
SCREEN 13
DO
	' Get mouse x, y and buttons. Discard wheel position.
	GETMOUSE x, y, , buttons
	LOCATE 1, 1
	IF x < 0 THEN
		PRINT "Mouse not available or not on window"
	ELSE
		PRINT USING "Mouse position: ###:###  Buttons: "; x; y;
		IF buttons AND 1 THEN PRINT "L";
		IF buttons AND 2 THEN PRINT "R";
		IF buttons AND 4 THEN PRINT "M";
		PRINT "   "
	END IF
LOOP WHILE INKEY$ = ""
END


Differences from QB:

Function new in FB.


See also:

SETMOUSE, SCREEN, MULTIKEY, GETJOYSTICK.



+-------------+---------------------------------------------------------------
| IMAGECREATE |
+-------------+

Function to create a new image buffer.


Syntax:
	IMAGECREATE(width,height[,color])


Argument:	Description:

width,height	Size of the image in pixels.

color		Optional color with which to clear the image upon creation.
		If omitted, defaults to the trasparent color.


Insights:

Use this function to allocate and set up a memory buffer for pixel data; once
created, the image can be used as target to all gfx primitives.
Upon creation, the image is cleared to color if specified, otherwise it is
cleared to the transparent color for the current color depth, that is, 0 for
indexed modes and &hFF00FF for hi/truecolor modes.
IMAGECREATE returns a pointer to the allocated image block, and will succeed
only if a gfx mode has already been set by calling SCREEN or SCREENRES; on
failure, 0 is returned.
Images created by IMAGECREATE must be freed by calling IMAGEDESTROY once you
are done using them in order to free allocated memory.


Example:

DIM buffer AS ANY PTR
SCREEN 15, 32
buffer = IMAGECREATE(64, 64, RGBA(64, 160, 0, 255))
CIRCLE buffer, (32, 32), 28, RGBA(255, 0, 0, 128),,,,F
PUT (160, 120), buffer, PSET
PUT (180, 140), buffer, ALPHA
IMAGEDESTROY buffer


Differences from QB:

Function new in FB.


See also:

IMAGEDESTROY, SCREEN, SCREENRES.



+--------------+--------------------------------------------------------------
| IMAGEDESTROY |
+--------------+

Function to free the memory allocated for an image created by IMAGECREATE.


Syntax:
	IMAGEDESTROY image


Argument:	Description:

image		The image to be freed.


Insights:

IMAGEDESTROY frees the memory allocated for the given image, assuming it was
previously created by calling IMAGECREATE.


Example:

none


Differences from QB:

Function new in FB.


See also:

IMAGECREATE.



+-----+-----------------------------------------------------------------------
| INP |
+-----+

Function for VGA port input emulation.


Syntax:
	INP(port)


Argument:	Description:

port		Emulated VGA port number to read from.


Insights:

This function emulates the QB INP function for VGA port access; the only port
value this function accepts is &h3C9.
You do not normally need this function; use 8bit or higher color depth modes
and PALETTE instead.


Example:

none


Differences from QB:

This is just a limited emulation, and only port &h3C9 is supported for DOS
VGA palette DAC registers reading operations. A read from any other port will
return 0.


See also:

PALETTE, OUT, WAIT.



+------+----------------------------------------------------------------------
| LINE |
+------+

Statement for line/box drawing.


Syntax:
	LINE [buffer,][[STEP](x1,y1)]-[STEP](x2,y2)[,[color[,[B[F]][,style]]]


Argument:	Description:

buffer		Buffer were drawing takes place. If omitted, drawing occurs
		into current work page.

STEP		Forces given coordinate to be relative to last graphical
		cursor position. When used before second pair of coordinates
		the position is relative to first pair.

x1,y1,x2,y2	Position of start and end points. If start point is omitted,
		last graphical cursor position is assumed.

color		Color to be used for drawing, in the same format supported by
		the COLOR statement. If you omit this, current foreground
		color is assumed.

B		Draws the outlines of a box instead of a line, treating
		(x1,y1) and (x2,y2) as the opposite corners of the box. Style
		does not apply in this case.

BF		Same as B, but draws a filled box.

style		16bit bitmask value to be used for styled line drawing.
		Starting from most significant bit, for each pixel of the
		line the style bit is tested and if not set, the pixel is not
		drawn. Each 16 pixels the bit position is reset to the most
		significant bit of the 16bit style mask.


Insights:

LINE coordinates are affected by last WINDOW and VIEW statements, and respect
clipping rect set by VIEW.


Example:

none


Differences from QB:

none


See also:

CIRCLE, WINDOW, VIEW.



+----------+------------------------------------------------------------------
| MULTIKEY |
+----------+

Function to detect multiple keypresses


Syntax:
	MULTIKEY(scancode)


Argument:	Description:

scancode	The DOS hardware scancode of the key you want to query for.


Insights:

This function lets you detect the immediate status of any key at any time; the
returned value is -1 if key is pressed, 0 otherwise. The keyboard input buffer
is not disabled while you use MULTIKEY; that is, pressed keys will be stored
and subsequently returned by your next call to INKEY$. This means you have to
empty INKEY$ when you finish using MULTIKEY:

	WHILE INKEY$ <> "": WEND

Keeping INKEY$ to work while you use MULTIKEY allows more flexibility and can
be useful to detect CHR$(255)+"X" combo returned on window close button click.
Pay attention: this function does only work if you are in gfx mode; it does
NOT work in console mode. For a list of accepted scancodes, see appendix A.


Example:

DIM work_page AS INTEGER, x AS INTEGER, y AS INTEGER
' Request 640x480 with 2 pages
SCREEN 18, 24,2
COLOR 2, 15
work_page = 0
x = 320
y = 240
DO
	' Let's work on a page while we display the other one
	SCREENSET work_page, work_page XOR 1
	' Check arrow keys and update position accordingly
	IF MULTIKEY(&h4B) AND x > 0 THEN x = x - 1
	IF MULTIKEY(&h4D) AND x < 639 THEN x = x + 1
	IF MULTIKEY(&h48) AND y > 0 THEN y = y - 1
	IF MULTIKEY(&h50) AND y < 479 THEN y = y + 1
	CLS
	CIRCLE(x, y), 30, , , , ,F
	' Page flip
	work_page = work_page XOR 1
LOOP WHILE NOT MULTIKEY(&h1)
' Clear input buffer
WHILE INKEY$ <> "": WEND
' Restore both work and visible pages to page 0
SCREENSET
PRINT "Press any key to exit..."
SLEEP


Differences from QB:

Function new in FB.


See also:

SCREEN, INKEY$, Appendix A.



+-----+-----------------------------------------------------------------------
| OUT |
+-----+

Statement for VGA port output emulation.


Syntax:
	OUT port,value


Argument:	Description:

port		Emulated VGA port number to write to.

value		Byte value to be written.


Insights:

Used for lowlevel VGA palette management emulation, this function only accepts
port numbers &h3C7, &h3C8 and &h3C9.
You do not normally need this function; use 8bit or higher color depth modes
and PALETTE instead.


Example:

none


Differences from QB:

This is just a limited emulation, and only ports &h3C7, &h3C8 and &h3C9 are
supported for DOS VGA palette DAC registers writing operations. A write to any
other port will have no effect.


See also:

PALETTE, INP, WAIT.



+-------+---------------------------------------------------------------------
| PAINT |
+-------+

Statement for flood-filling a screen region.


Syntax:
	PAINT [buffer,][STEP](x,y)[,[paint][,bordercolor]]


Argument:	Description:

buffer		Buffer were drawing takes place. If omitted, drawing occurs
		into current work page.

STEP		Forces given coordinate to be relative to last graphical
		cursor position.

x,y		Coordinates where to begin filling operation.

paint		Paint color or pattern, see below. If you omit this argument,
		current foreground color is used.

bordercolor	Color of the border in the same format as used by the COLOR
		statement. Filling stops when a pixel of this color is
		encountered.


Insights:

This function flood-fills a region of the screen, starting at specified
coordinates, which are affected by last call to WINDOW and VIEW. Clipping
region set by VIEW is respected. If the paint argument is a number, it is
assumed a color in the same format used by the COLOR statement, and the region
is flood-filled using that color. If paint is a string, the region will be
filled using a pattern; the pattern is always 8x8 pixels, and the passed
string must hold pixels data in a format dependent on the current color depth.
The string holds pattern pixels row by row, and its size should be as follows:

For color depths 1, 2, 4 and 8:
	size = 8 * 8 = 64
For color depths 15 and 16:
	size = (8 * 8) * 2 = 128
For color depths 24 and 32:
	size = (8 * 8) * 4 = 256

If the passed string is smaller, missing pixels will be 0.
Flood-filling continues until pixels of the specified border color are found.


Example:

none


Differences from QB:

The QB additional background parameter is not supported.


See also:

COLOR, WINDOW, VIEW.



+---------+-------------------------------------------------------------------
| PALETTE |
+---------+

Statement to set or get current palette.


Syntax:
	PALETTE [GET] [index,color]
	PALETTE [GET] [index,r,g,b]
	PALETTE [GET] USING arrayname(idx)


Argument:	Description:

index		Index of the color to be set/get.

color		Packed color RGB value for specified index.

r		Color red component, ranging 0-255.

g		Color green component, ranging 0-255.

b		Color blue component, ranging 0-255.

arrayname(idx)	Array of packed RGB color values to be set, or destination
		array for current palette packed RGB color values.


Insights:

The PALETTE statement is used to customize the current palette for gfx modes
with a color depth of up to 8bpp; using PALETTE while in a mode with a higher
color depth will have no effect.
Calling PALETTE with no argument restores the default palette for current gfx
mode. If you specify index and color, these are dependent on the current mode:

Screen mode:                       | index range: | color range:
-----------------------------------+--------------+--------------
1                                  |      0-3     |     0-15
2                                  |      0-1     |     0-15
7, 8                               |     0-15     |     0-15
9                                  |     0-15     |     0-63
11                                 |      0-1     |   see below
12                                 |     0-15     |   see below
13, 14, 15, 16, 17, 18, 19, 20, 21 |     0-255    |   see below

In screen modes 1, 2, 7, 8 and 9 you can assign to each color index one of the
colors in the available range.
In other screen modes, the color must be specified in the packed form
&hBBGGRR, where BB, GG and RR are the blue, green and red components ranging
&h0-&h3F in hexadecimal (0-63 in decimal). If you don't like hexadecimal form,
you can use the following formula to compute the integer value to pass to this
parameter:

  color = red or (green shl 8) or (blue shl 16)

Where red, green and blue must range 0-63.
You can also specify the new color red, green and blue components directly,
by calling PALETTE with 4 parameters. In this case r, g and b must be in the
range 0-255.
The available colors are reset by the SCREEN statement to a default palette;
see appendix B for details. You can alter the contents of the current palette
using the PALETTE statement for modes with a color depth higher or equal to 8,
or by using the OUT statement in lower depth modes.
Calling PALETTE USING allows to set a list of color values all at once; you
should pass an array holding enough elements as the color indices available
for your current gfx mode color depth (2 for 1bpp, 4 for 2bpp, 16 for 4bpp or
256 for 8bpp). The array elements must be integer values holding packed colors
in the form described above. The colors stored into arrayname starting with
given idx index are then assigned to each palette index, starting with index
0. Any change to the palette is immediately visible on screen.
If the GET option is specified, PALETTE retrieves instead of setting color
values for the current palette. The parameters have the same meaning as
specified for the set form, but in this case color, r, g and b must be
variables that will hold the color RGB values on function exit.


Example:

none


Differences from QB:

none


See also:

SCREEN, COLOR, OUT, Appendix B.



+-------+---------------------------------------------------------------------
| PCOPY |
+-------+

Alias for FLIP and SCREENCOPY, but requires both arguments. See SCREENCOPY for
details.



+------+----------------------------------------------------------------------
| PMAP |
+------+

Function to map coordinates between view and physical mapping.


Syntax:
	PMAP(expr, func)


Argument:	Description:

expr		Expression indicating the coordinate to be mapped.

func		Mapping function number to be applied to given coordinate.


Insights:

This function allows to convert a coordinate between view (as defined by the
WINDOW statement) and physical (as set by the VIEW statement) mappings.
Depending on the value of func, expr is used to compute a different mapping
to be returned by PMAP:

func value:	return value:
0		Treats expr as x view coordinate and returns corresponding
		x physical coordinate.
1		Treats expr as y view coordinate and returns corresponding
		y physical coordinate.
2		Treats expr as x physical coordinate and returns corresponding
		x view coordinate.
3		Treats expr as y physical coordinate and returns corresponding
		y view coordinate.


Example:

none


Differences from QB:

none


See also:

VIEW, WINDOW.



+-------+---------------------------------------------------------------------
| POINT |
+-------+

Function to read a pixel color or coordinate.


Syntax:
	POINT(x,y[,buffer])
	POINT(func)


Argument:	Description:

buffer		Buffer were to get pixel from. If omitted, pixel is taken from
		current work page.

x,y		Coordinates of the pixel.

func		Specify which coordinate mapping to return.


Insights:

When called with two arguments, the specified (x,y) coordinates are affected
by the most recent WINDOW and VIEW statements; if the pixel lies out of the
current clipping region, POINT returns -1, otherwise a color number in the
same format as used by the COLOR statement.
When called with one argument, this function allows to retrieve the current
gfx cursor position; POINT returns a value dependent on the func argument:

func:	return value:
0	Current x physical coordinate.
1	Current y physical coordinate.
2	Current x view coordinate. If the WINDOW statement has not been used,
	this returns the same as POINT(0).
3	Current y view coordinate. If the WINDOW statement has not been used,
	this returns the same as POINT(1).


Example:

none


Differences from QB:

none


See also:

COLOR, VIEW, WINDOW.



+------+----------------------------------------------------------------------
| PSET |
+------+

Statement to plot a single pixel.


Syntax:
	PSET [buffer,][STEP](x,y) [,color]


Argument:	Description:

buffer		Buffer were drawing takes place. If omitted, drawing occurs
		into current work page.

STEP		The STEP option specify that x and y are offsets relative to
		the current graphics cursor position.

x,y		Coordinates of the pixel.

color		Color attribute. This is mode specific, see COLOR and SCREEN
		for details.


Insights:

This function plots a single pixel on the screen. The x and y coordinates are
affected by the last call to the VIEW and WINDOW statements, and respect the
current clipping region as set by the VIEW statement. If you do not specify
color, current foreground color is used.


Example:

none


Differences from QB:

none


See also:

POINT, VIEW, WINDOW.



+-----+-----------------------------------------------------------------------
| PUT |
+-----+

Statement to draw a block of pixels previously saved by GET.


Syntax:
	PUT [buffer,][STEP](x,y), arrayname[(idx)] [,mode[,(alpha|blender)]]


Argument:	Description:

buffer		Buffer were drawing takes place. If omitted, drawing occurs
		into current work page.

STEP		The STEP option specify that x and y are offsets relative to
		the current graphics cursor position.

x,y		Coordinates where to place the top-left corner of the block to
		be drawn.

arrayname	Array holding saved block pixels data.

idx		Index into arrayname where data is assumed to start. If idx is
		omitted, it is assumed to be 0.

mode		One of PSET, PRESET, AND, OR, XOR, TRANS or ALPHA; see below.
		If omitted, this defaults to XOR.

alpha		Uniform alpha value for sprite blending; see below.

blender		Pointer to custom blender function; see below.


Insights:

PUT can be used to draw images previously saved by the GET statement or
created by the IMAGECREATE function. The x and y coordinates are affected by
the last call to the VIEW and WINDOW statements, and plotted image respects
the current clipping region set by last call to the VIEW statement. Pixels
stored in given array (source pixels) are drawn on the screen interacting with
the pixels onto which they are going to be drawn (destination pixels); the
interaction depends on the mode parameter:

mode:		interaction:
PSET		Source pixels overwrite destination pixels.
PRESET		Source pixels are 1-complement negated and written over
		destination pixels.
AND		Destination pixels are bitwise ANDed with source pixels.
OR		Destination pixels are bitwise ORed with source pixels.
XOR		Destination pixels are bitwise XORed with source pixels.
TRANS		Source pixels overwrite destination pixels. If a source pixel
		is the mask color (see below), the pixel is skipped.
ALPHA		Source pixels are blended on top of destination pixels
		accordingly to either the source pixel alpha value, either
		the value specified in the alpha parameter, if present.
CUSTOM		Source pixels are blended on top of destination pixels
		accordingly to the user-specified function passed in the
		blender parameter.

The AND, OR and XOR modes produce different results depending on the current
color depth, as pixels are stored in different formats; see appendix C for
details.
If the TRANS mode is used, pixels using the mask color are not drawn. The mask
color depends on the current color depth: in paletted modes (up to 8 bpp) it
is equal to color index 0, while on hi/truecolor modes (15, 16, 24 and 32 bpp)
it is equal to color &hFF00FF (bright pink).
If the ALPHA mode is used, you can also specify an optional alpha parameter,
ranging 0-255. If the alpha parameter is present, PUT will use it for all the
pixels of your sprite, and will skip mask colors like in the TRANS mode; this
will work only if you're in 15, 16, 24 or 32bit color depth. If you omit the
alpha parameter, PUT will only work if you're in 32bit color depth, and it
will use the alpha values embedded in each pixel; pixels using the mask color
will not be skipped in this case, as it is assumed the sprite has a properly
set up alpha channel.
If the CUSTOM mode is used, you must also specify the blender parameter, which
must be a pointer to a function of the form:

FUNCTION MyBlender (BYVAL src AS UINTEGER, BYVAL dest AS UINTEGER) AS UINTEGER

Such a function will be called for each pixel of your sprite, will receive the
source sprite pixel and the destination pixel where it is going to be drawn,
and must return the new pixel to be drawn. All color values are in the same
format as accepted by all other gfx primitives, that is color indices for
paletted modes, and &hRRGGBB values for hi/truecolor modes.
The pixels data stored in given array must be compatible with current gfx mode
color depth; that is, if you acquire an image using GET and you later change
screen mode via SCREEN, the image data may not be valid in the new gfx mode,
making PUT to behave badly.


Example:

' Set 320x240 mode using 16bpp color depth
SCREEN 14, 16
' Let's allocate space for a 32x32 sprite
DIM sprite((32 * 32 * 2) + 4) AS UBYTE
' Let's prepare our sprite
LINE (0,0)-(31,31), &hFF0000, BF
LINE (0,0)-(31,31), &h00FF00, B
LINE (8,8)-(23,23), &hFF00FF, BF
LINE (1,1)-(30,30), &h0000FF
LINE (30,1)-(1,30), &h0000FF
GET (0,0)-(31,31), sprite
' Showtime!
CLS
FOR i = 0 TO 63
	v = ABS(SIN(CSNG(i) / 8.0)) * 255.0
	LINE (0,i)-(319,i), RGB(v, v, v)
NEXT i
PUT (12, 16), sprite, PSET
PUT (56, 16), sprite, PRESET
PUT (100, 16), sprite, AND
PUT (144, 16), sprite, OR
PUT (188, 16), sprite, XOR
PUT (232, 16), sprite, TRANS
PUT (276, 16), sprite, ALPHA, 96
SLEEP


Differences from QB:

FB version supports hi/truecolor sprites, transparency, alpha blending and
clipping. For modes with color depth up to 8bpp, it always assumes 1 byte
equals 1 pixel into arrayname, whereas QB packs more pixels per byte if color
depth is less than 8bpp.


See also:

GET, SCREEN.



+-----+-----------------------------------------------------------------------
| RGB |
+-----+

Macro to compute valid color value for hi/truecolor modes.


Syntax:
	RGB(red,green,blue)


Argument:	Description:

red,green,blue	Red, green and blue components ranging 0-255.


Insights:

The RGB macro can be used to compute a valid color value for use while in
hi/truecolor modes. It returns a number in the format &hRRGGBB, where RR, GG
and BB equals the values passed to this function, in hexadecimal format.
Internally it's defined as:

#define RGB(r,g,b)    ((cint(r) shl 16) or (cint(g) shl 8) or cint(b))


Example:

See PUT example.


Differences from QB:

Macro new in FB.


See also:

RGBA, COLOR.



+------+----------------------------------------------------------------------
| RGBA |
+------+

Macro to compute valid color value for hi/truecolor modes.


Syntax:
	RGBA(red,green,blue,alpha)


Argument:	Description:

red,green,	Red, green, blue and alpha components ranging 0-255.
blue,alpha


Insights:

The RGBA macro works exactly like the RGB one, but also allows to specify an
alpha component, for use in 32bpp modes. Internally it's defined as:

#define RGBA(r,g,b,a)   ((cint(a) shl 24) or (cint(r) shl 16) or _
                         (cint(g) shl 8) or cint(b))


Example:

none


Differences from QB:

Macro new in FB.


See also:

RGB, COLOR.



+--------+--------------------------------------------------------------------
| SCREEN |
+--------+

Statement to set current gfx mode.


Syntax:
	SCREEN mode[,[depth][,[num_pages][,[flags][,refresh_rate]]]]


Argument:	Description:

mode		Gfx mode number, see below.

depth		Color depth in bits per pixel. If you omit this argument, the
		default depth for given mode is set.

num_pages	Number of pages, see below. Default if omitted is 1.

flags		Mode options, see below. Default if omitted is 0.

refresh_rate	Requested refresh rate in Hz. Default if omitted is 0, which
		lets gfxlib to pick up a working refresh rate automatically.


Insights:

The SCREEN statement sets the current gfx mode. Available modes list follows:

Mode 1: 320x200 in CGA emulation.
	40x25 text format, 8x8 character size.
	16 background colors and one of four sets of foreground colors set by
	the COLOR statement.
Mode 2: 640x200 in CGA emulation.
	80x25 text format, 8x8 character size.
	16 colors assigned to any of 2 attributes.
Mode 7: 320x200 in EGA emulation.
	40x25 text format, 8x8 character size.
	16 colors assigned to any of 16 attributes.
Mode 8: 640x200
	80x25 text format, 8x8 character size.
	16 colors assigned to any of 16 attributes.
Mode 9: 640x350
	80x25 or 80x43 text format, 8x14 or 8x8 character size.
	64 colors assigned to any of 16 attributes.
Mode 11: 640x480
	80x30 or 80x60 text format, 8x16 or 8x8 character size.
	Assignment of up to 256K colors to any of 2 attributes.
Mode 12: 640x480
	80x30 or 80x60 text format, 8x16 or 8x8 character size.
	Assignment of up to 256K colors to any of 16 attributes.
Mode 13: 320x200
	40x25 text format, 8x8 character size.
	Assignment of up to 256K colors to any of 256 attributes.
Mode 14: 320x240
	40x30 text format, 8x8 character size.
	Assignment of up to 256K colors to any of 256 attributes.
Mode 15: 400x300
	50x37 text format, 8x8 character size.
	Assignment of up to 256K colors to any of 256 attributes.
Mode 16: 512x384
	64x24 or 64x48 text format, 8x16 or 8x8 character size.
	Assignment of up to 256K colors to any of 256 attributes.
Mode 17: 640x400
	80x25 or 80x50 text format, 8x16 or 8x8 character size.
	Assignment of up to 256K colors to any of 256 attributes.
Mode 18: 640x480
	80x30 or 80x60 text format, 8x16 or 8x8 character size.
	Assignment of up to 256K colors to any of 256 attributes.
Mode 19: 800x600
	100x37 or 80x75 text format, 8x16 or 8x8 character size.
	Assignment of up to 256K colors to any of 256 attributes.
Mode 20: 1024x768
	128x48 or 128x96 text format, 8x16 or 8x8 character size.
	Assignment of up to 256K colors to any of 256 attributes.
Mode 21: 1280x1024
	160x64 or 160x128 text format, 8x16 or 8x8 character size.
	Assignment of up to 256K colors to any of 256 attributes.

For modes 14 and up, the depth parameter changes the color depth to the
specified new one; if depth is not specified, these modes run in 8bpp. For
modes 13 and below, depth has no effect. If you need custom resolutions,
have a look at the SCREENRES statement.
The num_pages parameter specifies the number of "pages" supported by the
video mode: a page is either the visible screen or an offscreen buffer the
same size of the screen. You can show a page while working on another one;
see the SCREENSET statement for details. You can request any number of pages
for any video mode; if you omit num_pages, 1 will be assumed, and only the
visible page (number 0) will be available.
The flags parameter can be an OR combination of the following values:

Value:		Option description:
&h1		Request fullscreen mode
&h2		Request OpenGL mode
&h10		Request stencil buffer for when in OpenGL mode
&h20		Request accumulation buffer for when in OpenGL mode

Depending on if the fullscreen flag is set or not, SCREEN will try to set
the specified video mode in fullscreen or windowed mode, respectively. Note
that the system may not be able to fulfill this request, fallbacking on a
working alternative.
If the OpenGL flag is set, gfxlib will enter OpenGL mode: all primitives
drawing functions will have no effect and the screen will not be automatically
updated for you. Basically in OpenGL mode you're just left alone with a
working OpenGL window, and your OpenGL code should handle all rendering. When
a frame is ready, you can request a page flip using the FLIP command, which
has this special behaviour while in OpenGL mode.
The stencil buffer flag has effect only when in OpenGL mode, and if set it
requests the OpenGL context to have a stencil buffer.
Similarly, the accumulation flag also only works when an OpenGL mode has been
requested, and requests an accumulation buffer for it.
The refresh_rate parameter allows to specify a desired refresh rate for the
gfx mode to be set; this is just an hint to gfxlib, which will try to fullfil
the request. It is not guaranteed that the mode will have specified refresh
rate; if gfxlib can't set it, it'll fall back on the first working rate. If
you omit this parameter or pass 0 to it, gfxlib will automatically detect and
use the first working refresh rate for specified mode.
Gfxlib will try its best to fulfill your gfx mode requests, but if everything
fails no mode will be set and execution will resume from the statement next
to the SCREEN call. So you should take particular care about checking if
SCREEN is successful; a way to do this is to test the return value of the
SCREENPTR function, have a look at it for details. Another way is just to
check for errors with ON ERROR; SCREEN will cause an illegal function call
error on failure.
To find out which video modes are supported by the host system, you can use
the SCREENLIST function.
Once a gfx mode has been set, you can toggle fullscreen and windowed mode at
any time by pressing ALT-ENTER, providing the system supports it. While in
windowed mode, clicking on the window close button will return CHR$(255)+"X"
to INKEY$, while clicking on the maximize window button will switch to
fullscreen mode if possible.
The system mouse cursor is displayed by default; you can hide it at any time
using the SETMOUSE statement.
A successful SCREEN call sets currently visible and working pages both to page
number 0, resets the palette to the specified mode one (see appendix B),
resets the clipping region to the size of the screen, disables custom
coordinates mappings, moves the gfx cursor to the center of the screen, moves
the text cursor to the top-left corner of the screen and sets foreground and
background colors to bright white and black respectively.


Example:

' Sets fullscreen 640x480 with 32bpp color depth and 4 pages
SCREEN 18, 32, 4, 1
IF NOT SCREENPTR THEN
	PRINT "Error setting video mode!"
	END
END IF


Differences from QB:

Parameters differ, FB version allows additional modes and color depths, and
any number of pages in any mode.


See also:

SCREENRES, SCREENLOCK, SCREENUNLOCK, SCREENPTR, SCREENSET, SCREENCOPY,
SCREENINFO, SETMOUSE, PALETTE.



+------------+----------------------------------------------------------------
| SCREENCOPY |
+------------+

Statement to copy the contents of a graphical page into another graphical page,
or to swap OpenGL buffers.


Syntax:
	SCREENCOPY [from_page][,to_page]


Argument:	Description:

from_page	Page to copy from. If you omit this argument, the current
		work page is assumed.

to_page		Page to copy to. If you omit this argument, the currently
		visible page is assumed.


Insights:

You can use this function to add a double buffer to your graphics. Any SCREEN
mode supports this function; you must supply valid page numbers otherwise
SCREENCOPY will have no effect. If a viewport has been set with the VIEW
statement, only the viewport area is copied, otherwise the whole page.
If in OpenGL mode, calling this function will result in a hardware page flip,
causing the rendered frame to be displayed; in this case the from_page and
to_page parameters have no meaning and are always not used.
This function has two aliases: FLIP and PCOPY.


Example:

See SCREENSET example.


Differences from QB:

Function new in FB: works like the QB PCOPY statement, but works for any gfx
mode, providing you requested enough pages.


See also:

SCREEN, SCREENSET.



+------------+----------------------------------------------------------------
| SCREENINFO |
+------------+

Statement to retrieve information about current video mode.


Syntax:
	SCREENINFO [w][,[h][,[depth][,[bpp][,[pitch][,[rate][,driver]]]]]


Argument:	Description:

w,h		Width and height of gfx mode in pixels.

depth		Color depth in bits per pixel.

bpp		Bytes per pixel.

pitch		Bytes per row.

rate		Refresh rate in Hertz.

driver		Name of the gfx driver being used.


Insights:

SCREENINFO can be used to retrieve informations on the current gfx mode; if
no mode is set when this statement is called, informations on the system
desktop will be returned.
Driver name is the internal gfxlib driver name being used (for example: "GDI",
"DirectX", "X11"). If querying the desktop, the empty string will be stored
in driver.
If SCREENINFO fails to query for a specific information, 0 will be stored in
the corresponding variable passed by reference.


Example:

SCREEN 15, 32
' Obtain info about current mode
SCREENINFO w, h, depth,,,refresh,driver_name$
PRINT STR$(w) + "x" + STR$(h) + "x" + STR$(depth);
IF (refresh > 0) THEN
	PRINT " @ " + STR$(refresh) + " Hz";
END IF
PRINT " using " + driver_name$ + " driver"
SLEEP
' Quit gfx mode and obtain info about desktop
SCREEN 0
SCREENINFO w, h, depth
PRINT "Desktop running at " + STR$(w) + "x" + STR$(h) + "x" + STR$(depth);


Differences from QB:

Function new in FB.


See also:

SCREEN, SCREENLIST.



+------------+----------------------------------------------------------------
| SCREENLIST |
+------------+

Function to fetch supported video modes.


Syntax:
	SCREENLIST ([depth])


Insights:

The SCREENLIST function can be used to find out at runtime which fullscreen
video modes are available on the host machine. This works like the DIR$
function: you first have to call this function once requesting the list of
supported resolutions for a given color depth (supported depths are 8, 15, 16,
24 and 32); this will return the first supported resolution for the request,
encoded in an integer result such that the screen width and height are stored
in the high and low word respectively.
Next, continue calling SCREENLIST without parameters to get the next supported
resolutions, until 0 is returned.
Resolutions are returned from lowest to highest supported ones. Also, it is
safe to call this function at any time.


Example:

DIM AS INTEGER mode, w, h
'' Find which 8bit resolutions are supported
mode = SCREENLIST(8)
WHILE (mode)
	w = HIWORD(mode)
	h = LOWORD(mode)
	PRINT STR$(w) + "x" + STR$(h)
	mode = SCREENLIST
WEND


Differences from QB:

Function new in FB.


See also:

SCREEN, SCREENRES.



+------------+----------------------------------------------------------------
| SCREENLOCK |
+------------+

Statement to lock work page framebuffer.


Syntax:
	SCREENLOCK


Insights:

The SCREENLOCK function locks the current work page framebuffer for direct
memory access. Once the page is locked, the screen contents stop being updated
automatically until you unlock the page with the SCREENUNLOCK statement.
While the work page is locked, you can read/write its memory freely; you must
call SCREENUNLOCK when you are done. It is strongly recommended that you hold
a page locked for a time as short as possible; and you should also note that
you are not supposed to call SCREENLOCK if a lock has not been unlocked first,
even though nested calls will simply have no effects.
If the work page is the same as the visible page, any modifications to the
page memory while locked will not become visible until SCREENUNLOCK is called.


Example:

See SCREENPTR example.


Differences from QB:

Function new in FB.


See also:

SCREEN, SCREENUNLOCK, SCREENPTR.



+-----------+-----------------------------------------------------------------
| SCREENPTR |
+-----------+

Function to retrieve a pointer to current work page framebuffer memory.


Syntax:
	SCREENPTR


Insights:

The SCREENPTR function returns a pointer to the current work page framebuffer
memory, or NULL (0) if no gfx mode is set. It can be used either to test if a
call to SCREEN is successful, either to do read/write operations directly to
the work page memory, providing the page is first locked and later unlocked
via the SCREENLOCK and SCREENUNLOCK statements.
The pointer returned by SCREENPTR is only valid after a successful call to
SCREEN, and is invalidated by subsequent calls to SCREEN.


Example:

' Set good old 320x200 in 8bpp mode
' No pages specified so we have one work page = visible page
SCREEN 13
' We're in an 8bpp mode, so a BYTE PTR is needed for framebuffer access
DIM framebuffer AS BYTE PTR
framebuffer = SCREENPTR
' We need to lock current work page before access is possible
SCREENLOCK
' Plot a white pixel at coordinates 160,100 on the work page
POKE framebuffer + (100 * 320) + 160, 15
' Unlock work page so our change is made visible
SCREENUNLOCK
SLEEP


Differences from QB:

Function new in FB.


See also:

SCREEN, SCREENLOCK, SCREENUNLOCK.



+-----------+-----------------------------------------------------------------
| SCREENRES |
+-----------+

Statement to set a custom resolution gfx mode.


Syntax:
	SCREENRES width,height[,[depth][,[num_pages][,[flags][,refresh_rate]]]]


Argument:	Description:

width		Width of the new gfx mode in pixels.

height		Height of the new gfx mode in pixels.

depth		Same as for the SCREEN statement, look at it for details.

num_pages	Same as for the SCREEN statement, look at it for details.

flags		Same as for the SCREEN statement, look at it for details.

refresh_rate	Same as for the SCREEN statement, look at it for details.


Insights:

SCREENRES works exactly like SCREEN, but allows to set custom resolutions.


Example:

none


Differences from QB:

Function new in FB.


See also:

SCREEN.



+-----------+-----------------------------------------------------------------
| SCREENSET |
+-----------+

Statement to set current work and visible pages.


Syntax:
	SCREENSET [work_page][,visible_page]


Argument:	Description:

work_page	New work page number.

visible_page	New visible page number.


Insights:

SCREENSET allows to set the current working page and the current visible page.
Page numbers can range 0-(num_pages - 1), where num_pages is the number of
pages set by the most recent call to the SCREEN statement. You can use this
function to achieve page-flipping or double-buffering.
If you omit work_page but not visible_page, only visible page is changed. If
you omit visible_page but not work_page, only work page is changed. If you
omit both arguments, both work page and visible page are reset to page 0.


Example:

' Set good old 320x200 in 8bpp mode, but with 2 pages
SCREEN 13, ,2
COLOR ,15
DIM x AS INTEGER
x = -40
' Let's work on page 1 while we display page 0
SCREENSET 1, 0
DO
	CLS
	LINE (x, 80)-(x + 39, 119), 4, BF
	x = x + 1
	IF (x > 319) THEN x = -40
	' Wait for vertical sync
	WAIT &h3DA, 8
	' Copy work page to visible page
	SCREENCOPY
LOOP WHILE INKEY$ = ""


Differences from QB:

Function new in FB.


See also:

SCREEN, SCREENCOPY.



+------------+----------------------------------------------------------------
| SCREENSYNC |
+------------+

Statement to wait for screen vertical blank.


Syntax:
	SCREENSYNC


Insights:

SCREENSYNC waits for the screen vertical blank to occur, then returns control
to the caller program.


Example:

none


Differences from QB:

Function new in FB.


See also:

SCREEN, WAIT.



+--------------+--------------------------------------------------------------
| SCREENUNLOCK |
+--------------+

Statement to unlock work page framebuffer.


Syntax:
	SCREENUNLOCK [start_line][,end_line]


Argument:	Description:

start_line	Optional argument specifying first screen line to be updated.
		If you omit this argument, top screen line is assumed.

end_line	Optional argument specifying last screen line to be updated.
		If you omit this argument, bottom screen line is assumed.


Insights:

SCREENUNLOCK unlocks the current work page assuming it was previously locked
by calling SCREENLOCK. This function lets the system restart updating the
screen regularly, and when called produces the immediate update of the screen
region marked by the given start and end lines. When no lock is held, you can
no longer directly access the work page framebuffer via SCREENPTR.


Example:

See SCREENPTR example.


Differences from QB:

Function new in FB.


See also:

SCREEN, SCREENLOCK, SCREENPTR.



+----------+------------------------------------------------------------------
| SETMOUSE |
+----------+

Statement to position and show/hide the system mouse cursor.


Syntax:
	SETMOUSE [x][,[y][,cursor]]


Argument:	Description:

x,y		Screen coordinates of the new mouse cursor position.

cursor		Pass 0 to hide the cursor, or 1 to show it.


Insights:

This statement is useful to set the current system mouse cursor position, and
to hide or show it. The cursor is shown by default when you call SCREEN.


Example:

none


Differences from QB:

Function new in FB.


See also:

GETMOUSE.



+------+----------------------------------------------------------------------
| VIEW |
+------+

Statement to define new physical coordinates mapping and clipping region.


Syntax:
	VIEW [[SCREEN] (x1,y1)-(x2,y2) [,[color][,border]]]


Argument:	Description:

SCREEN		When specified, any x,y coordinate will be relative to the
		top-left corner of the screen, and not to the left-top corner
		of the viewport.

x1,y1,x2,y2	Coordinates of the top-left and bottom-right corners of the
		new viewport.

color		Color with which to clear the new viewport; if you omit this
		argument, the viewport will not be cleared.

border		Color of the border box surrounding the new viewport. If you
		omit this argument, no border box will be drawn.


Insights:

Use this statement to set a new clipping region, also known as viewport. The
new viewport will override the previous one, if any; if the SCREEN argument
is omitted, all future coordinates specifications will be relative to the
top-left corner of the new viewport, instead of relative to the top-left
corner of the screen. Any graphical primitive will be affected by the new
viewport, and drawing outside specified region will produce no effect.
If color is specified, in the same format as the one supported by COLOR, the
new viewport is cleared with it; if border is specified, also in COLOR format,
a box using border as color will be drawn surrounding given region.
If all arguments are omitted, the viewport is reset to the screen mode size.


Example:

none


Differences from QB:

none


See also:

SCREEN, WINDOW.



+------+----------------------------------------------------------------------
| WAIT |
+------+

Statement for DOS port data waiting emulation.


Syntax:
	WAIT port,and_expr[,xor_expr]


Argument:	Description:

port		DOS port number onto wait data for.

and_expr	Integer expression to be ANDed with data from the port; if the
		result of this operation is not 0, the statement returns.

xor_expr	Integer expression to be XORed with data from the port, before
		passing it to and_expr. If you omit this argument, 0 is
		assumed.


Insights:

The only port number WAIT supports is &h3DA, for vertical blank syncing. You
should only call WAIT this way:

WAIT &h3DA, 8

Any other combination of port, and_expr and xor_expr will have no effect.
This function is supported for backwards QB compatibility only; it is
recommended that you use SCREENSYNC in your programs if you want to wait for
the vertical blank.


Example:

See SCREENSET example.


Differences from QB:

This is just an emulation of the QB WAIT statement, and only supports port
number &h3DA.


See also:

SCREENSYNC, INP, OUT.



+--------+--------------------------------------------------------------------
| WINDOW |
+--------+

Statement to define new view coordinates mapping for current viewport.


Syntax:
	WINDOW [[SCREEN] (x1,y1)-(x2,y2)]


Argument:	Description:

SCREEN		Optional argument specifying y coordinates increase from top
		to bottom.

x1,y1,x2,y2	New floating point values corresponding to the opposite
		corners of the current viewport.


Insights:

WINDOW is used to define a new coordinates system. (x1,y1) and (x2,y2) are the
new coordinates to be mapped to the opposite corners of the current viewport;
all future coordinates passed to gfx primitive statements will be affected by
this new mapping. If SCREEN is omitted, the new coordinates system will be
cartesian, that is, with y coordinates increasing from bottom to top.
Call WINDOW with no argument to disable the coordinates transformation.


Example:

none


Differences from QB:

none


See also:

SCREEN, VIEW.



+-------------+---------------------------------------------------------------
| WINDOWTITLE |
+-------------+

Statement to set the program window title.


Syntax:
	WINDOWTITLE stringexpr


Argument:	Description:

stringexpr	String to be assigned as new window title.


Insights:

This statement is useful to change the program window title. The new title set
will become active immediately if the program already runs in windowed mode,
otherwise will become the new title for any window produced by subsequent
calls to the SCREEN statement.
If you never call this function before setting a new windowed mode via SCREEN,
the program window will have your executable file name without extension as
title by default.


Example:

WINDOWTITLE "FreeBASIC example program"
SCREEN 15
SLEEP


Differences from QB:

Function new in FB.


See also:

SCREEN.



==============================================================================
Appendix A: DOS keyboard scancodes
==============================================================================

Here follows a list of hardware keyboard scancodes accepted by the MULTIKEY
function. These are equal to DOS scancodes, and are guaranteed to be always
recognized on all platforms.
These constants are also defined in the fbgfx.bi include file you can use in
your programs.

#define SC_ESCAPE	&h01
#define SC_1		&h02
#define SC_2		&h03
#define SC_3		&h04
#define SC_4		&h05
#define SC_5		&h06
#define SC_6		&h07
#define SC_7		&h08
#define SC_8		&h09
#define SC_9		&h0A
#define SC_0		&h0B
#define SC_MINUS	&h0C
#define SC_EQUALS	&h0D
#define SC_BACKSPACE	&h0E
#define SC_TAB		&h0F
#define SC_Q		&h10
#define SC_W		&h11
#define SC_E		&h12
#define SC_R		&h13
#define SC_T		&h14
#define SC_Y		&h15
#define SC_U		&h16
#define SC_I		&h17
#define SC_O		&h18
#define SC_P		&h19
#define SC_LEFTBRACKET	&h1A
#define SC_RIGHTBRACKET	&h1B
#define SC_ENTER	&h1C
#define SC_CONTROL	&h1D
#define SC_A		&h1E
#define SC_S		&h1F
#define SC_D		&h20
#define SC_F		&h21
#define SC_G		&h22
#define SC_H		&h23
#define SC_J		&h24
#define SC_K		&h25
#define SC_L		&h26
#define SC_SEMICOLON	&h27
#define SC_QUOTE	&h28
#define SC_TILDE	&h29
#define SC_LSHIFT	&h2A
#define SC_BACKSLASH	&h2B
#define SC_Z		&h2C
#define SC_X		&h2D
#define SC_C		&h2E
#define SC_V		&h2F
#define SC_B		&h30
#define SC_N		&h31
#define SC_M		&h32
#define SC_COMMA	&h33
#define SC_PERIOD	&h34
#define SC_SLASH	&h35
#define SC_RSHIFT	&h36
#define SC_MULTIPLY	&h37
#define SC_ALT		&h38
#define SC_SPACE	&h39
#define SC_CAPSLOCK	&h3A
#define SC_F1		&h3B
#define SC_F2		&h3C
#define SC_F3		&h3D
#define SC_F4		&h3E
#define SC_F5		&h3F
#define SC_F6		&h40
#define SC_F7		&h41
#define SC_F8		&h42
#define SC_F9		&h43
#define SC_F10		&h44
#define SC_NUMLOCK	&h45
#define SC_SCROLLLOCK	&h46
#define SC_HOME		&h47
#define SC_UP		&h48
#define SC_PAGEUP	&h49
#define SC_LEFT		&h4B
#define SC_RIGHT	&h4D
#define SC_PLUS		&h4E
#define SC_END		&h4F
#define SC_DOWN		&h50
#define SC_PAGEDOWN	&h51
#define SC_INSERT	&h52
#define SC_DELETE	&h53
#define SC_F11		&h57
#define SC_F12		&h58

' Extra scancodes not compatible with DOS scancodes
#define SC_LWIN		&h7D
#define SC_RWIN		&h7E
#define SC_MENU		&h7F



==============================================================================
Appendix B: Default palettes
==============================================================================

These are the default palettes you get when SCREEN is called:

		Index:	Color:

Mode 1:		0	Black
		1	Cyan
		2	Magenta
		3	White

Modes 2,10, and 11:	0	Black
		1	White

Mode 7, 8, 9	0	Black
12 and first	1	Blue
16 colors of	2	Green
mode 13 and up:	3	Cyan
		4	Red
		5	Pink
		6	Yellow
		7	Grey
		8	Dark grey
		9	Bright blue
		10	Bright green
		11	Bright cyan
		12	Bright red
		13	Bright pink
		14	Bright yellow
		15	White



==============================================================================
Appendix C: Internal pixel formats
==============================================================================

Internally, gfxlib always uses one of 3 pixel formats: indexed 1 byte per
pixel, direct color 2 bytes per pixel and direct color 4 bytes per pixel.
Here's a table to determine the pixel format depending on current color depth:

Depth:	Pixel format:
1	1 byte per pixel, indexed, index ranging 0-1.
2	1 byte per pixel, indexed, index ranging 0-3.
4	1 byte per pixel, indexed, index ranging 0-15.
8	1 byte per pixel, indexed, index ranging 0-255.
15,16	2 bytes per pixel, direct color, RRRRRGGGGGGBBBBB.
24,32	4 bytes per pixel, direct color, AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB.

As you can see, 15 and 16bpp modes internally have the same 16bpp format. The
same can be said for 24 and 32bpp modes, both using the 32bpp format.
This internal format is platform independent.

The pages memory will have pixels data set up in one of the 3 formats just
specified, so keep this in mind when accessing it via SCREENPTR; the same
applies to data in GET and PUT arrays.
Mask color for GET/PUT arrays is then encoded this way:

Depth:		Mask color value:
1,2,4,8		0
15,16		&hF81F
24,32		&hFF00FF

Indexed modes always use color index 0 for transparency, while direct color
modes use bright pink.



==============================================================================
Appendix D: About speed and size
==============================================================================

About speed: internally gfxlib uses normal system memory as pages memory. All
your read/writes on the page buffers (including direct writes via SCREENPTR)
will be done in system memory. On Win32 and Linux, a separated thread does
the screen updates as needed, running at the refresh rate speed; only dirty
lines are updated. This thread also does color conversion if needed.
While this may sound as an overhead in fullscreen modes, it is necessary for
windowed modes; to keep the lib slim and simple, the same method has been used
also in fullscreen, at the cost of a tiny speed penalty due to the memory
copy. MMX is used whenever possible all over gfxlib though, so the lib is
still pretty fast.

About size: one of the goals of gfxlib was to be independent of external libs.
Well, the goal has been achieved: the lib has its own tiny drivers (10-15 KB
each) and does not depend on anything else. Of course your EXEs will have to
include also other code at least for gfx initialization, fonts data, support
for all color depths, default palettes and some other stuff. All this means if
you use gfxlib routines your EXE size will increase in size from 40K up to
about 90K, depending on the functionalities your program uses (fbc will link
in just what you use). But your EXEs will be standalone.

Of course by standalone it doesn't mean it has no dependencies at all, but
just dependencies to system libraries you can assume to be always available.
Here's a list of the additional dependencies your EXEs will have when using
gfxlib:

Win32:
	user32.dll
	gdi32.dll
	(ddraw.dll, dinput.dll and opengl32.dll only loaded at runtime)
Linux:
	libX11
	libXpm
	libXext
	libXrender
	libXrandr
	libpthread
	(libGL only loaded at runtime)



==============================================================================
Appendix E: Internal drivers
==============================================================================

As previously stated, gfxlib features its own tiny drivers to work on various
systems. Here is the list of drivers:

Win32:
	DirectX
		This driver is based on DirectDraw and DirectInput; it'll work
		on any system that has already at least DirectX 3.0 installed.
		Windows 98 is the minimum OS requirement; if you have Windows
		95 this is not guaranteed to work.
		The required DirectX DLLs are loaded at execution time, so
		your EXE will not depend on them, being able to also run on
		systems where DX is not installed (this driver will fail to
		initialize there).
		Supports windowed and fullscreen modes.
	GDI
		Basic Windows GDI driver; slower than DirectX, yet guaranteed
		to always work. This is a fallback driver for when DX is not
		installed.
		Supports windowed mode only.
	OpenGL
		OpenGL driver; likely to be hardware accelerated on every system,
		it always works.
		Supports windowed and fullscreen modes.
Linux:
	X11
		Raw Xlib based driver; it always works, providing an X11
		server is reachable (at least XFree86 4.3.0 or Xorg required).
		If your program runs locally, it uses the Xshm extension to
		provide faster framebuffer access via shared memory. For
		fullscreen mode switching, the Xrandr extension is used (your X11
		gfx driver must support resolution switching, and your program
		needs to be executed locally, otherwise fullscreen will not work).
	OpenGL
		OpenGL driver; likely to be hardware accelerated on every system,
		it works as long as your X server is configured for OpenGL support.
		Supports windowed and fullscreen modes, but for fullscreen to
		work the same conditions as those requested by the raw X11 driver
		need to be satisfied.
DOS:
	VGA
		Supported on any VGA-compatible adapter, this driver provides 256-
		color modes 320x200, 320x100, 256x256, 160x120, and 80x80.
	ModeX
		Supported on any VGA-compatible adapter, this driver provides 256-
		color modes 320x240.  It is based on the classic Mode X tweak by
		Michael Abrash.

gfxlib will always choose the best driver for your system when a new video
mode is set via SCREEN. To override driver selection, you can set the FBGFX
environmental variable to the name of the driver you want to be tried first:
on Win32 for example you could do:

set FBGFX=gdi

This way gfxlib will first try to initialize a driver named "GDI"; if given
driver fails or cannot be found, gfxlib will fallback on the usual automatic
driver selection path.



==============================================================================
Appendix F: Hints
==============================================================================

- Avoid double buffering whenever possible; gfxlib already uses a double
  buffering system internally to keep the screen updated, so using your own
  double buffer will just mean an additional (unneeded) screen copy, thus a
  slowdown. Use the provided page flipping capabilities exported via the
  SCREENSET statement; see the MULTIKEY example provided in this doc, or see
  the fbgfx_flame.bas source in your FreeBASIC/examples/gfx directory.


- Other than normal arrays, GET and PUT support pointers as pixel data holder;
  the following code will work:

	TYPE FB_IMAGE FIELD = 1
		  width AS USHORT
		  height AS USHORT
		  imageData(64000) AS UBYTE
	END TYPE

	DIM udt AS FB_IMAGE
	DIM udt_ptr AS FB_IMAGE PTR
	DIM array(16001) AS INTEGER
	DIM array_ptr AS INTEGER PTR
	
	udt_ptr = @udt
	array_ptr = @array(0)
	
	SCREEN 13
	
	' These are all equivalent to each other
	GET (0,0)-(319,199), array
	GET (0,0)-(319,199), array(0)
	GET (0,0)-(319,199), @array(0)
	GET (0,0)-(319,199), array_ptr
	GET (0,0)-(319,199), @array_ptr[0]
	
	' These are also all equivalent to each other
	GET (0,0)-(319,199), @udt
	GET (0,0)-(319,199), udt_ptr
	GET (0,0)-(319,199), @udt_ptr[0]
  
  Here we used GET for the example, but the concept applies to PUT as well.


- All gfx primitives can work on GET/PUT buffers. This means you can have any
  number of offscreen surfaces of any size where to draw your stuff, and blit
  your buffers later onto the screen:

	DIM buffer(9602) AS USHORT
	DIM sprite(1028) AS UBYTE
	
	SCREEN 13
	
	' Since buffer is supposed to be a GET/PUT buffer, here we manually
	' set it up so its first 4 bytes are the usual GET/PUT buffer header.
	buffer(0) = 160 SHL 3	' Width * 8
	buffer(1) = 120		' Height
	
	CIRCLE buffer, (16,16), 15, 12,,, 1, F
	GET buffer, (0,0)-(31,31), sprite
	PSET sprite, (16,16), 15
	LINE buffer, (0,0)-(159,119), 2, B
	PUT buffer, (50,50), sprite, PSET
	PUT (80,40),buffer, PSET

  An easier way to create a GET/PUT buffer is to use the IMAGECREATE function:
  this will automatically allocate and set up the image buffer for you. The
  above example would become:
  
	DIM buffer AS ANY PTR
	DIM sprite AS ANY PTR
	
	SCREEN 13
	
	buffer = IMAGECREATE(160, 120)
	sprite = IMAGECREATE(32, 32)
	
	CIRCLE buffer, (16,16), 15, 12,,, 1, F
	GET buffer, (0,0)-(31,31), sprite
	PSET sprite, (16,16), 15
	LINE buffer, (0,0)-(159,119), 2, B
	PUT buffer, (50,50), sprite, PSET
	PUT (80,40),buffer, PSET
	
	IMAGEDESTROY buffer
	IMAGEDESTROY sprite

  When drawing onto a buffer, coordinates are affected by the most recent call
  to WINDOW, but VIEW has no effect; clipping is set to the whole buffer area.
  Of course the optional target buffer parameter passed to all gfx primitives
  can be an array as well as a pointer, as in the case of GET/PUT pixel data
  holders.


- You can enhance the PRINT functionality by using a custom routine that uses
  the internal predefined gfx fonts. The following snippet defines a new
  GfxPrint function that allows to draw transparent text by specifying the
  location in pixel coordinates, supports clipping and also allows to print
  text on GET/PUT buffers:

	DECLARE SUB GfxPrint( BYREF text AS STRING, _
		BYVAL x AS INTEGER, BYVAL y AS INTEGER, _
		BYVAL col AS INTEGER, BYVAL buffer AS ANY PTR = 0 )

	TYPE fb_FontType
		w AS INTEGER ' Width in pixels
		h AS INTEGER ' Height in pixels
		data AS UBYTE PTR
	END TYPE

	' Uncomment the internal gfx font you want to use
	EXTERN fb_FontData ALIAS "fb_font_8x8" AS fb_FontType
	'EXTERN fb_FontData ALIAS "fb_font_8x14" AS fb_FontType
	'EXTERN fb_FontData ALIAS "fb_font_8x16" AS fb_FontType

	SUB GfxPrint( BYREF text AS STRING, _
			BYVAL x AS INTEGER, BYVAL y AS INTEGER, _
			BYVAL col AS INTEGER, BYVAL buffer AS ANY PTR = 0 )

		DIM row AS INTEGER, i AS INTEGER
		DIM bits AS UBYTE PTR
	
		FOR i = 1 TO LEN(text)
			bits = fb_FontData.data + _
				(ASC(MID$(text, i, 1)) * fb_FontData.h)
			FOR row = 0 TO fb_FontData.h-1
				IF (buffer) THEN
					LINE buffer, (x + 7, y + row)_
						-(x, y + row), col,, _
						*bits SHL 8
				ELSE
					LINE (x + 7, y + row)-(x, y + row),_
						col,, *bits SHL 8
				END IF
				bits += 1
			NEXT row
			x += 8
		NEXT i
	END SUB

	SCREEN 13
	GfxPrint "Hello world!", 112, 96, 15
	SLEEP

  Pay attention when using the internal fonts data; gfxlib stores all fonts
  and palettes internally in a LZW compressed format to save binary space in
  your EXEs, and decompresses the data on the first call to SCREEN. If you
  do not call SCREEN in your programs, accessing the internal palettes and
  fonts data will return garbage.


- Gfxlib internally stores default fonts and palettes data in a LZW compressed
  format, decompressing it once on the first call to SCREEN. The tiny LZW
  codec used is not visible to the user programs not to clutter namespace, and
  as it's not really in the scope of gfxlib to provide data compressing
  facilities. Nonetheless, as it's there, you can access it by declaring
  prototypes of the encode and decode routines, pointing to the correct
  implementation inside gfxlib. Here's an example:

	DECLARE FUNCTION LZW_Encode ALIAS "fb_hEncode" ( _
					BYVAL in_buffer AS ANY PTR, _
					BYVAL in_size AS INTEGER, _
					BYVAL out_buffer AS ANY PTR, _
					BYREF out_size AS INTEGER _
				) AS INTEGER

	DECLARE FUNCTION LZW_Decode ALIAS "fb_hDecode" ( _
					BYVAL in_buffer AS ANY PTR, _
					BYVAL in_size AS INTEGER, _
					BYVAL out_buffer AS ANY PTR, _
					BYREF out_size AS INTEGER _
				) AS INTEGER
	
	DIM src_buffer(100000) AS UBYTE
	DIM src_size AS INTEGER
	DIM dest_buffer(100000) AS UBYTE
	DIM dest_size AS INTEGER
	
	'' Cannot work if our program doesn't link with gfxlib
	SCREEN 15
	
	src_size = 0
	OPEN "gfxlib.txt" FOR BINARY AS #1
	WHILE NOT EOF(1)
		GET #1,, src_buffer(src_size)
		src_size += 1
	WEND
	CLOSE #1
	PRINT "Data size before compression:", src_size
	GOSUB ShowData
	
	dest_size = 100000
	PRINT "Compressing...";
	LZW_Encode @src_buffer(0), src_size, @dest_buffer(0), dest_size
	PRINT "done."
	
	PRINT "Data size after compression:", dest_size
	PRINT
	
	src_size = 100000
	PRINT "Decompressing...";
	LZW_Decode @dest_buffer(0), dest_size, @src_buffer(0), src_size
	PRINT "done."
	
	PRINT "Data size before decompression:", src_size
	GOSUB ShowData
	SLEEP
	END
	
	ShowData:
		DIM i AS INTEGER
		PRINT "Contents: ";
		FOR i = 3 TO 36: PRINT CHR$(src_buffer(i)); : NEXT
		PRINT " [...]"
		RETURN


- Creating an OpenGL texture out of a GET/PUT buffer is easy; here's a small
  snippet that does it:
  
	#DEFINE TEX_MASKED		&h1
	#DEFINE TEX_MIPMAP		&h2
	#DEFINE TEX_NOFILTER		&h4
	#DEFINE TEX_HASALPHA		&h8
	
	FUNCTION CreateTexture( BYVAL buffer AS ANY PTR, BYVAL flags AS INTEGER _
							= 0 ) AS GLuint
		REDIM dat(0) AS UBYTE
		DIM p AS UINTEGER PTR, s AS USHORT PTR
		DIM AS INTEGER w, h, x, y, col
		DIM tex AS GLuint
		DIM AS GLenum format, minfilter, magfilter
		
		CreateTexture = 0
		
		s = buffer
		w = s[0] SHR 3
		h = s[1]
		
		IF( (w < 64) OR (h < 64) ) THEN
			EXIT FUNCTION
		END IF
		IF( (w AND (w-1)) OR (h AND (h-1)) ) THEN
			'' Width/height not powers of 2
			EXIT FUNCTION
		END IF
		
		REDIM dat(w * h * 4) AS UBYTE
		p = @dat(0)
		
		glGenTextures 1, @tex
		glBindTexture GL_TEXTURE_2D, tex
		
		FOR y = h-1 TO 0 STEP -1
			FOR x = 0 TO w-1
				col = POINT(x, y, buffer)
				'' Swap R and B so we can use the GL_RGBA texture format
				col = RGBA(col AND &hFF, _
						  (col SHR 8) AND &hFF, _
						  (col SHR 16) AND &hFF, _
						  col SHR 24)
				IF( flags AND TEX_HASALPHA ) THEN
					*p = col
				ELSE
					IF( (flags AND TEX_MASKED) AND _
							(col = &hFF00FF) ) THEN
						*p = 0
					ELSE
						*p = col OR &hFF000000
					END IF
				END IF
				p += 4
			NEXT x
		NEXT y
		
		IF( flags AND ( TEX_MASKED OR TEX_HASALPHA ) ) THEN
			format = GL_RGBA
		ELSE
			format = GL_RGB
		END IF
		
		IF( flags AND TEX_NOFILTER ) THEN
			magfilter = GL_NEAREST
		ELSE
			magfilter = GL_LINEAR
		END IF
		
		IF( flags AND TEX_MIPMAP ) THEN
			gluBuild2DMipmaps GL_TEXTURE_2D, format, w, h, GL_RGBA, _
							  GL_UNSIGNED_BYTE, @dat(0)
			IF( flags AND TEX_NOFILTER ) THEN
				minfilter = GL_NEAREST_MIPMAP_NEAREST
			ELSE
				minfilter = GL_LINEAR_MIPMAP_LINEAR
			END IF
		ELSE
			glTexImage2D GL_TEXTURE_2D, 0, format, w, h, 0, GL_RGBA, _
							 GL_UNSIGNED_BYTE, @dat(0)
			minfilter = magfilter
		END IF
		glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter
		glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilter
		
		CreateTexture = tex
	
	END FUNCTION

