int ggiInit(void);
Initalizes the library. This function must be called before using other LibGGI functions; otherwise results will be undefined.
Return: 0 for OK, otherwise an error code.
Example:
if(!ggiInit())
exit(EXIT_FAILURE);
/* do some libggi stuff */
ggiExit();
int ggiExit(void);
Uninitializes the library and automatically cleanup. This should be called after an application is finished with the library. If any GGI functions are called after the use of ggiExit the results will be undefined.
Return:
after successfully cleaning up,
the number of 'open' ggiInit calls, if there has been more than one call to ggiInit. As ggiInit and ggiExit must be used in properly nested pairs, e.g. the first ggiExit after two ggiInits will return 1.
error, especially if more ggiExit calls have been done than ggiInit calls.
Example:
if (!ggiInit())
exit(1); /* can't start! */
/* do some libggi stuff */
ggiExit();
void ggiPanic(const char *format, ...);
Graceful shutdown for fatal errors with reporting. May be used like printf(3). It will shut down the graphics modes active, close all visuals, print the error message given and then exit the application.
ggiPanic() should only be used by usermode programs when something is really screwed, and they do not know what to do. The same applies for libraries, but might be used in rare situations such as corruption of critical data structures.
Return: never returns.
Example:
ggiPanic("Aiee! Penguin on fire! ;-) Error code: %d", err);
A visual is simply a thing you can draw on. For example, a VT in
fullscreen-mode, an X window, an invisible memory area, and a printer. It is
identified by its handle of type ggi_visual_t, which is given to all
drawing functions to indicate which visual to operate on.
Each visual is completely independent of each other. You can use these visuals to display on multiple monitors and/or in multiple windows or to work on "virtual" graphics devices like in-memory pixmaps or even PPM-files on disk.
Most LibGGI functions are passed a visual returned by ggiOpen() to know where they should operate on.
ggi_visual_t is opaque to the user. Do not try to access any part of
the structure directly. It may change without notice.
ggi_visual_t ggiOpen(const char *display, ...);
Opens a visual. This function is given a NULL terminated list of the names of LibGGI dynamic drivers to load. This is usually one display target. Once loaded, they will all be associated with the single visual. Giving no arguments except the NULL instructs LibGGI to open the default display target (e.g. display-X, set by GGI_DISPLAY, see chapter GGI_DISPLAY).
Return: The opened visual, or NULL for error.
Example:
memory_visual = ggiOpen("display-memory", NULL);
/* Get from GGI_DISPLAY enviroment variable */
default_visual = ggiOpen(NULL);
if(!memory_visual || !default_visual)
return EXIT_FAILURE;
int ggiClose(ggi_visual_t vis);
Releases and destroys the visual and the associated internal control structures. This will close X windows, return consoles to text-mode, etc.
If focus is on the closed visual, focus is set to NULL.
Return: 0 for OK, otherwise an error code.
Example:
memory_visual = ggiOpen("display-memory", NULL);
/* do some drawing, save image, etc. */
ggiClose(memory_visual);
After opening the visual, you must set a mode (e.g. the dimensions, how many colors, etc.) before you can do anything useful with it, such as drawing.
ggi_mode structThis structure defines a visual's mode.
The definition in ggi/ggi.h is:
typedef struct { sint16 x, y; } ggi_coord;
typedef struct /* requested by user and changed by driver */
{
uint32 frames; /* frames needed */
ggi_coord visible; /* vis. pixels, may change slightly */
ggi_coord virt; /* virtual pixels, may change */
ggi_coord size; /* size of visible in mm */
ggi_graphtype graphtype; /* which mode ? */
ggi_coord dpp; /* dots per pixel */
} ggi_mode;
You don't need to care about the definition, if you want to set a mode,
but it is necessary if you want to find out the mode actually set.
Use of multiple buffering is specified in the frames member of the
ggi_mode struct, as the number of screen buffers needed.
dpp specifies the number of dots per pixel. For graphic modes, it is 1
(x and y) by definition. In text modes, it is the font size (each character
in text modes is a pixel).
Please note that the visible and virtual size are given in pixels, not dots. This makes a difference for text modes, because a character is treated as one pixel, but consists of a dpp.x*dpp.y sized matrix of dots.
ggi_graphtypeLibGGI defines a number of common graphic types, organized by bitdepth.
Currently defined graphtypes include:
is equivalent to the GGI_AUTO (see below) and means basically: please take your default value. Where possible this is currently a graphics mode, often the highest.
text modes with word- and longword-aligned characters.
(These modes use a palette.)
graphics modes with the respective bits per pixel. Note that for 32-bit modes, only the size (bits per pixel) is 32-bits, the depth (significant bits) is 24-bit.
The fuller graphtype definition consists of:
Number of bits-per-pixel
Number of significant bits
Mode "category": e.g. GT_TEXT (text modes), GT_TRUECOLOR (pixel is a direct RGB value), GT_GREYSCALE (grayscale :-), GT_PALETTE (each pixel is an index to a colormap)
Miscellaneous info. Indicates whether the pixel values are in reverse byte or bit order, etc.
These are packed into ggi_graphtype. See ggi/types.h for details.
Supposedly, applications can request GGI_AUTO in any of these fields to get a 'recommended' setting, and make their own graphtypes, but this is probably not supported yet by the targets.
However, applications can usually request one of the commonly used graphtypes above instead of making the graphtype themselves.
GGI_AUTOIf a mode is set or checked, any size parameter may be GGI_AUTO (defined in
ggi/types.h. This is a placeholder.
The behaviour is:
If some paramters are set, then the goal is to find a working mode that meets the given constraints.
The rules above are recommendations to the driver implementer and in no way guaranteed. The only guarantee is that the returned mode works[*]. But if they are applied in the listed order, the result should be pretty much what the user expects.
[*] In the rare case that the returned mode doesn't work, an application can assume that any further mode setting will not work on the visual and can give up.
As of March 3rd, 1998, the KGI drivers can't handle GGI_AUTO well, so please specify a complete default mode with GGI_DEFMODE.
There are three types of mode calls:
If a mode can not be set, the struct passed is changed to the suggested mode as follows:
int ggiSetMode(ggi_visual_t visual, ggi_mode *tm);
Set any mode (text or graphics).
Return: 0 for OK, otherwise could not set mode.
If GGI_AUTO/GT_AUTO is specified for any of the members of *tm, these
are filled in with the 'recommended' parameters, following the rules above.
If the mode cannot be set, a mode is suggested in *tm, but it will not
be silently set.
However, you'll probably want to use the convenience functions ggiSetTextMode() and ggiSetGraphMode() instead of this function.
int ggiGetMode(ggi_visual_t visual, ggi_mode *tm);
Get the current mode. tm will be filled with the current mode on return.
Return: 0 for OK, otherwise an error code.
int ggiCheckMode(ggi_visual_t visual, ggi_mode *tm);
Check any mode (text or graphics).
Return: A return of 0 means that a setmode call for this mode would succeed. Otherwise, the mode is given cannot be set.
The ggiCheck{Text,Graph}Mode() and ggiSet{Text,Graph}Mode() functions simply
accept mode parameters as arguments rather than having the application muck
with the ggi_mode struct itself. Otherwise, they are functionally
equivalent to the "master" ggiCheckMode() and ggiSetMode() functions.
However, you cannot specify multiple buffering with these functions; for
that, fill in a ggi_mode and use ggiSetMode() above.
int ggiSetTextMode(ggi_visual_t visual, int cols, int rows, int vcols, int vrows, int fontx, int fonty);
Set a textmode with given columns and rows, virtual columns and rows and a font of the given size.
Return: 0 for OK, otherwise could not set mode.
The fontsize is actually the size of the pixel (ggi_mode.dpp), in textmodes.
int ggiCheckTextMode(ggi_visual_t visual, int cols, int rows, intvcols, int vrows, fontx, int fonty, ggi_mode *suggested_mode, ...);
Check a text mode, with a null-terminated list of mode features. The last argument must be NULL.
Return: A return of 0 means that a setmode call for this mode would succeed. Otherwise, the mode is given cannot be set. In this case, tm is changed to the suggested mode:
If suggested_mode is not NULL, then it will be filled with the suggested mode, as documented under ggiCheckMode(). In the future, there may be more arguments, but currently there is nothing that may be put between the final NULL and suggested_mode.
int ggiSetGraphMode(ggi_visual_t visual, int x, int y, int xv,int yv, ggi_graphtype type);
Set a graphics mode with a visible area of size x/y and a virtual area of size vx/vy (you can pan aound the virtual area using the ggiSetOrigin()) and the specified graphics type.
Return: 0 for OK, otherwise could not set mode.
int ggiCheckGraphMode(ggi_visual_t visual, int x, int y, int xv,int yv, ggi_graphtype type, ggi_mode *suggested_mode, ...);
Check a graphics mode, with a null-terminated list of mode features. The last argument must be NULL.
Return: A return of 0 means that a setmode call for this mode would succeed. Otherwise, the mode is given cannot be set. In this case, tm is changed to the suggested mode:
If suggested_mode is not NULL, then it will be filled with the suggested mode, as documented under ggiCheckMode(). In the future, there may be more arguments, but currently there is nothing that may be put between the final NULL and suggested_mode.
Example:
/* Use only my mode... but you really should try to negotiate though */
err = ggiCheckGraphMode(vis, 320, 200, 320, 200, GT_8BIT, NULL, NULL);
if(err)
return EXIT_FAILURE;
/* OR use a suggested mode if our mode not available*/
err = ggiCheckGraphMode(vis, 320, 200, 320, 200, GT_8BIT, &sug_mode, NULL);
ggiSetMode(&sug_mode);
ggiParseMode(const char * s, ggi_mode * m)This function parses a string into a mode, using the following template:
visible-x x visible-y # virtual-x x virtual-y D dpp-x x dpp-y F frames(T)[graphtype or bpp value]
Whitspace is ignored before and after each number.
All values can be omitted (and default to GGI_AUTO).
Please do export a fully defined GGI_DEFMODE (e.g. 320x200#320x200D1x1[8]) if your KGI driver does not support GGI_AUTO yet.
T indicates text modes, as an alternative the graphtype can be 'T' also (or e.g. GT_TEXT16, of course).
Examples include:
just a visible size
same size, but double-height virtual screen
only virtual size defined
(default-bitsized) text mode with 80x40 characters
text mode with 100 virtual lines
same
640x400 at 8 bits per pixel
640x400[8BIT] 640x400[GT_8BIT] all the same
32bit text mode
int ggiSPrintMode(char * s, ggi_mode *m);int ggiFPrintMode(FILE * s, ggi_mode *m);int ggiPrintMode(ggi_mode *m)
These functions print all the members of ggi_mode in a human-readable
form. ggiSPrintMode() outputs to a preallocated string buffer,
ggiFPrintMode() outputs to a stdio FILE, and ggiPrintMode() outputs to
standard output. These functions correspond to sprintf(), fprintf(), and
printf() respectively.
Multiple buffering is the allocation of multiple framebuffers and drawing on/reading/displaying them independently. Applications use double-buffering to prepare a picture offline and switching display to it.
For compatibility with older applications the current ggiSet*Mode calls will not be changed. So this feature is currently only accessible through changing the mode struct and using ggiSetMode.
The frames field in the ggi_mode struct indicates the number of
screen buffers requested. It will default to 1.
Frames will be numbered 0 ... <frameno> -1
After mode setting frame 0 is active for reading, writing and display.
Three additional functions are required, to switch between these frames for drawing, reading back (ggiGet*) and for displaying, e.g.:
int ggiSetDisplayFrame(ggi_visual_t vis, int frameno)This function sets the frame that gets displayed.
int ggiSetWriteFrame(ggi_visual_t vis, int frameno)This function sets the frame for write operations like ggiPuts, ggiHLine ...
int ggiSetReadFrame(ggi_visual_t vis, int frameno)This function sets the frame for read operations, like ggiGetPixel and the ggiCrossBlit source.
All functions return 0 if they succeed, and -1 if they fail.
All libGGI primitives will obey the current read/write frame setting.
int ggiGetDisplayFrame(ggi_visual_t vis)This function reports the frame currently displayed. It may not fail.
int ggiGetWriteFrame(ggi_visual_t vis)This function reports the frame currently written to. It may not fail.
int ggiGetReadFrame(ggi_visual_t vis)This function reports the frame currently read from. It may not fail.
Visuals may have an indirect mapping off the pixel-value to a color via a programmable palette. This is e.g. true for the 8 bit IBM VGA modes. But even for "direct-mapped" modes, you will need to know which color maps to which pixel-value.
Try to keep the results of palette lookups in your application for efficiency purposes.
ggi_colorThe ggi_color struct has 16 bit wide entries for red (.r), green
(.g), and blue (.b) values.
It also has an alpha value (.a>) which is unused in libggi, but allow
LibGGI extensions to store an alpha value there.
Please scale your palette values as necessary.
ggi_pixelThe ggi_pixel, or the pixelvalue is a hardware-dependent representation
of a color. It is usually calculated from a ggi_color by
ggiMapColor or read from the visual by ggiGetPixel, and you can
safely assume that the relationship between a ggi_color and it's
associated ggi_pixel value does not change unless you change the visual
or the mode the current visual is in.
You can also do calculations with ggi_pixel values. Their format is
defined in the ggi_pixelformat section.
ggi_pixel ggiMapColor(ggi_visual_t vis, ggi_color * col);
Gets the pixelvalue for the given color.
Return: the (closest) pixel value
int ggiUnmapPixel(ggi_visual_t vis, ggi_pixel pixel, ggi_color *col);
Gets the color associated with a given pixelvalue.
Return: 0 for OK, otherwise an error code.
int ggiPackColors(ggi_visual_t vis, void *buf, ggi_color *cols,int len);
Converts the colors in cols to pixelvalues in buf.
Return: 0 for OK, otherwise an error code.
The output of ggiPackColors is suitable for input to the ggiPut{HLine,VLine,Box} functions.
int ggiUnpackPixels(ggi_visual_t vis, void *buf, ggi_color *cols,int len);
Converts pixelvalues in buf to individual elements of cols.
Return: 0 for OK, otherwise an error code.
This function maybe used to convert buffers output by the ggiGet{HLine,VLine,Box} functions from the pixelvalue representation to ggi_colors.
int ggiSetPalette(ggi_visual_t vis, int s, int len, ggi_color*cmap);
Sets a range of palette values, of length len, starting at index number s.
Return: 0 for OK, otherwise an error code.
When called with len=0 this function will not automatically succeed, but the return code will indicate whether there is a writable CLUT.
The index may also be the special value GGI_PALETTE_DONTCARE, which indicates that the palette can be installed anywhere in the CLUT, and in any order. This allows optimised use in windowing environments (minimizes color flashing between windows) and should be used whenever possible.
int ggiGetPalette(ggi_visual_t vis, int s, int len, ggi_color*cmap);
Gets a range of palette values, of length len, starting at index number s.
Return: 0 for OK, otherwise an error code.
When called with len=0 this function will not automatically succeed, but the return code will indicate whether there is a readable CLUT.
Some truecolor modes on some hardware can use the DAC's palette to lookup the values before sending to the monitor. Generally this is used for gamma correction by filling the lookup table with a curve, hence the name "gamma map" I suppose, but it could be used for other things e.g. special effects in games.
int ggiGetGammaMap(ggi_visual_t vis,int s,int len,ggi_color *gammamap);int ggiSetGammaMap(ggi_visual_t vis,int s,int len,ggi_color *gammamap);
Set or get the gamma map, for len colors starting at s.
Return: 0 for OK, otherwise an error code.
int ggiGetGamma(ggi_visual_t vis,ggi_float *r,ggi_float *g,ggi_float *b);int ggiSetGamma(ggi_visual_t vis,ggi_float r,ggi_float g,ggi_float b);
Set or get the gamma correction.
Return: 0 for OK, otherwise an error code.
LibGGI has a current context associated with each visual. This is done for performance reasons, as LibGGI can set up pointers to optimized functions when the GC changes (which can be monitored, as it may only be changed by the functions mentioned below).
int ggiSetGCForeground(ggi_visual_t vis, ggi_pixel color);
Sets the current colors for the foreground, used in all normal graphics functions.
Return: 0 for OK, otherwise an error code.
int ggiSetGCBackground(ggi_visual_t vis, ggi_pixel color);
Sets the current colors for the background, used in some 2-color operations like drawing text.
Return: 0 for OK, otherwise an error code.
int ggiGetGCForeground(ggi_visual_t vis, ggi_pixel * color);
Reads the current foreground color.
Return: 0 for OK, otherwise an error code.
int ggiGetGCBackground(ggi_visual_t vis, ggi_pixel * color);
Reads the current background color.
Return: 0 for OK, otherwise an error code.
int ggiSetGCClipping(ggi_visual_t vis, int left, int top, intright,int bottom);
Set the current clipping rectangle to (left,top)-(right,bottom). (right and bottom are the bottom right corner of the rectangle + 1).
Return: 0 for OK, otherwise an error code.
Initially the clipping rectangle is the whole virtual screen.
All libGGI drawing primitives obey the clipping rectangle.
For more advanced clipping please use libggi2d.
Return: 0 for OK, otherwise an error code.
int ggiGetGCClipping(ggi_visual_t vis, int *left, int *top, int*right, int *bottom);
Get the current clipping rectangle's coordinates.
Return: 0 for OK.
ggi_pixelformat
This structure describes the format of a ggi_pixel. An application
would use this if it wanted to directly output ggi_pixels rather than
calling ggiMapColor() or ggiPackColors() (to convert a ggi_color to a
ggi_pixel value).
/* Pixelformat for ggiGet/Put* buffers and pixellinearbuffers */
typedef struct {
int depth; /* Number of significant bits */
int size; /* Physical size in bits */
ggi_pixel red_mask; /* Bitmask of red bits */
ggi_pixel green_mask; /* Bitmask of green bits */
ggi_pixel blue_mask; /* Bitmask of blue bits */
ggi_pixel alpha_mask; /* Bitmask of alphachannel bits */
ggi_pixel clut_mask; /* Bitmask of bits for the clut */
ggi_pixel fg_mask; /* Bitmask of foreground color */
ggi_pixel bg_mask; /* Bitmask of background color */
ggi_pixel texture_mask; /* Bitmask of the texture (for
textmodes - the actual character) */
uint32 flags; /* Pixelformat flags */
} ggi_pixelformat;
/* Pixelformat flags */
#define GGI_PF_REVERSE_ENDIAN 0x01
#define GGI_PF_HIGHBIT_RIGHT 0x02
#define GGI_PF_HAM 0x04
#define GGI_PF_EXTENDED 0x08
depth and size are same as the depth and access size information
specified in the ggi_graphtype.
clut_mask is used in GT_PALETTE modes, indicating which bits correspond
to an index to the CLUT (color look-up table).
fg_mask, bg_mask, and texture_mask are for text modes only.
ggi_pixelformat *ggiGetPixelFormat(ggi_visual_t vis);
This function obtains the default pixel format for the given visual.
Return: pointer to ggi_pixelformat structure.
LibGGI has three basic types of primitives when it comes to filling rectangular areas (including the degenerate cases of horizontal and vertical lines and single pixels).
We have found three operations commonly performed on such areas :
The format of the pixels in ggiGet* and ggiPut* buffers are defined by ggi_pixelformat (please see the ggi_pixelformat section above).
Pixels are stored linearly, e.g. a rectangle with a width of three and a height of two will be stored pixel (0,0) (1,0) (2,0) (0,1) (1,1), (2,1) in that order.
Both ggiGet* and ggiPut* use chunky pixels, unpacked, even if their representation in the framebuffer is packed (i.e. pixel size not multiple of 8 bits) or non-linear. Thus the application does not need to know how to use planar or packed pixels for non-direct acccess.
(You may specify use of packed buffers using the GT_SUB_PACKED_GETPUT ggi_graphtype flag, but as of this writing, no targets implement that yet.)
The buffer passed to the ggiGet* and ggiPut* functions should be allocated
for at least width * height * ((ggiGetPixelFormat()->size+7)8)/ bytes.
(That is, the pixel size is obtained from ggi_pixelformat->size, rounded to
a multiple of 8 bits (one byte), multiplied by x and y.)
int ggiDrawPixel(ggi_visual_t vis, int x, int y);int ggiPutPixel(ggi_visual_t vis, int x, int y, ggi_pixel col);int ggiGetPixel(ggi_visual_t vis, int x, int y, ggi_pixel *col);
Draws/Puts/Gets a single pixel at x/y.
Return: 0 for OK, otherwise an error code.
int ggiDrawHLine(ggi_visual_t vis, int x, int y, int w);int ggiPutHLine(ggi_visual_t vis, int x, int y, int w, void*buf);int ggiGetHLine(ggi_visual_t vis, int x, int y, int w, void*buf);
Draws/Puts/Gets a horizontal line from x/y, extending w pixels in the positive x direction (normally right).
Return: 0 for OK, otherwise an error code.
int ggiDrawVLine(ggi_visual_t vis, int x, int y, int h);int ggiPutVLine(ggi_visual_t vis, int x, int y, int h, void*buf);int ggiGetVLine(ggi_visual_t vis, int x, int y, int h, void*buf);
Draws/Puts/Gets a vertical line from x/y, extending h pixels in the positive y direction (normally down).
Return: 0 for OK, otherwise an error code.
int ggiDrawBox(ggi_visual_t vis, int x, int y, int w, int h);int ggiPutBox(ggi_visual_t vis, int x, int y, int w, int h, void*buf);int ggiGetBox(ggi_visual_t vis, int x, int y, int w, int h, void*buf);
Draws/Gets/Puts a filled rectangle at x/y and extending w pixels in the positive x direction and h in the positive y direction.
Return: 0 for OK, otherwise an error code.
int ggiFillscreen(ggi_visual_t vis);
Fills the entire virtual screen. May be more efficient than the
corresponding call to ggiDrawBox().
Return: 0 for OK, otherwise an error code.
int ggiDrawLine(ggi_visual_t vis, int x, int y, int xe, int ye);
Draws any line from x/y to xe/ye. The line is exact; the pixel set is no more than 0.5 pixels off the place it should be.
Return: 0 for OK, otherwise an error code.
LibGGI provides means to do basic character output. These functions are intended for debugging and simple GUI applications. They are simple on purpose, without loadable font support, without internationalisation support, without changeable size. All more complex character functions go beyond the scope of this base library.
Only the standard ASCII charset ('\0x20' ... '\0x7f') is supported.
In graphics modes, ggiPutc() and ggiPuts() use at least 8x8 character fonts. In text mode, (by definition) the character cell is 1x1. (The actual font size, of which the application usually doesn't need to know, is specified in the dpp member of ggi_mode)
int ggiPutc(ggi_visual_t vis, int x, int y, char c);
Puts a single character on a graphical visual. This is only a very simple routine using a fixed-width font.
Return: 0 for OK, otherwise an error code.
int ggiPuts(ggi_visual_t vis, int x, int y, const char *str);
Puts multiple characters at once. No special handling is applied to control characters like CR or LF. You will see the associated glyph being displayed, so do this yourself if you need. ggiPuts() also does not wrap text at the clipping rectangle; it merely stops.
Return: 0 for OK, otherwise an error code.
Don't use ggiPutc() repeatedly for multiple characters, as ggiPuts() might be able to optimize the output of muliple chars at once.
Example:
ggiPuts(vis, 0, 100, "Hello World!");
int ggiGetCharSize(ggi_visual_t vis, int *width, int *height)This function stores the size of a ggiPutc character, measured in pixels, in width and height. For text mode, it will put (1,1) there by definition. For graphical modes, it puts the appropriate size (usually 8,8).
Return: 0 for OK, otherwise an error code.
int ggiCopyBox(ggi_visual_t vis, int x, int y, int w, int h, intnx, int ny);
This is a area-to-area-blit, all in the same visual. Copy the box described by x,y,w,h to the new location nx,ny. This automatically takes care of overlaps and optimizes for the given target (e.g. uses HW-accel or intermediate buffers as appropriate).
Return: 0 for OK, otherwise an error code.
ggiCopyBox will transfer an area between frames when the read frame is
not the same as the write frame.
int ggiCrossBlit(ggi_visual *src, int sx, int sy, int sw, int sh, ggi_visual *dst, int dx, int dy)
Blits a rectangular memory area from one visual to another. It handles colorspace-conversion. (Though it can be quite expensive, so take care.)
Return: 0 for OK, otherwise an error code.
ggiCrossBlit will transfer an area from the source visual's read frame
to the destination visual's write frame.
This function does not perform stretching.
int ggiSetOrigin(ggi_visual_t vis, int x, int y);
Set the top-left corner of the displayed area to x/y.
Return: 0 for OK, otherwise an error code.
When using a larger virtual area, you can pan the visible area over the virtual one to do scrolling. Some targets have extemely efficient means to do this (i.e. they do it in hardware).
Thus this is commonly used for double-buffering by requesting a double- height virtual screen (i.e. virtual size is double of the visible size), and then drawing on the upper/lower half alternatingly and displaying the currently "steady" buffer (the one which is not drawn to) using ggiSetOrigin(). (Though there is an easier way to do this.)
Example: Pan from the top to the bottom of the virtual screen
for(i = 0; i<virt_y-visible_y; i++) {
ggiSetOrigin(vis, 0, i);
}
Note that this call takes dot coordinates, not pixel coordinates as the drawing primitives do. This makes a difference in text mode.
int ggiGetOrigin(ggi_visual_t vis, int *x, int *y);
Get the current top-left corner of the displayed area into x/y.
Note that due to rounding to the hardware's capabilities, the values retrieved by a subsequent ggiGetOrigin() may not necessarily match those passed to ggiSetOrigin() previously.
Return: 0 if OK, otherwise an error code.
In addition to graphics operations, LibGGI provides several event handling functions, and, as a convenience, basic keyboard support.
The keyboard functions are based on ggiEventPoll() and ggiEventRead(). If you need more complex things, use the event interface directly.
int ggiKbhit(ggi_visual_t vis);
Checks if a key has been hit on the keyboard. This does not consume the key. It is basically for easy porting of old DOS applications.
Return: 0 if no key has been received yet, otherwise there is a key to be consumed.
DO NOT poll like this: do while( ! ggiKbhit(vis) );. On a multitasking
OS you would be wasting ressources which could be available to other processes.
If you want to wait for a key, use the ggiGetc() call.
int ggiGetc(ggi_visual_t vis);
Gets a character from the keyboard. Blocks if no key is available.
Return: a Unicode character (either UCS-2 (16-bit) or UCS-4 (32-bit))
For a fuller definition of characters, please look at ggi/keyboard.h. It is based on Linux keysyms and Unicode.
Events are of type ggi_event:
typedef union ggi_event {
uint8 size; /* size of this event */
ggi_any_event any; /* access COMMON_DATA */
ggi_cmd_event cmd; /* command/broadcast */
ggi_raw_event raw; /* raw data event */
ggi_val_event val; /* valuator change */
ggi_key_event key; /* key press/release */
ggi_pmove_event pmove; /* pointer move */
ggi_pbutton_event pbutton; /* pointer buttons */
} ggi_event;
The first element, size,
is the size of the given event (in bytes). Then the COMMON_DATA follows:
uint8 size; /* size of event in bytes */
uint8 type; /* type of this event */
uint8 focus; /* focus this is reported from */
uint8 device; /* who sent this */
uint32 time; /* timestamp */
Type is the type of event, which may be the following:
typedef enum ggi_event_type {
evNothing = 0, /* event is not valid. (must be zero) */
evCommand, /* report command/do action */
evBroadcast, /* notification of general interest */
evDeviceInfo, /* report input device information */
evRawData, /* raw data received from device */
evKeyPress, /* key has been pressed */
evKeyRelease, /* key has been released */
evKeyRepeat, /* automatically repeated keypress */
evKeyState, /* resynchronize keys state */
evPtrRelative, /* pointer movements reported relative */
evPtrAbsolute, /* pointer movements reported absolute */
evPtrButtonPress, /* pointer button pressed */
evPtrButtonRelease, /* pointer button released */
evPtrState, /* resynchronize pointer state */
evValRelative, /* valuator change (reported relative) */
evValAbsolute, /* valuator change (reported absolute) */
evValState, /* resynchronize valuator state */
evLast /* must be less than 33 */
} ggi_event_type;
Use the appropriate member from the ggi_event union to access the event data, depending on the given type. See ggi/event.h and ggi/keyboard.h for more details. For example:
ggi_event ev;
/* ... get the event... */
switch(ev.any.type) {
case evKeyPress:
case evKeyRepeat:
printf("Received key symbol: %x\n", ev.key.sym);
break;
case evKeyRelease:
/* ... ignore ... */ break;
case evPtrRelative:
case evPtrAbsolute:
printf("Moved the mouse! x: %d, y: %d\n",
ev.pmove.x, ev.pmove.y);
/* ... etc ... */
There is also ggi_event_mask which may be passed to various event
handling functions to indicate which types of events the program is
interested in. See ggi/ggi.h for possible masks.
ggi_event_mask ggiEventPoll(ggi_visual_t vis, ggi_event_mask *mask, struct timeval t)
Check if any of the events given in EvMask is available. Using the struct timeval *t, you can control the timeout, like select(2). Give NULL to wait indefinitely or a filled out struct to wait for a given time (which may be 0 to get non-blocking behaviour).
Return: a mask of events which are available (within the limits set by the mask parameter).
int ggiEventRead(ggi_visual_t vis, ggi_event *ev, ggi_event_maskmask)
Read an Event from the queue. This call blocks, if there is no such event present. Any queued events not in the mask remain unaffected, and can be retrieved later on when needed.
Return: the size of the event.
int ggiSetEventMask(ggi_visual_t vis, ggi_event_mask mask)
Set the global event mask. Only the events in this mask get queued for later retrieval using ggiEventRead. Events not in this mask are always discarded. Note that changing this mask causes all queued events not in the new mask to be flushed, which may be just what you want.
Return: 0 for OK, otherwise an error code.
ggi_event_mask ggiGetEventMask(ggi_visual_t vis)
Return: the global event mask.
int ggiAddEventMask(ggi_visual_t vis, ggi_event_mask evm)int ggiRemoveEventMask(ggi_visual_t vis, ggi_event_mask evm)
Macros to add or remove a specific event mask.
Dependent on the visual target and runtime environment found, applications may be granted direct access to hardware and/or library internal buffers. This may significantly enhance performance for certain pixel oriented applications or libraries.
The DirectBuffer is a mechanism in which a LibGGI program can use to determine all the characteristics of these buffers (typically the framebuffer), including the method of addressing, the stride, alignment requirements, and endianness.
However, use not conforming to this specification will have undefined effects and may cause data loss or corruption, program malfunction or abnormal program termination. So you don't really want to do this.
A frame buffer may be organized as several distinct buffers. Each buffer may have a different layout. This means both the addressing scheme to be used as well as the addressing parameters may differ from buffer to buffer.
LibGGI currently has support for pixel-linear buffers, bit-planar buffers, and interleaved planar buffers.
A linear buffer is a region in the application's virtual memory address space. A pixel with the pixel coordinates (<x>,<y>) is assigned a pixel number according to the following formula: <pixel number> = (<origin_y> + <y>)*<stride> + <origin_x> + <x> In any case both <x> and <y> must not be negative, <x> must be less than <size_x> and <y> must be less than <size_y>. For top-left-origin screen coordinates, <stride> and <origin_y> will both be positive. For bottom-left-origin screen coordinates, <stride> and <origin_y> will both be negative. This will result in the correct pixel number with the same formula in both cases. The pixel number will be used to address the pixel.
A certain number <bpp> of bits is stored per pixel. Bit <n> of the pixel value for pixel number <i> is stored in bit number <i>*<bpp> + <n> of the buffer. Bit <n> of byte <i> in the buffer corresponds to bit <i>*8 + <n> of the buffer for host CPU native bit and byte ordering. For some targets, the buffer might not be in host CPU native format and swapping operations need to be performed before writes or after reads.
Read and write access to the buffer is done using load and store instructions of the host CPU.
The access width and alignment requirements are assumed to be the same as the host CPU.
Read operations should be performed using the <read> buffer and write operations should be performed using the <write> buffer. These might be the same, but need not. If they are, read/write may be done to either buffer. Please note, that either read or write may be NULL. These are write-only or read-only buffers, which might be caused by hardware limitations. Such buffers are not suited to do Read-Modify-Write operations, so take care.
If the buffer is not stored with native bit and byte ordering,
swapping operations have to be performed before writes and after
reads. For pixel-linear buffers, this is indicated in the flags member of
ggi_pixelformat. For example, if flags & GGI_PF_REVERSE_ENDIAN, then
the pixel values must be byte swapped or reversed.
Paged buffers are indicated with page_size != 0 in ggi_directbuffer.
Successive access to addresses <addr> and <addr2> of either
read or write buffers with
<addr0> <page_size> != <addr1> / <page_size>/
may be very expensive compared to successive accesses with
<addr0> <page_size> == <addr1> / <page_size>/.
On i386 the penalty will be about 1500 cycles plus 4 cycles per
to be remapped. Because of this, block transfer operations might
become very inefficient for paged buffers. If there are two
different buffers provided for read and write operations,
you should do successive reads from one and do successive writes
to the other. If not, it is recommended to copy pagewise into
a temporary buffer and then to copy this temporary buffer
back to screen.
typedef enum {
blPixelLinearBuffer,
blExtended,
blLastBufferLayout
} ggi_bufferlayout;
typedef struct {
int stride; /* bytes per row */
ggi_pixelformat *pixelformat; /* format of the pixels */
} ggi_pixellinearbuffer;
/* Buffer types */
#define GGI_DB_NORMAL 0x01
#define GGI_DB_EXTENDED 0x02
#define GGI_DB_MULTI_LEFT 0x04
#define GGI_DB_MULTI_RIGHT 0x08
/* Flags that may be or'ed with the buffer type */
#define GGI_DB_SIMPLE_PLB 0x80000000
/* GGI_DB_SIMPLE_PLB means that the buffer has the following properties:
type=GGI_DB_NORMAL
read=write
layout=blPixelLinearBuffer
*/
typedef struct {
int frame; /* framenumber */
uint32 type; /* buffer type */
/* access info */
void *read; /* buffer address for reads */
void *write; /* buffer address for writes */
unsigned int page_size; /* zero for true linear buffers */
ggi_bufferlayout layout;
/* The actual buffer info. Depends on layout. */
union {
ggi_pixellinearbuffer plb;
void *extended;
} buffer;
} ggi_directbuffer;
is the frame number as used in multiple buffering.
is an enumeration specifying whether the buffer is pixel-linear, planar, etc.
is a union of all buffer info. Check the layout member
to see which member of use.
Please see the ggi_pixelformat section for information ggi_pixelformat,
which is the format of the pixels for pixel-linear buffers.
int ggiDBGetNumBuffers(ggi_visual_t vis);Return the number of DirectBuffers available to the application.
const ggi_directbuffer *ggiDBGetBuffer(ggi_visual_t vis, int bufnum);Return DirectBuffer with number bufnum. The buffers at position 0
to ggi_mode.frames-1 represent the DirectBuffers for each frame in the
visual, if they are available.
Pixel-linear buffers have type==GGI_DB_SIMPLE_PLB | GGI_DB_NORMAL.
You're on your own now.
ggi_visual_t vis;
ggi_mode mode;
int i;
/* Pointers to framebuffer */
unsigned char *readptr[2], *writeptr[2];
int stride[2];
mode.frames = 2; /* Double-buffering */
mode.visible.x = 640; /* Screen res */
mode.visible.y = 480;
mode.virt.x = GGI_AUTO; /* Any virtual resolution. Will usually be set
mode.virt.y = GGI_AUTO; to be the same as visible but some targets may
have restrictions on virtual size. */
mode.graphtype = GT_8BIT; /* Depend on 8-bit palette. */
mode.dpp.x = mode.dpp.y = GGI_AUTO; /* Always 1x1 but we don't care. */
if(ggiInit())
{
/* Failed to initialize library. Bomb out. */
}
vis = ggiOpen(NULL);
if(!vis)
{
/* Opening default visual failed, quit. */
}
if(ggiSetMode(vis, &mode))
{
/* Set mode has failed, should check if suggested mode
is o.k. for us, and try the call again. */
}
/* We got the mode we wanted.
Now get framebuffers for frame #0 and frame #1. */
for(i = 0; i<mode.frames; i++)
{
ggi_directbuffer *db;
db = ggiDBGetBuffer(vis, i);
if(!db)
{
/* Failed to get buffer... */
break;
}
if(!(db->type & GGI_DB_SIMPLE_PLB))
{
/* We don't handle anything but simple pixel-linear buffers.
Fall back to ggiPutBox() or something. */
break;
}
readptr[i] = db->read;
writeptr[i] = db->write;
/* Stride of framebuffer (in bytes). */
stride[i] = db->buffer.plb.stride;
/* Check pixel format, be portable.... */
Some targets allow different modes with regard to when the screen is updated and the actual drawing takes place.
The synchronous mode is default because it is what most programmers expect: When the drawing command returns, it is already or will be executed very shortly. So the visible effect is that everything is drawn immediately. (It is not guaranteed in the strict sense that it is already drawn when the function call returns, but almost.)
The asynchronous mode is (at least on the X) faster, but does
not guarantee that the command is executed immediately. To make sure that
all pending graphics operations are actually done
and the screen is updated, you need to call
ggiFlush(myvis);.
(Side note: The screen refresh the X target does every 1/20 s can take about half the execution time of a program. So syncronous mode can really slow things down.)
As it stands now, all operations are guaranteed to be performed in the order given in both modes. Reordering has been discussed but is currently not done.
So the recommendation for all graphics applications is to set the asynchronous mode. It will be far more efficient on some platforms and will never be worse. (If asynchronous mode is not supported by a target, setting it is still allowed, but has no effect.)
How to set up asynchronous mode?
ggiAddFlags(myvis,GGIFLAG_ASYNC);
switches to asynchronous mode,ggiFlush(myvis); updates the screen,ggiRemoveFlags(myvis,GGIFLAG_ASYNC);
switches to synchronous mode.
int ggiFlush(ggi_visual_t visual);
Flush all pending output. Not needed in synchrounous mode.
int ggiSetFlags(ggi_visual_t vis, ggi_flags flags);
Set flags on visual, e.g. asynchronous mode.
int ggiGetFlags(ggi_visual_t vis, ggi_flags flags);
Get flags currently in effect.
int ggiAddFlags(ggi_visual_t vis, ggi_flags flags);int ggiRemoveFlags(ggi_visual_t vis, ggi_flags flags);
Macros to add or remove individual flags. (Currently only GGIFLAG_ASYNC.)
int ggiGetSelectFD(ggi_visual_t vis);
Obtain a file descriptor for the specified visual. This file descriptor then can be passed as part of a set to select(2) -- when there is input available, it becomes readable. This is useful in user interfaces where you need to wait for multiple inputs at once.
Return: file descriptor, or -1 if it is not available.
Use ggiEventPoll() and ggiEventRead() once you get an event.