Based on the original GRX manual written by: Csaba Biegl on August 10, 1992
Adapted for MGRX by: Mariano Alvarez Fernández on August 1, 2005
Last update: April 13, 2023
MGRX is a 2D graphics library derived from the GRX library. GRX was originaly written by Csaba Biegl for DJ Delorie's DOS port of the GCC compiler.
MGRX supports four platforms:
For the Linux console and the Linux X11 versions three architectures are supported: i386 (32bit), x86_64 (64bit) and ARM (32bit, tested in a Raspberry Pi 4 using Raspbian).
Additionally MGRX can work without graphic output using the memory driver.
MGRX (mgrx.fgrim.com) is a fork of GRX (grx.gnu.de). The main MGRX differences are:
The MGRX goal is to be a small, easy to use and maintain, C graphics library.
The next program draws a double frame around the screen and writes "Hello, MGRX world" centered, then it waits until a key is pressed.
#include <string.h> #include <mgrx.h> #include <mgrxkeys.h> int main() { char *message = "Hello, MGRX world"; int x, y; GrTextOption grt; GrEvent ev; GrSetMode(GR_default_graphics); GrEventInit(); GrMouseDisplayCursor(); grt.txo_font = GrGetDefaultFont(); grt.txo_fgcolor = GrWhite(); grt.txo_bgcolor = GrBlack(); grt.txo_direct = GR_TEXT_RIGHT; grt.txo_xalign = GR_ALIGN_CENTER; grt.txo_yalign = GR_ALIGN_CENTER; grt.txo_chrtype = GR_BYTE_TEXT; GrBox(0, 0, GrMaxX(), GrMaxY(), GrWhite()); GrBox(4, 4, GrMaxX()-4, GrMaxY()-4, GrWhite()); x = GrMaxX() / 2; y = GrMaxY() / 2; GrDrawString(message, strlen(message), x, y, &grt); GrEventWaitKeyOrClick(&ev); GrMouseEraseCursor(); GrEventUnInit(); GrSetMode(GR_default_text); return 0; }
How to compile the hello world program (assuming the MGRX library was previously installed)
If you have enabled the experimental Linux console KMS/DRM driver add "-ldrm" to the command.
All public data structures and graphics primitives meant for usage by the application program are declared/prototyped in the header files (in the 'include' sub-directory):
User programs normally only include mgrx.h and mgrxkeys.h and optionally mgrxcolr.h
The graphics driver is normally autodetected or set by the
final user using the environment variable MGRXDRV
, but a program
can set it by function:
int GrSetDriver(char *drvspec);
on succes it returns non-zero (TRUE). The drvspec string has the same format as the environment variable:
<driver> gw <width> gh <height> nc <colors>
available drivers are for:
the optionals gw, gh and nc parameters set the desired default graphics mode. Normal values for 'nc' are 2, 16, 256, 64K and 16M.
If neither the MGRXDRV
variable exist, nor the
driver is set by program, MGRX will try to detect the correct driver when
first calling GrSetMode
(see bellow)
After initiated the current driver name can be obtained from:
GrCurrentVideoDriver()->name
The type of the installed graphics adapter can be determined with the function:
GrVideoAdapter GrAdapterType(void);
it returns the type of the adapter as one of the following symbolic constants (defined in mgrx.h):
typedef enum _GR_videoAdapters { GR_UNKNOWN = (-1), /* not known (before driver set) */ GR_VGA, /* VGA adapter */ GR_EGA, /* EGA adapter */ GR_XWIN, /* X11 driver */ GR_WIN32, /* W32 driver */ GR_LNXFB, /* Linux console driver */ GR_MEM /* memory only driver */ } GrVideoAdapter;
Note that the VESA
driver return GR_VGA
here.
Before a program can do any graphics drawing it has to
configure the graphics driver for the desired graphics mode. It is done with
the GrSetMode
function as follows:
int GrSetMode(int which,...);
On succes it returns non-zero (TRUE). The which
parameter can be one of the following constants, declared in mgrx.h:
GR_default_graphics, GR_default_text, GR_width_height_graphics, GR_biggest_graphics, GR_width_height_color_graphics, GR_custom_graphics, GR_width_height_bpp_graphics, GR_custom_bpp_graphics, GR_NC_default_text, GR_NC_default_graphics, GR_NC_width_height_graphics, GR_NC_biggest_graphics, GR_NC_width_height_color_graphics, GR_NC_custom_graphics, GR_NC_width_height_bpp_graphics, GR_NC_custom_bpp_graphics,
The GR_default_graphics
inits the graphic screen
with the resolution and color depth defined in the MGRXDRV environment
variable (or by te GrSetDriver function or by the the driver defaults).
The GR_default_text
can be used, at the end of the
program, to return the graphics screen to his original state.
The GR_biggest_graphics
inits the graphic screen
with the maximum resolution and color depth supported by the graphic driver.
For Win32 and X11 this goes to full screen. If you want to limit the maximum
resolution to use, you can set the environment variable MGRXBIGG with
"maxw maxh".
The GR_width_height_graphics
mode requires the
two size arguments: int width
and int height
.
The GR_width_height_color_graphics
mode requires three arguments: int width
,
int height
and GrColor colors
.
The GR_width_height_bpp_graphics
mode requires three arguments: int width
, int height
and int bpp
(bits per plane instead number of colors).
The GR_custom_graphics
and
GR_custom_bpp_graphics
modes require five arguments:
int width
, int height
, GrColor colors
or int bpp
, int vx
and int vy
. Using
this modes you can set a virtual screen of vx
by vy
size, but it only works on some videomodes with the DOS drivers.
The GR_NC_...
modes are equivalent to the
GR_..
ones, but they don't clear the video memory.
Graphics drivers can provide info of the supported graphics modes, use the next code skeleton to colect the data:
{ GrFrameMode fm; const GrVideoMode *mp; for (fm =GR_firstGraphicsFrameMode; fm <= GR_lastGraphicsFrameMode; fm++) { mp = GrFirstVideoMode(fm); while (mp != NULL) { .. .. use the mp info .. mp = GrNextVideoMode(mp)) } } }
Don't worry if you don't understand it, normal user programs
don't need to know about FrameModes
. The GrVideoMode
structure has the following fields:
typedef struct _GR_videoMode GrVideoMode; struct _GR_videoMode { char present; /* is it really available? */ char bpp; /* log2 of # of colors */ short width,height; /* video mode geometry */ short mode; /* BIOS mode number (if any) */ int lineoffset; /* scan line length */ int privdata; /* driver can use it for anything */ struct _GR_videoModeExt *extinfo; /* extra info (maybe shared) */ };
the width
, height
and bpp
members are the useful information if you are interested in set
modes other than the GR_default_graphics
.
The current graphics mode (one of the valid mode
argument values for GrSetMode
) can be obtained with:
GrGraphicsMode GrCurrentMode(void);
while the current GrVideoMode
can be determined with:
GrVideoMode * GrCurrentVideoMode(void);
A user-defined function can be invoked every time the video
mode is changed (i.e. GrSetMode
is called). This function should
not take any parameters and don't return any value. It can be installed (for
all subsequent GrSetMode
calls) with the function:
void GrSetModeHook(void (*hookfunc)(void));
Important note. If you ask for a no supported video mode
GrSetMode
will return the more similar mode it founds, so be
prepared to use different dimensions and number of colors of those you
asked for.
The library supports a set of drawing regions called contexts
(the GrContext
structure). These can be in video memory or in
system memory. Contexts in system memory always have the same memory
organization as the video memory. When GrSetMode
is called, a
default context is created which maps to the whole graphics screen. Contexts
are described by the GrContext
data structure:
typedef struct _GR_context GrContext; struct _GR_context { struct _GR_frame gc_frame; /* frame buffer info */ struct _GR_context *gc_root; /* context which owns frame */ int gc_xmax; /* max X coord (width - 1) */ int gc_ymax; /* max Y coord (height - 1) */ int gc_xoffset; /* X offset from root's base */ int gc_yoffset; /* Y offset from root's base */ int gc_xcliplo; /* low X clipping limit */ int gc_ycliplo; /* low Y clipping limit */ int gc_xcliphi; /* high X clipping limit */ int gc_ycliphi; /* high Y clipping limit */ int gc_usrxbase; /* user window min X coordinate */ int gc_usrybase; /* user window min Y coordinate */ int gc_usrwidth; /* user window width */ int gc_usrheight; /* user window height */ # define gc_baseaddr gc_frame.gf_baseaddr # define gc_selector gc_frame.gf_selector # define gc_onscreen gc_frame.gf_onscreen # define gc_memflags gc_frame.gf_memflags # define gc_lineoffset gc_frame.gf_lineoffset # define gc_driver gc_frame.gf_driver };
The following four functions return information about the
layout of and memory occupied by a graphics context of size width
by height
in the current graphics mode (as set up by
GrSetMode
):
int GrLineOffset(int width); int GrNumPlanes(void); long GrPlaneSize(int w,int h); long GrContextSize(int w,int h);
GrLineOffset
always returns the offset between
successive pixel rows of the context in bytes. GrNumPlanes
returns the number of bitmap planes in the current graphics mode.
GrContextSize
calculates the total amount of memory needed by a
context, while GrPlaneSize
calculates the size of a bitplane
in the context. The function:
GrContext *GrCreateContext(int w,int h,char *memory[4],GrContext *where);
can be used to create a new context in system memory. The NULL pointer is
also accepted as the value of the memory
and where
arguments, in this case the library allocates the necessary amount of memory
internally. It is a general convention in the library that functions
returning pointers to any MGRX specific data structure have a last
argument (most of the time named where
in the prototypes) which
can be used to pass the address of the data structure which should be filled
with the result. If this where
pointer has the value of NULL,
then the library allocates space for the data structure internally.
The memory
argument is really a 4 pointer array,
each pointer must point to space to handle GrPlaneSize(w,h)
bytes, really only GrNumPlanes()
pointers must be malloced, the
rest can be NULL. Nevertheless the normal use (see below) is gc =
GrCreateContext(w,h,NULL,NULL)
, so yo don't need to care about.
The function:
GrContext *GrCreateSubContext(int x1,int y1,int x2,int y2, const GrContext *parent,GrContext *where);
creates a new sub-context which maps to a part of an existing context. The
coordinate arguments (x1
through y
2) are
interpreted relative to the parent context's limits. Pixel addressing is
zero-based even in sub-contexts, i.e. the address of the top left pixel is
(0,0) even in a sub-context which has been mapped onto the interior of its
parent context.
Sub-contexts can be resized, but not their parents (i.e.
anything returned by GrCreateContext
or set up by
GrSetMode
cannot be resized -- because this could lead to
irrecoverable "loss" of drawing memory. The following function
can be used for this purpose:
void GrResizeSubContext(GrContext *context,int x1,int y1,int x2,int y2);
The current context structure is stored in a static location in the library. (For efficiency reasons -- it is used quite frequently, and this way no pointer dereferencing is necessary.) The context stores all relevant information about the video organization, coordinate limits, etc... The current context can be set with the:
void GrSetContext(const GrContext *context);
function. This function will reset the current context to the full
graphics screen if it is passed the NULL pointer as argument. The value of
the current context can be saved into a GrContext
structure
pointed to by where
using:
GrContext *GrSaveContext(GrContext *where);
again, if where
is NULL, the library allocates
the space, and you must remember to destory it, but remember this is a copy,
not the original context, so for typical use of this fuction (save the current
context, set a new context, do some drawings anf restore the original context)
is better to provide where
. Example:
void do_something() { GrContext grc; GrSaveContext(&grc); GrSetContext(another_context); ...do some drawing; GrSetContext(&grc); }
The next two functions:
const GrContext *GrCurrentContext(void); const GrContext *GrScreenContext(void);
return the current context and the screen context respectively. Contexts can be destroyed with:
void GrDestroyContext(GrContext *context);
This function will free the memory occupied by the context only if it was allocated originally by the library. The next three functions set up and query the clipping limits associated with the current context:
void GrSetClipBox(int x1,int y1,int x2,int y2); void GrGetClipBox(int *x1p,int *y1p,int *x2p,int *y2p); void GrResetClipBox(void);
GrResetClipBox
sets the clipping limits to the
limits of context. These are the limits set up initially when a context is
created. There are three similar functions to sets/gets the clipping limits
of any context:
void GrSetClipBoxC(GrContext *c,int x1,int y1,int x2,int y2); void GrGetClipBoxC(const GrContext *c,int *x1p,int *y1p,int *x2p,int *y2p); void GrResetClipBoxC(GrContext *c);
The limits of the current context can be obtained using the following functions:
int GrMaxX(void); int GrMaxY(void); int GrSizeX(void); int GrSizeY(void);
The Max
functions return the biggest valid
coordinate, while the Size
functions return a value one higher.
The size of the graphics screen (regardless of the current context) can be
obtained with:
int GrScreenX(void); int GrScreenY(void);
If you had set a virtual screen (using a custom graphics mode), the limits of the virtual screen can be fetched with:
int GrVirtualX(void); int GrVirtualY(void);
The routine:
int GrScreenIsVirtual(void);
returns non zero if a virtual screen is set. The rectangle showed in the real screen can be set with:
int GrSetViewport(int xpos,int ypos);
and the current viewport position can be obtained by:
int GrViewportX(void); int GrViewportY(void);
Here is an example of standard graphic context use:
GrContext *grc; if ((grc = GrCreateContext(w, h, NULL, NULL)) == NULL) { ...process the error } else { GrSetContext grc); /* now all drawing will be in grc! */ ...do some drawing ...and probably bitblt to the screen context GrSetContext(NULL); /* return to the screen context! */ GrDestroyContext(grc); }
But if you have a GrContext variable (not a pointer) that you want to use (probably because is static to some routines) you can do:
static GrContext grc; /* not a pointer!! */ if (GrCreateContext(w, h, NULL, &grc)) == NULL) { ...process the error } else { GrSetContext(&grc); /* now all drawing will be in grc! */ ...do some drawing ...and probably bitblt to the screen context GrSetContext(NULL); /* return to the screen context! */ GrDestroyContext(&grc); }
Note that GrDestoryContext
knows if grc was
automatically malloced or not!!
Only if you don't want GrCreateContext
use malloc
at all, you must allocate the memory buffers and pass it to
GrCreateContext
.
Using GrCreateSubContext
is the same, except it
doesn't need the buffer, because it uses the parent buffer.
Using contexts it is easy to implement double buffering, a technique to first draw each frame in memory and display them on screen at once, this makes changes to the screen appear much smoother:
GrContext *grc; if ((grc = GrCreateContext(GrScreenX(), GrScreenY(), NULL, NULL)) == NULL) { ...process the error and exit } GrSetContext( grc ); /* now all drawing will be in grc! */ while (1) { ...draw the frame GrBitBlt(GrScreenContext(), 0, 0, grc, 0, 0, grc->gc_xmax, grc->gc_ymax, GrWRITE); ...now process user input ...and break at exit }
MGRX defines the type GrColor
for color
variables. GrColor
it's a 32 bits integer. The 8 left bits are
reserved for the write mode (see below). The 24 bits right are the color
value.
The library supports two models for color management. In the 'indirect' (or color table) model, color values are indices to a color table. The color table slots will be allocated with the highest resolution supported by the hardware (EGA: 2 bits, VGA: 6 bits) with respect to the component color intensities. In the 'direct' (or RGB) model, color values map directly into component color intensities with non-overlapping bitfields of the color index representing the component colors.
Color table model is supported until 256 color modes. The RGB model is supported in 256 color and up color modes.
In RGB model the color index map to component color
intensities depend on the video mode set, so it can't be assumed the
component color bitfields (but if you are curious check the GrColorInfo
global structure in mgrx.h).
After the first GrSetMode
call two colors are
always defined: black and white. The color values of these two colors are
returned by the functions:
GrColor GrBlack(void); GrColor GrWhite(void);
GrBlack()
is guaranteed to be 0.
The library supports five write modes (a write mode descibes the operation between the actual bit color and the one to be set): write, XOR, logical OR, logical AND and IMAGE. These can be selected with OR-ing the color value with one of the following constants declared in mgrx.h :
#define GrWRITE 0UL /* write color */ #define GrXOR 0x01000000UL /* to "XOR" any color to the screen */ #define GrOR 0x02000000UL /* to "OR" to the screen */ #define GrAND 0x03000000UL /* to "AND" to the screen */ #define GrIMAGE 0x04000000UL /* BLIT: write, except given color */
The GrIMAGE
write mode only works with the
bitblt
function.
By convention, the no-op color is obtained by combining color value 0 (black) with the XOR operation. This no-op color has been defined in mgrx.h as:
#define GrNOCOLOR (GrXOR | 0) /* GrNOCOLOR is used for "no" color */
The write mode part and the color value part of a
GrColor
variable can be obtained OR-ing it with one of the following
constants declared in mgrx.h:
#define GrCVALUEMASK 0x00ffffffUL /* color value mask */ #define GrCMODEMASK 0xff000000UL /* color operation mask */
The number of colors in the current graphics mode is returned by the:
GrColor GrNumColors(void);
function, while the number of unused, available color can be obtained by calling:
GrColor GrNumFreeColors(void);
Colors can be allocated with the:
GrColor GrAllocColor(int r,int g,int b); GrColor GrAllocColor2(long hcolor);
functions (component intensities can range from 0 to 255,
hcolor
must be in 0xRRGGBB format), or with the:
GrColor GrAllocCell(void);
function. In the second case the component intensities of the returned color can be set with:
void GrSetColor(GrColor color,int r,int g,int b);
In the color table model all Alloc
functions
return GrNOCOLOR
if there are no more free colors available. In
the RGB model GrNumFreeColors
returns 0 and GrAllocCell
always returns GrNOCOLOR
, as colors returned
by GrAllocCell
are meant to be changed -- what is not supposed
to be done in RGB mode. Also note that GrAllocColor
operates
much more efficiently in RGB mode, and that it never returns GrNOCOLOR
in this case.
Color table entries can be freed (when not in RGB mode) by calling:
void GrFreeColor(GrColor color);
The component intensities of any color can be queried using one of this functions:
void GrQueryColor(GrColor c,int *r,int *g,int *b); void GrQueryColor2(GrColor c,long *hcolor);
Initially the color system is in color table (indirect) model if there are 256 or less colors. 256 color modes can be put into the RGB model by calling:
void GrSetRGBcolorMode(void);
The color system can be reset (i.e. put back into color table model if possible, all colors freed except for black and white) by calling:
void GrResetColors(void);
The function:
void GrRefreshColors(void);
reloads the currently allocated color values into the video hardware. This function is not needed in typical applications, unless the display adapter is programmed directly by the application.
This functions:
GrColor GrAllocColorID(int r,int g,int b); GrColor GrAllocColor2ID(long hcolor); void GrQueryColorID(GrColor c,int *r,int *g,int *b); void GrQueryColor2ID(GrColor c,long *hcolor);
are inlined versions (except if you compile MGRX with GRX_SKIP_INLINES defined) to be used in the RGB model (in the color table model they call the normal routines).
People that only want to use a few colors find the MGRX color handling a bit confusing, but it gives the power to manage a lot of color deeps and two color models. Here are some guidelines for using a few colors in a portable way in MGRX programs.
The "mgrxcolr.h" provides defines and functions to use three color tables, a EGA one with 16 colors that you can use with 4bpp and more graphics modes; another table with the 138 WEB colors, as defined by the w3.org, that you can use with 8bpp and more graphics modes; and a last one with the 256 ANSI colors for use too with 8bpp and more graphics modes.
For each table you have:
#define EGAR_BLACK 0x000000 #define EGAR_BLUE 0x0000AA #define EGAR_GREEN 0x00AA00 ... #define WEBR_ALICEBLUE 0xF0F8FF #define WEBR_ANTIQUEWHITE 0xFAEBD7 #define WEBR_AQUAMARINE 0x7FFFD4 ... #define ANSR_BLACK 0x000000 #define ANSR_MAROON 0x800000 #define ANSR_GREEN 0x008000 ...
You can use directly those defines to allocate colors with
GrAllocColor2(XXXR_xxx)
GrSetMode
to allocate colors:
extern GrColorTableDef GrEgaColorTable[]; int GrGenEgaColorTable(void); extern GrColorTableDef GrWebColorTable[]; int GrGenWebColorTable(void); extern GrColorTableDef GrAnsColorTable[]; int GrGenAnsColorTable(void);
As an extra in the tables are the color names.
#define EGAC_BLACK GrEgaColorTable[0].color #define EGAC_BLUE GrEgaColorTable[1].color #define EGAC_GREEN GrEgaColorTable[2].color ... #define WEBC_ALICEBLUE GrWebColorTable[0].color #define WEBC_ANTIQUEWHITE GrWebColorTable[1].color #define WEBC_AQUAMARINE GrWebColorTable[2].color ... #define ANSC_BLACK GrAnsColorTable[0].color #define ANSC_MAROON GrAnsColorTable[1].color #define ANSC_GREEN GrAnsColorTable[2].color ...
Note that you can't use those defines to initialize static variables because the corresponding table is not populated yet.
#define EGAI_BLACK 0 #define EGAI_BLUE 1 #define EGAI_GREEN 2 ... #define WEBI_ALICEBLUE 0 #define WEBI_ANTIQUEWHITE 1 #define WEBI_AQUAMARINE 2 ... #define ANSI_BLACK 0 #define ANSI_MAROON 1 #define ANSI_GREEN 2 ...
You can use those defines to initialize static variables, but to use the
colors you need to write GrXXXColorTable[XXXI_xxx].color
or the
macro XXXColor(XXXI_xxx)
There is an example of how to use each case in the "clrtable.c" test program.
This is the classic method to use the 16 EGA colors in a portable way that also works in versions prior to 1.1.2. We need this MGRX function:
GrColor *GrAllocEgaColors(void);
it returns a 16 GrColor
array with the 16 ega colors alloced
(really it's a trivial function, read the source src/setup/colorega.c).
We can use a construction like that:
First, in your C code make a global pointer, and init it after set the graphics mode:
GrColor *egacolors; .... int your_setup_function( ... ) { ... GrSetMode( ... ) ... egacolors = GrAllocEgaColors(); ... }
Next, add this to your main include file:
extern GrColor *egacolors; #define BLACK egacolors[0] #define BLUE egacolors[1] #define GREEN egacolors[2] #define CYAN egacolors[3] #define RED egacolors[4] #define MAGENTA egacolors[5] #define BROWN egacolors[6] #define LIGHTGRAY egacolors[7] #define DARKGRAY egacolors[8] #define LIGHTBLUE egacolors[9] #define LIGHTGREEN egacolors[10] #define LIGHTCYAN egacolors[11] #define LIGHTRED egacolors[12] #define LIGHTMAGENTA egacolors[13] #define YELLOW egacolors[14] #define WHITE egacolors[15]
Now you can use the defined colors in your code (by example:
GrClearScreen(YELLOW);
). Note that if
you are in color table model in a 16 color mode, you have exhausted the color
table. Note too that this don't work to initialize static variables with a
color, because egacolors is not initialized.
The screen, the current context or the current clip box can be cleared (i.e. set to a desired background color) by using one of the following three functions:
void GrClearScreen(GrColor bg); void GrClearContext(GrColor bg); void GrClearClipBox(GrColor bg);
Any context can be cleared using this function:
void GrClearContextC(GrContext *ctx, GrColor bg);
Thanks to the special GrColor
definition, you can
do more than simple clear with this functions, by example with:
GrClearScreen( GrWhite()|GrXOR );
the graphics screen is negativized, do it again and the screen is restored.
The following line drawing graphics primitives are supported by the library:
void GrPlot(int x,int y,GrColor c); void GrLine(int x1,int y1,int x2,int y2,GrColor c); void GrHLine(int x1,int x2,int y,GrColor c); void GrVLine(int x,int y1,int y2,GrColor c); void GrBox(int x1,int y1,int x2,int y2,GrColor c); void GrCircle(int xc,int yc,int r,GrColor c); void GrEllipse(int xc,int yc,int xa,int ya,GrColor c); void GrCircleArc(int xc,int yc,int r,int start,int end,int style,GrColor c); void GrEllipseArc(int xc,int yc,int xa,int ya, int start,int end,int style,GrColor c); void GrPolyLine(int numpts,int points[][2],GrColor c); void GrPolygon(int numpts,int points[][2],GrColor c);
All primitives operate on the current graphics context. The
last argument of these functions is always the color to use for the drawing.
The HLine
and VLine
primitives are for drawing
horizontal and vertical lines. They have been included in the library because
they are more efficient than the general line drawing provided by
GrLine
. The ellipse primitives can only draw ellipses with their major
axis parallel with either the X or Y coordinate axis. They take the half X
and Y axis length in the xa
and ya
arguments. The
arc (circle and ellipse) drawing functions take the start and end angles in
tenths of degrees (i.e. meaningful range: 0 ... 3600). The angles are
interpreted counter-clockwise starting from the positive X axis. The style
argument can be one of this defines from mgrx.h:
#define GR_ARC_STYLE_OPEN 0 #define GR_ARC_STYLE_CLOSE1 1 #define GR_ARC_STYLE_CLOSE2 2
GR_ARC_STYLE_OPEN
draws only the arc,
GR_ARC_STYLE_CLOSE1
closes the arc with a line between his start
and end point, GR_ARC_STYLE_CLOSE2
draws the typical cake slice.
This routine:
void GrLastArcCoords(int *xs,int *ys,int *xe,int *ye,int *xc,int *yc);
can be used to retrieve the start, end, and center points used by the last arc drawing functions.
The polyline and polygon primitives take the address of an n by 2 coordinate array. The X values should be stored in the elements with 0 second index, and the Y values in the elements with a second index value of 1. Coordinate arrays passed to the polygon primitive can either contain or omit the closing edge of the polygon -- the primitive will append it to the list if it is missing.
Because calculating the arc points it's a very time consuming operation, there are two functions to pre-calculate the points, that can be used next with polyline and polygon primitives:
int GrGenerateEllipse(int xc,int yc,int xa,int ya, int points[GR_MAX_ELLIPSE_POINTS][2]); int GrGenerateEllipseArc(int xc,int yc,int xa,int ya,int start,int end, int points[GR_MAX_ELLIPSE_POINTS][2]);
The following filled primitives are available:
void GrFilledBox(int x1,int y1,int x2,int y2,GrColor c); void GrFramedBox(int x1,int y1,int x2,int y2,int wdt,const GrFBoxColors *c); void GrFilledCircle(int xc,int yc,int r,GrColor c); void GrFilledEllipse(int xc,int yc,int xa,int ya,GrColor c); void GrFilledCircleArc(int xc,int yc,int r, int start,int end,int style,GrColor c); void GrFilledEllipseArc(int xc,int yc,int xa,int ya, int start,int end,int style,GrColor c); void GrFilledPolygon(int numpts,int points[][2],GrColor c); void GrFilledConvexPolygon(int numpts,int points[][2],GrColor c);
Similarly to the line drawing, all of the above primitives
operate on the current graphics context. The GrFramedBox
primitive can be used to draw motif-like shaded boxes and "ordinary" framed
boxes as well. The x1
through y2
coordinates
specify the interior of the box, the border is outside this area,
wdt
pixels wide. The primitive uses five different
colors for the interior and four borders of the box which are specified
in the GrFBoxColors
structure:
typedef struct { GrColor fbx_intcolor; GrColor fbx_topcolor; GrColor fbx_rightcolor; GrColor fbx_bottomcolor; GrColor fbx_leftcolor; } GrFBoxColors;
The GrFilledConvexPolygon
primitive can be used
to fill convex polygons. It can also be used to fill some concave polygons
whose boundaries do not intersect any horizontal scan line more than twice.
All other concave polygons have to be filled with the (somewhat less
efficient) GrFilledPolygon
primitive. This primitive can also
be used to fill several disjoint nonoverlapping polygons in a single
operation.
The function:
void GrFloodFill(int x, int y, GrColor border, GrColor c);
flood-fills the area bounded by the color border
using
x
, y
like the starting point.
Floodspill is a color replacer, replacing color A with color B. This is quite useful for highlighting a selected item in a list, or changing a selected color(s) in a multi colored area.
void GrFloodSpill(int x1, int y1, int x2, int y2, GrColor old_c, GrColor new_c)
replaces old color with new color in the rectangle bounded by x1, y1, x2, y2.
void GrFloodSpillC(GrContext *ctx, int x1, int y1, int x2, int y2, GrColor old_c, GrColor new_c)
as above but in the specified context.
void GrFloodSpill2(int x1, int y1, int x2, int y2, GrColor old_c1, GrColor new_c1, GrColor old_c2, GrColor new_c2)
replaces 2 colors, a one stop shop for highlighting a selection in a list.
void GrFloodSpillC2(GrContext *ctx, int x1, int y1, int x2, int y2, GrColor old_c1, GrColor new_c1, GrColor old_c2, GrColor new_c2)
as above but in the specified context.
The current color value of any pixel in the current context can be obtained with:
GrColor GrPixel(int x,int y);
and:
GrColor GrPixelC(GrContext *c,int x,int y);
do the same for any context.
Rectangular areas can be transferred within a context or between contexts by calling:
void GrBitBlt(GrContext *dest,int x,int y,GrContext *source, int x1,int y1,int x2,int y2,GrColor op);
x
, y
is the position in the destination context,
and x1
, y1
, x2
, y2
the area from the source context to be transfered. The op
argument should be one of supported color write modes (GrWRITE, GrXOR, GrOR,
GrAND, GrIMAGE), it will control how the pixels from the source context are
combined with the pixels in the destination context (the GrIMAGE op must be
ored with the color value to be handled as transparent). If either the source
or the destination context argument is the NULL pointer then the current
context is used for that argument.
GrBitblt works pixel by pixel, there is another function that can stretch the source to the destination:
void GrStretchBlt(GrContext *dst,int dx1,int dy1,int dx2,int dy2, GrContext *src,int x1,int y1,int x2,int y2,GrColor oper);
here dx1
, dy1
, dx2
, dy2
define the destination area to stretch the source area.
A efficient form to get/put pixels from/to a context can be achieved using the next functions:
const GrColor *GrGetScanline(int x1,int x2,int yy); const GrColor *GrGetScanlineC(GrContext *ctx,int x1,int x2,int yy); void GrPutScanline(int x1,int x2,int yy,const GrColor *c, GrColor op);
The Get
functions return a pointer to a static
GrColor
pixel array (or NULL if they fail) with the color values
of a row (yy
) segment (x1
to x2
).
GrGetScanline
uses the current context. GrGestScanlineC
uses the context ctx
(that can be NULL to refer to the
current context). Note that the output is only valid until the next
MGRX call.
GrPutScanline
puts the GrColor pixel array
c
on the yy
row segmet defined by x1
to x2
in the current context using the op
operation. op
can be any of GrWRITE
,
GrXOR
, GrOR
, GrAND
or
GrIMAGE
. Data in c
must fit GrCVALUEMASK
otherwise the results are implementation dependend. So you can't
supply operation code with the pixel data!.
There is a non-clipping version of some of the elementary primitives. These are somewhat more efficient than the regular versions. These are to be used only in situations when it is absolutely certain that no drawing will be performed beyond the boundaries of the current context. Otherwise the program will almost certainly crash! The reason for including these functions is that they are somewhat more efficient than the regular, clipping versions. ALSO NOTE: These function do not check for conflicts with the mouse cursor. (See the explanation about the mouse cursor handling later in this document.) The list of the supported non-clipping primitives:
void GrPlotNC(int x,int y,GrColor c); void GrLineNC(int x1,int y1,int x2,int y2,GrColor c); void GrHLineNC(int x1,int x2,int y,GrColor c); void GrVLineNC(int x,int y1,int y2,GrColor c); void GrBoxNC(int x1,int y1,int x2,int y2,GrColor c); void GrFilledBoxNC(int x1,int y1,int x2,int y2,GrColor c); void GrFramedBoxNC(int x1,int y1,int x2,int y2,int wdt,const GrFBoxColors *c); void GrBitBltNC(GrContext *dst,int x,int y,GrContext *src, int x1,int y1,int x2,int y2,GrColor op); GrColor GrPixelNC(int x,int y); GrColor GrPixelCNC(GrContext *c,int x,int y);
The basic line drawing graphics primitives described
previously always draw continuous lines which are one pixel wide. There is
another group of line drawing functions which can be used to draw wide
and/or patterned lines. These functions have similar parameter passing
conventions as the basic ones with one difference: instead of the color
value a pointer to a structure of type GrLineOption
has to be
passed to them. The definition of the GrLineOption
structure:
typedef struct { GrColor lno_color; /* color used to draw line */ int lno_width; /* width of the line */ int lno_pattlen; /* length of the dash pattern */ unsigned char *lno_dashpat; /* draw/nodraw pattern */ } GrLineOption;
The lno_pattlen
structure element should be equal
to the number of alternating draw -- no draw section length values in the
array pointed to by the lno_dashpat
element. The dash pattern
array is assumed to begin with a drawn section. If the pattern length is
equal to zero a continuous line is drawn.
Example, a white line 3 bits wide (thick) and pattern 6 bits draw, 4 bits nodraw:
GrLineOption mylineop; ... mylineop.lno_color = GrWhite(); mylineop.lno_width = 3; mylineop.lno_pattlen = 2; mylineop.lno_dashpat = "\x06\x04";
The available custom line drawing primitives:
void GrCustomLine(int x1,int y1,int x2,int y2,const GrLineOption *o); void GrCustomBox(int x1,int y1,int x2,int y2,const GrLineOption *o); void GrCustomCircle(int xc,int yc,int r,const GrLineOption *o); void GrCustomEllipse(int xc,int yc,int xa,int ya,const GrLineOption *o); void GrCustomCircleArc(int xc,int yc,int r, int start,int end,int style,const GrLineOption *o); void GrCustomEllipseArc(int xc,int yc,int xa,int ya, int start,int end,int style,const GrLineOption *o); void GrCustomPolyLine(int numpts,int points[][2],const GrLineOption *o); void GrCustomPolygon(int numpts,int points[][2],const GrLineOption *o);
The library also supports pattern filled and paterned versions
of the filled and custom primitives described above. These functions have similar
parameter passing conventions as the basic ones with one difference: instead
of the color value a pointer to an union of type 'GrPattern' has to be passed
to them. The GrPattern
union can contain a bitmap, a pixmap or a
gradient fill pattern. The first integer slot in the union determines which
type it is. Bitmap fill patterns are rectangular arrays of bits, each set
bit representing the foreground color of the fill operation, and each zero
bit representing the background. Both the foreground and background colors
can be combined with any of the supported logical operations. Bitmap fill
patterns have one restriction: their width must be eight pixels. Pixmap
fill patterns are very similar to contexts. Gradients are smooth color
changes, can be linear or radial. Gradients can be used only in rgb
color modes. The relevant structure
declarations (from mgrx.h):
#define GR_PTYPE_BITMAP 0 #define GR_PTYPE_PIXMAP 1 #define GR_PTYPE_GRADIENT 2 /* * BITMAP: a mode independent way to specify a fill pattern of two * colors. It is always 8 pixels wide (1 byte per scan line), its * height is user-defined. SET THE TYPE FLAG TO GR_PTYPE_BITMAP!!! */ typedef struct _GR_bitmap { int bmp_ptype; /* type flag for pattern union */ int bmp_height; /* bitmap height */ char *bmp_data; /* pointer to the bit pattern */ GrColor bmp_fgcolor; /* foreground color for fill */ GrColor bmp_bgcolor; /* background color for fill */ int bmp_memflags; /* set if dynamically allocated */ } GrBitmap; /* * PIXMAP: a fill pattern stored in a layout identical to the video RAM * for filling using 'bitblt'-s. It is mode dependent, typically one * of the library functions is used to build it. SET THE TYPE FLAG TO * GR_PTYPE_PIXMAP!!! */ typedef struct _GR_pixmap { int pxp_ptype; /* type flag for pattern union */ int pxp_width; /* pixmap width (in pixels) */ int pxp_height; /* pixmap height (in pixels) */ GrColor pxp_oper; /* bitblt mode (SET, OR, XOR, AND, IMAGE) */ struct _GR_frame pxp_source; /* source context for fill */ } GrPixmap; /* * GRADIENT: a fill pattern that change color in the direction defined by a * vector (linar gradient) or from the distance to a point (radial gradient). * Only can be used in rgb mode. SET THE TYPE FLAG TO GR_PTYPE_GRADIENT!!! */ typedef struct { int xi, yi, xf, yf; // vector that define the gradient float dist_if; // distance from i to f (calculated) } GrGrdLinearData; typedef struct { int xc, yc, r; // center and radius that define the gradient } GrGrdRadialData; typedef struct { int dist; // normalized distance (0 to 255) GrColor c; // color } GrGrdStop; #define GR_LINEAR_GRADIENT 0 #define GR_RADIAL_GRADIENT 1 #define GR_GRADIENT_MAXSTOPS 10 typedef struct { int grd_ptype; // type flag for pattern union int grd_mode; // gradient mode (linear or radial) GrColor grd_oper; // bitblt mode (SET, OR, XOR, AND, IMAGE) int grd_memflags; // set if dynamically allocated union { GrGrdLinearData grd_ld; // linear data GrGrdRadialData grd_rd; // radial data }; int grd_nstops; // num of stops GrGrdStop grd_stop[GR_GRADIENT_MAXSTOPS]; // stop definition int grd_genctbl; // color table has been generated 1=yes 0=no GrColor grd_ctbl[257]; // color table ctbl[0]=num_colors=256 ever } GrGradient; /* * Fill pattern union -- can either be a bitmap, a pixmap or a gradient */ typedef union _GR_pattern { int gp_ptype; /* type flag */ GrBitmap gp_bitmap; /* fill bitmap */ GrPixmap gp_pixmap; /* fill pixmap */ GrGradient gp_gradient; /* fill gradient */ } GrPattern;
This define group (from mgrx.h) help to acces the
GrPattern
menbers:
#define gp_bmp_data gp_bitmap.bmp_data #define gp_bmp_height gp_bitmap.bmp_height #define gp_bmp_fgcolor gp_bitmap.bmp_fgcolor #define gp_bmp_bgcolor gp_bitmap.bmp_bgcolor #define gp_pxp_width gp_pixmap.pxp_width #define gp_pxp_height gp_pixmap.pxp_height #define gp_pxp_oper gp_pixmap.pxp_oper #define gp_pxp_source gp_pixmap.pxp_source #define gp_grd_mode gp_gradient.grd_mode #define gp_grd_oper gp_gradient.grd_oper #define gp_grd_memflags gp_gradient.grd_memflags #define gp_grd_ld gp_gradient.grd_ld #define gp_grd_rd gp_gradient.grd_rd #define gp_grd_nstops gp_gradient.grd_nstops #define gp_grd_stop gp_gradient.grd_stop #define gp_grd_genctbl gp_gradient.grd_genctbl #define gp_grd_ctbl gp_gradient.grd_ctbl
Bitmap patterns can be easily built from initialized character arrays and static structures by the C compiler, thus no special support is included in the library for creating them. The only action required from the application program might be changing the foreground and background colors as needed. Here is an example:
unsigned char bmpdata[8] = {0x00, 0x7E, 0x82, 0x82, 0x82, 0x82, 0x7E, 0x00}; GrBitmap bm1 = {GR_PTYPE_BITMAP, 8, NULL, 0, 0, 0}; bm1.bmp_fgcolor = GrWhite(); bm1.bmp_bgcolor = GrBlack(); bm1.bmp_data = (char *)bmpdata;
Pixmap patterns are more difficult to build as they replicate the layout of the video memory which changes for different video modes. For this reason the library provides three functions to create pixmap patterns in a mode-independent way:
GrPattern *GrBuildPixmap(const char *pixels,int w,int h,const GrColorTableP ct); GrPattern *GrBuildPixmapNR(const char *pixels,int w,int h,const GrColorTableP ct); GrPattern *GrBuildPixmapFromBits(const char *bits,int w,int h, GrColor fgc,GrColor bgc); GrPattern *GrBuildPixmapFromBitsNR(const char *bits,int w,int h, GrColor fgc,GrColor bgc); GrPattern *GrConvertToPixmap(GrContext *src);
GrBuildPixmap
build a pixmap from a two
dimensional (w
by h
) array of characters. The
elements in this array are used as indices into the color table specified
with the argument ct
. (This means that pixmaps created
this way can use at most 256 colors.) The color table pointer:
typedef GrColor *GrColorTableP;
should point to an array of integers with the first element being the number of colors in the table and the color values themselves starting with the second element. NOTE: any color modifiers (GrXOR, GrOR, GrAND) OR-ed to the elements of the color table are ignored.
The GrBuildPixmapFromBits
function builds a
pixmap fill pattern from bitmap data. It is useful if the width of the
bitmap pattern is not eight as such bitmap patterns can not be used to build
a GrBitmap
structure.
Either GrBuildPixmapFromBits
and
GrBuildPixmap
can return a pixmap wider than w
up to a multiple of 8 bytes for faster bitblt's. If that conduct is not
desirable use the NR versions of the functions.
The GrConvertToPixmap
function converts a
graphics context to a pixmap fill pattern. It is useful when the pattern
can be created with graphics drawing operations. NOTE: the pixmap pattern
and the original context share the drawing RAM, thus if the context is
redrawn the fill pattern changes as well.
Gradients can be build by simple code or using functions from the library. First you call one of these:
GrPattern *GrCreateLinGradient(int xi, int yi, int xf, int yf); GrPattern *GrCreateRadGradient(int xc, int yc, int r);
to create a linear or a radial gradient. After that you define the gradient stop points using:
int GrAddGradientStop(GrPattern *p, int dist, GrColor c);
dist
is a integer normalized distance, from 0 to 255, that
represent the distance from (xi,yi) to (xf,yf) or (r). Here is an simple
example for a radial gradient with 3 stop points:
rg1 = GrCreateRadGradient(GrMaxX()/2, GrMaxY()/2, GrMaxX()/2); if (rg1 == NULL) goto error; GrAddGradientStop(rg1, 0, GrAllocColor(255, 0, 0)); GrAddGradientStop(rg1, 128, GrAllocColor(0, 0, 255)); GrAddGradientStop(rg1, 255, GrAllocColor(0, 255, 0)); GrGenGradientColorTbl(rg1);
In any case, after creating the gradient you must call a function to populate the color table that defines the gradient:
int GrGenGradientColorTbl(GrPattern *p);
When drawing with a gradient, the lib must calculate the distance to show the correct color for every point. If you want the same gradient a lot of times is faster to generate first a pixmap from the gradient:
GrPattern *GrBuildPixmapFromGradient(GrPattern *p, int xo, int yo, int w, int h);
w,h
will be the pixmap dimensions, and xo,yo
the
gradient pos that will correspond to the 0,0 pixmap point.
Patterns which were built by library routines can be destroyed when no longer needed (i.e. the space occupied by them can be freed) by calling:
void GrDestroyPattern(GrPattern *p);
NOTE: when pixmap patterns converted from contexts are destroyed, the drawing RAM is not freed. It is freed when the original context is destroyed. Fill patterns built by the application have to be destroyed by the application as well (if this is needed).
The list of supported pattern filled graphics primitives is shown below. These functions are very similar to their solid filled counterparts, only their last argument is different:
void GrPatternFilledPlot(int x,int y,GrPattern *p); void GrPatternFilledLine(int x1,int y1,int x2,int y2,GrPattern *p); void GrPatternFilledBox(int x1,int y1,int x2,int y2,GrPattern *p); void GrPatternFilledCircle(int xc,int yc,int r,GrPattern *p); void GrPatternFilledEllipse(int xc,int yc,int xa,int ya,GrPattern *p); void GrPatternFilledCircleArc(int xc,int yc,int r,int start,int end, int style,GrPattern *p); void GrPatternFilledEllipseArc(int xc,int yc,int xa,int ya,int start,int end, int style,GrPattern *p); void GrPatternFilledConvexPolygon(int numpts,int points[][2],GrPattern *p); void GrPatternFilledPolygon(int numpts,int points[][2],GrPattern *p); void GrPatternFloodFill(int x, int y, GrColor border, GrPattern *p);
All the above functions align the pattern origin with the context origin. Most of the time it is what is expected, so two intersecting shapes show a continuous pattern. But some times it is needing to align to other point, next functions do that:
void GrPatAlignFilledPlot(int xo,int yo,int x,int y,GrPattern *p); void GrPatAlignFilledLine(int xo,int yo,int x1,int y1,int x2,int y2,GrPattern *p); void GrPatAlignFilledBox(int xo,int yo,int x1,int y1,int x2,int y2,GrPattern *p); void GrPatAlignFilledCircle(int xo,int yo,int xc,int yc,int r,GrPattern *p); void GrPatAlignFilledEllipse(int xo,int yo,int xc,int yc,int xa,int ya,GrPattern *p); void GrPatAlignFilledCircleArc(int xo,int yo,int xc,int yc,int r, int start,int end,int style,GrPattern *p); void GrPatAlignFilledEllipseArc(int xo,int yo,int xc,int yc,int xa,int ya, int start,int end,int style,GrPattern *p); void GrPatAlignFilledConvexPolygon(int xo,int yo,int n,int pt[][2],GrPattern *p); void GrPatAlignFilledPolygon(int xo,int yo,int n,int pt[][2],GrPattern *p); void GrPatAlignFloodFill(int xo,int yo,int x, int y, GrColor border, GrPattern *p);
There are two functions to display all or part of a pixmap in the current context, aligning to the display box:
void GrPixmapDisplay(int x,int y, GrPixmap *p); void GrPixmapDisplayExt(int x1,int y1,int x2,int y2, GrPixmap *p);
And two others to transform pixmaps:
GrPixmap *GrPixmapInverse(GrPixmap *p,int flag); GrPixmap *GrPixmapStretch(GrPixmap *p,int nwidth,int nheight);
GrPixmapInverse
creates a new pixmap
flipping p
left-right or top-down as indicated by flag
that can be:
#define GR_PIXMAP_INVLR 0x01 /* inverse left right */ #define GR_PIXMAP_INVTD 0x02 /* inverse top down */
GrPixmapStretch
creates a new pixmap stretching
p
to nwidth
by nheight
.
The custom line drawing functions introduced above also have
a version when the drawn sections can be filled with a (bitmap, pixmap or gradient)
fill pattern. To achieve this these functions must be passed both a custom
line drawing option (GrLineOption
structure) and a fill pattern
(GrPattern
union). These two have been combined into the
GrLinePattern
structure:
typedef struct { GrPattern *lnp_pattern; /* fill pattern */ GrLineOption *lnp_option; /* width + dash pattern */ } GrLinePattern;
All patterned line drawing functions take a pointer to this structure as their last argument. The list of available functions:
void GrPatternedLine(int x1,int y1,int x2,int y2,GrLinePattern *lp); void GrPatternedBox(int x1,int y1,int x2,int y2,GrLinePattern *lp); void GrPatternedCircle(int xc,int yc,int r,GrLinePattern *lp); void GrPatternedEllipse(int xc,int yc,int xa,int ya,GrLinePattern *lp); void GrPatternedCircleArc(int xc,int yc,int r,int start,int end, int style,GrLinePattern *lp); void GrPatternedEllipseArc(int xc,int yc,int xa,int ya,int start,int end, int style,GrLinePattern *lp); void GrPatternedPolyLine(int numpts,int points[][2],GrLinePattern *lp); void GrPatternedPolygon(int numpts,int points[][2],GrLinePattern *lp);
Again the above functions align the pattern origin with the context origin. To align with another point use next functions:
void GrPatndAlignLine(int xo,int yo,int x1,int y1,int x2,int y2,GrLinePattern *lp); void GrPatndAlignBox(int xo,int yo,int x1,int y1,int x2,int y2,GrLinePattern *lp); void GrPatndAlignCircle(int xo,int yo,int xc,int yc,int r,GrLinePattern *lp); void GrPatndAlignEllipse(int xo,int yo,int xc,int yc,int xa,int ya,GrLinePattern *lp); void GrPatndAlignCircleArc(int xo,int yo,int xc,int yc,int r, int start,int end,int style,GrLinePattern *lp); void GrPatndAlignEllipseArc(int xo,int yo,int xc,int yc,int xa,int ya, int start,int end,int style,GrLinePattern *lp); void GrPatndAlignPolyLine(int xo,int yo,int numpts,int points[][2],GrLinePattern *lp); void GrPatndAlignPolygon(int xo,int yo,int numpts,int points[][2],GrLinePattern *lp);
New in MGRX 1.4.3 version are multipolygons, they let fill and draw a group of polygons at once, so figures with holes can be drawn and filled. A multipolygon must be defined with a GrMultiPointArray structure:
typedef struct { int npoints; // number of points int closed; // closed polygon if != 0 (not used for fill) int (*points)[2]; // Points array } GrPointArray; typedef struct { int npa; // number of point arrays GrPointArray p[1]; // Points arrays (not actual size) } GrMultiPointArray;
You can fill a multipolygon with a solid color or a pattern using next functions:
void GrFilledMultiPolygon(GrMultiPointArray *mpa,GrColor c); void GrPatternFilledMultiPolygon(GrMultiPointArray *mpa,GrPattern *p); void GrPatAlignFilledMultiPolygon(int xo,int yo,GrMultiPointArray *mpa,GrPattern *p);
And draw the multipolygon borders with a solid color or a pattern, even with a specific thick like we explained in previous chapters:
void GrMultiPolygon(GrMultiPointArray *mpa,GrColor c); void GrCustomMultiPolygon(GrMultiPointArray *mpa,const GrLineOption *o); void GrPatternedMultiPolygon(GrMultiPointArray *mpa,GrLinePattern *lp); void GrPatndAlignMultiPolygon(int xo,int yo,GrMultiPointArray *mpa,GrLinePattern *lp);
Note that you can not achieve the fill effect on multipolygons using normal fill polygon functions, but the draw functions are convenient functions only, the same effect can be reached using the normal polygon (for closed ones) or polyline (for opened ones) functions iterating over each member of the GrMultiPointArray struct.
If you use only ASCII text you can skip this chapter, set
the chrtype
to GR_BYTE_TEXT
(see below) and go ahead.
But if you need to use extended chars you need to know abour character
encodings. MGRX has (limited) support for extended encodings.
The problem is that you can have different encodings for your source code, for the fonts you are using and for the machine where your program is finally running. To manage this MGRX has four concepts:
The User encoding is the source code encoding, the encoding the programmer have used when he wrote the source. The supported encodings are:
#define GRENC_CP437 0 /* standard DOS encoding */ #define GRENC_CP850 1 /* latin1 DOS encoding */ #define GRENC_CP1252 2 /* standard Latin Win encoding */ #define GRENC_ISO_8859_1 3 /* standard in some Linux */ #define GRENC_UTF_8 4 /* multibyte unicode, standard in newest Linux */ #define GRENC_UCS_2 5 /* restricted unicode, 2 bytes, only BMP range */ #define GRENC_CP1251 6 /* standard Cyrillic Win encoding */ #define GRENC_CP1253 7 /* standard Greek Win encoding */ #define GRENC_LASTENCODE 7 /* last encode, for checks */
By default MGRX sets the user encoding to GRENC_UTF_8
in linux
console and X11, to GRENC_PC437
in DJGPP and to
GRENC_PC1252
in Win32 after the first graphic mode is set.
But as a programmer you know better what is the user encoding really used in the
source code, so set it whit the GrSetUserEncoding
function. You can
set it even before the first graphics mode is set, in this case, MGRX will
not change it.
int GrGetUserEncoding(void); int GrSetUserEncoding(int enc);
The Font encoding is obsviusly the encoding used by the font glyphs, the supported font encodings are:
#define GR_FONTENC_UNKNOWN 0 /* unknown encoding (no recode) */ #define GR_FONTENC_CP437 1 /* standard dos encoding */ #define GR_FONTENC_CP850 2 /* standard dos encoding */ #define GR_FONTENC_CP1252 3 /* standard Latin Win encoding */ #define GR_FONTENC_ISO_8859_1 4 /* standard latin encoding */ #define GR_FONTENC_UNICODE 5 /* direct UNICODE encoding */ #define GR_FONTENC_MGRX512 6 /* custom MGRX 512 char encoding */ #define GR_FONTENC_ISO_8859_5 7 /* ASCII + Cyrillic */ #define GR_FONTENC_ISO_8859_7 8 /* ASCII + Greek */ #define GR_FONTENC_CP437EXT 9 /* CP437 + ISO-8859-1 + CP1252 */ #define GR_FONTENC_CP1251 10 /* standard Cyrillic Win encoding */ #define GR_FONTENC_CP1253 11 /* standard Greek Win encoding */ #define GR_FONTENC_LASTENC 11 /* last encoding, for checks */
Only the fonts provided whit MGRX in his own format (.fnt) have the
font encoding set in their heading data, but after loading a font, you can set their
encoding with the GrFontSetEncoding
function.
void GrFontSetEncoding(GrFont *font,int fontencoding);
The MGRX512 font encoding is a specially crafted encoding used by some of the fonts provided with MGRX. It has 512 glyphs covering Latin, Cyrilic and Greek and some other miscellaneous glyphs. See the doc/mgrx512.txt file for more information.
The CP437EXT font encoding is another MGRX custom encoding that cover CP437 + ISO8859-1 + CP1252 (by now) providing 323 glyphs. See the doc/cp437ext.txt file for more information.
Chrtype is the specific encoding used for a text string you want to draw, it can be one of these:
#define GR_BYTE_TEXT 0 /* 1 byte per character, unknown encoding */ #define GR_WORD_TEXT 1 /* 2 bytes per character, unknown encoding */ #define GR_CP437_TEXT 2 /* 1 bpc standard DOS encoding */ #define GR_CP850_TEXT 3 /* 1 bpc latin1 DOS encoding */ #define GR_CP1252_TEXT 4 /* 1 bpc standard Latin Win encoding */ #define GR_ISO_8859_1_TEXT 5 /* 1 bpc latin1 standard in some Linux */ #define GR_UTF8_TEXT 6 /* multibyte UTF-8 Unicode, restricted to 4 bytes */ #define GR_UCS2_TEXT 7 /* 2 bpc restricted Unicode, only BMP range */ #define GR_CP1251_TEXT 8 /* 1 bpc standard Cyrillic Win encoding */ #define GR_CP1253_TEXT 9 /* 1 bpc standard Greek Win encoding */
You can set the chrtype individually for every string you need to draw.
There is a funtion to get the corresponding chrtype for the User encoding:
char GrGetChrtypeForUserEncoding(void);
It takes advantage that the corresponding chrtype is "Userencoding + 2" so have these into account if you want to add more encodings to MGRX.
The MGRX text drawing funtions will try to recode from chrtype to the Font encoding before draw text.
The GR_BYTE_TEXT
and GR_WORD_TEXT
are there for
historical reasons and don't have a corresponding User encoding. Because they are
reallly unknown encodings you can use them to draw font glyphs because they will
not be recoded.
The KbSys encoding is the encoding used by the computer, where the program is executed, to get input from the keyboard. It can be one of the defined "user encoding".
Every input driver try to guess the KbSys encoding used for the running program, if not sure it uses the MGRXKBSYSENCODING environment variable that can be set by users to one of these strings: "CP437", "CP850", "CP1251", "CP1252", "CP1253", "ISO_8859_1", "UTF_8" or "UCS_2". The KbSys encoding can be get using this function:
int GrGetKbSysEncoding(void);
If the KbSys encoding is different from the User encoding, the input driver will
recode key events from KbSys encoding to User encoding. So using by example
GrSetUserEncoding(GRENC_UTF_8);
you can write a portable program that
gets UTF-8 encoded keys in every platform.
The library supports loadable fonts. When in memory they are bit-mapped (i.e. not scalable!) fonts. A driver design allow MGRX to load different font formats, the last MGRX release come with drivers to load the MGRX own font format, the BGI Borland format, the FNA ascii font format, the PSF formats 1 & 2, the windows resource font format and (only for the X11 version) the X11 raster font format.
The MGRX distribution come with a font collection in the MGRX own format. Some of these fonts were converted from VGA fonts, these fonts have all 256 characters from the CP437 or CP850 codepage. Some fonts were converted from fonts in the MIT X11 distribution, these are ASCII or ISO-8859-1 coded. A group of fonts were converted from the Terminus font and are MGRX512 encoded. There are too two big unicode fonts. The following fonts are included:
Font file name Family Description pc<W>x<H>[t].fnt pc pc font, fixed, CP437 px<W>x<H>.fnt pcext pc font, fixed, CP437EXT pc850-<H>[t].fnt pc pc font, fixed, CP850 xm<W>x<H>[b][i].fnt X_misc X11, fixed, miscellaneous group, ASCII char<H>[b][i].fnt char X11, proportional, charter family, ISO-8859-1 cour<H>[b][i].fnt cour X11, fixed, courier, ISO-8859-1 helv<H>[b][i].fnt helve X11, proportional, helvetica, ISO-8859-1 lucb<H>[b][i].fnt lucb X11, proportional, lucida bright, ISO-8859-1 lucs<H>[b][i].fnt lucs X11, proportional, lucida sans serif , ISO-8859-1 luct<H>[b][i].fnt luct X11, fixed, lucida typewriter, ISO-8859-1 ncen<H>[b][i].fnt ncen X11, proportional, new century schoolbook, ISO-8859-1 symb<H>.fnt symbol X11, proportional, greek letters, symbols tms<H>[b][i].fnt times X11, proportional, times, ISO-8859-1 tmgrx<H>[b].fnt tmgrx Ter, fixed, MGRX512 unifont.fnt unifont Converted from Unifont, propotional, Unicode unimk20.fnt unimk X11, propotional, Unicode
In the font names <W> means the font width, <H> the font height. Many font families have bold and/or italic variants. The files containing these fonts contain a 'b' and/or 'i' character in their name just before the extension. Some of the pc fonts come in thin formats also, these are denoted by a 't' in their file names.
A full font list is in the fonts/_fonts.dir file. Please read the copying.grx file to know about font licenses.
The GrFont
structure hold a font in memory. A
number of 'pc' fonts are built-in to the library and don't need to be
loaded:
extern GrFont GrFont_PC6x8; extern GrFont GrFont_PC8x8; extern GrFont GrFont_PC8x14; extern GrFont GrFont_PC8x16; extern GrFont GrFont_PX8x18; extern GrFont GrFont_PX11x22; extern GrFont GrFont_PX14x28;
The first four are CP437 coded and the last three CP437EXT.
Other fonts must be loaded with the GrLoadFont
function. If the font file name starts with any path separator character
or character sequence ('<drive letter>:', '/' or '\') then it is loaded
from the specified directory, otherwise the library try load the font first
from the current directory and next from the default font path. The font
path can be set up with the GrSetFontPath
function. If the font
path is not set then the value of the 'GRXFONT' environment variable is used
as the font path. GrLoadFont
will try every font driver, adding
the driver extension if necesary. Font loading routines return NULL if the
font was not found. When not needed any more, fonts can be unloaded (i.e.
the storage occupied by them freed) by calling GrUnloadFont
.
The prototype declarations for these functions:
GrFont *GrLoadFont(char *name); void GrUnloadFont(GrFont *font); void GrSetFontPath(char *path_list);
Using these functions:
GrFont *GrLoadConvertedFont(char *name,int cvt,int w,int h, int minch,int maxch); GrFont *GrBuildConvertedFont(const GrFont *from,int cvt,int w,int h, int minch,int maxch);
a new font can be generated from a file font or a font in memory, the 'cvt' argument direct the conversion or-ing the desired operations from these defines:
/* * Font conversion flags for 'GrLoadConvertedFont'. OR them as desired. */ #define GR_FONTCVT_NONE 0 /* no conversion */ #define GR_FONTCVT_SKIPCHARS 1 /* load only selected characters */ #define GR_FONTCVT_RESIZE 2 /* resize the font */ #define GR_FONTCVT_ITALICIZE 4 /* tilt font for "italic" look */ #define GR_FONTCVT_BOLDIFY 8 /* make a "bold"(er) font */ #define GR_FONTCVT_FIXIFY 16 /* convert prop. font to fixed wdt */ #define GR_FONTCVT_PROPORTION 32 /* convert fixed font to prop. wdt */
GR_FONTCVT_SKIPCHARS
needs 'minch' and 'maxch'
arguments.
GR_FONTCVT_RESIZE
needs 'w' and 'h' arguments.
The function:
GrFont *GrLoadFontFile(char *name, char *driver);
will try to load the named font file using the font driver specified bypassing the normal lookup.
The function:
int GrDumpGrxFont(const GrFont *f, char *fileName);
writes a font to a file int the MGRX own format. It returns 0 on error or 1 on succes.
The function:
int GrDumpFnaFont(const GrFont *f, char *fileName);
writes a font to an ascii font file, so it can be quickly edited with a text editor. For a description of the ascii font format, see the doc/fna.txt file. It returns 0 on error or 1 on succes.
The function:
int GrDumpFont(const GrFont *f,char *CsymbolName,char *fileName);
writes a font to a C source code file, so it can be compiled and linked
with a user program. GrDumpFont
would not normally be used in
a released program because its purpose is to produce source code. When the
source code is compiled and linked into a program distributing the font
file with the program is not necessary, avoiding the possibility of the
font file being deleted or corrupted.
You can use the premade src/utilprog/fnt2c.c program (see the source, it's so simple) to dump a selected font to source code, by example:
"fnt2c helv15 myhelv15.c myhelv15"
Next, if this line is included in your main include file:
extern GrFont myhelv15
and "myhelv15.c" compiled and linked with your project, you can use
'myhelv15' in every place a GrFont
is required.
This simple function:
void GrTextXY(int x,int y,char *text,GrColor fg,GrColor bg);
draw text in the current context in the standard direction, using the
Default Font (set initially to GrFont_PC8x14
but can be changed),
using the chrtype corresponding to the user encoding,
with x
, y
like the upper left corner and the
foreground and background colors given (note that bg
equal
to GrNOCOLOR
make the background transparent).
the Default Font can be get or set with these functions:
GrFont *GrGetDefaultFont(); void GrSetDefaultFont(GrFont *font);
For other functions the GrTextOption
structure
specifies how to draw a character string:
typedef struct _GR_textOption { /* text drawing option structure */ GrFont *txo_font; /* font to be used */ GrColor txo_fgcolor; /* foreground color */ GrColor txo_bgcolor; /* background color */ char txo_chrtype; /* character type (see above) */ char txo_direct; /* direction (see above) */ char txo_xalign; /* X alignment (see above) */ char txo_yalign; /* Y alignment (see above) */ } GrTextOption;
The text can be rotated in increments of 90 degrees
(txo_direct
), alignments can be set in both directions
(txo_xalign
and txo_yalign
), and separate
fore and background colors can be specified. The accepted text
direction values:
#define GR_TEXT_RIGHT 0 /* normal */ #define GR_TEXT_DOWN 1 /* downward */ #define GR_TEXT_LEFT 2 /* upside down, right to left */ #define GR_TEXT_UP 3 /* upward */ #define GR_TEXT_DEFAULT GR_TEXT_RIGHT
The accepted horizontal and vertical alignment option values:
#define GR_ALIGN_LEFT 0 /* X only */ #define GR_ALIGN_TOP 0 /* Y only */ #define GR_ALIGN_CENTER 1 /* X, Y */ #define GR_ALIGN_RIGHT 2 /* X only */ #define GR_ALIGN_BOTTOM 2 /* Y only */ #define GR_ALIGN_BASELINE 3 /* Y only */ #define GR_ALIGN_DEFAULT GR_ALIGN_LEFT
Text strings chrtype must be one of the types defined in the
previous section. With GR_BYTE_TEXT
and GR_WORD_TEXT
there will be no recoding, so is up to you to select a font that match the
text encoding you are using.
Remember that GR_WORD_TEXT
and GR_UCS2_TEXT
are two bytes per character. GR_UTF8_TEXT
is the standard multibyte
UTF-8 encoding. All other chrtypes are one byte per character.
Text strings can also be drawn underlined. This is controlled
by OR-ing the constant GR_UNDERLINE_TEXT
to the foreground color
value:
#define GR_UNDERLINE_TEXT (GrXOR << 4)
After the application initializes a text option structure with the desired values it can call one of the following two text drawing functions:
void GrDrawChar(long chr,int x,int y,const GrTextOption *opt); void GrDrawString(void *text,int length,int x,int y,const GrTextOption *opt);
You must set the length
parameter according to
the indicated chrtype, it must be number of words for GR_WORD_TEXT
and GR_UCS2_TEXT
, the real number of characters for
GR_UTF8_TEXT
, or the number of bytes for the rest of chrtypes.
If the string is NULL terminated you can set length
to 0, and the
function will calculate the lenght according to the chrtype.
NOTE: text drawing is fastest when it is drawn in the 'normal' direction, and the character does not have to be clipped. It this case the library can use the appropriate low-level video RAM access routine, while in any other case the text is drawn pixel-by-pixel by the higher-level code.
There are pattern filed versions too:
void GrPatternDrawChar(long chr,int x,int y,const GrTextOption *opt,GrPattern *p); void GrPatternDrawString(void *text,int length,int x,int y, const GrTextOption *opt,GrPattern *p); void GrPatternDrawCharExt(long chr,int x,int y,const GrTextOption *opt,GrPattern *p); void GrPatternDrawStringExt(void *text,int length,int x,int y, const GrTextOption *opt,GrPattern *p);
the first two align the pattern origin with the context origin. The last two align with the text box.
The size of a font, a character or a text string can be obtained by calling one of the following functions. These functions also take into consideration the text direction specified in the text option structure passed to them.
int GrFontCharPresent(const GrFont *font,int chr); int GrFontCharWidth(const GrFont *font,int chr); int GrFontCharHeight(const GrFont *font,int chr); int GrFontCharBmpRowSize(const GrFont *font,int chr); int GrFontCharBitmapSize(const GrFont *font,int chr); int GrFontStringWidth(const GrFont *font,void *text,int len,int chrtype); int GrFontStringHeight(const GrFont *font,void *text,int len,int chrtype); int GrCharWidth(long chr,const GrTextOption *opt); int GrCharHeight(long chr,const GrTextOption *opt); void GrCharSize(long chr,const GrTextOption *opt,int *w,int *h); int GrStringWidth(void *text,int length,const GrTextOption *opt); int GrStringHeight(void *text,int length,const GrTextOption *opt); void GrStringSize(void *text,int length,const GrTextOption *opt,int *w,int *h);
The first five funtions don't recode, so the chr
parameter is really the font glyph index. All other fucntions recode if needed.
If the string is NULL terminated you can set length
to 0, and
let the function calculate the lenght according to the chrtype.
To deal with GR_UTF8_TEXT
, MGRX provides some special
funtions:
int GrUTF8StrLen(unsigned char *s);
returns the number of UTF-8 characters (not bytes) in s
.
int GrStrLen(const void *text, int chrtype);
is a more general function that returns the number of characters according to the chrtype provided.
long GrUCS2ToUTF8(unsigned short ch);
converts a UCS-2 word character to a UTF-8 string packed in a long for convenience (some functions use it, see bellow).
long GrNextUTF8Char(unsigned char *s, int *nb);
returns the first UTF-8 character packed in a long, it sets nb
to the number of bytes consumed, so you can advance the string pointer to the
next character.
unsigned short GrUTF8ToUCS2(unsigned char *s);
converts the first UTF-8 character in s
to a a UCS-2
word character.
unsigned short *GrUTF8StrToUCS2Str(unsigned char *s, int *ulen, int maxlen); unsigned char *GrTextRecodeToUTF8(const void *text,int length,int chrtype); void *GrTextRecodeFromUTF8(const unsigned char *text,int length,int chrtype);
GrUTF8StrToUCS2Str
converts a UTF-8 string to a UCS-2 string and
set the ulen
variable with the UTF-8 string length. The
maxlen
parameter indicates the maximum len you want, a 0 indicates
no maxlen. GrTextRecodeFromUTF8
is a more generic funtion to recode
from UTF-8 to any chrtype
, and GrTextRecodeToUTF8
do
the opposite. All function allocate the necesary memory, so you must check the
returned pointer for NULL, and the memory must be freed when unneded.
For font related functions that expect a string and a length you must pass the UTF-8 string and the UTF-8 length (or less) in characters (not byres), example:
opt.txo_chrtype = GR_UTF8_TEXT; GrDrawString(sutf8, GrUTF8StrLen(sutf8), x, y, opt);
sutf8
is NULL terminated you can let the function
do the calculation:
opt.txo_chrtype = GR_UTF8_TEXT; GrDrawString(sutf8, 0, x, y, opt);
For font related functions that expect a unique character packed in a long and a chrtype, you need to pack the UTF-8 char in a long, example:
long *c; char cutf8[4]; ... put in cutf8 the character; // 1 to four bytes, fill with 0 the unused bytes!! c = (long *)&cutf8; opt.txo_chrtype = GR_UTF8_TEXT; void GrDrawChar(*c, x, y, opt);
or e.g. using the GrNextUTF8Char function:
long c; ... c = GrNextUTF8Char(sutf8, &nb); opt.txo_chrtype = GR_UTF8_TEXT; void GrDrawChar(c, x, y, opt);
For font functions that expect a unique character (really a glyph number) without chrtype, you must pass the UCS-2 equivalent character, example:
GrFontCharWidth(font,GrUTF8ToUCS2(sutf8));
GR_UCS2_TEXT chartype is a very convenient chartype to work internally for a program, because it can accommodate every character from other chartypes and any char occupies exactly two bytes (an unsigned short). MGRX provides funtions to recode to/from any chartype (including the GR_UTF8_TEXT chartype) from/to GR_UCS2_TEXT.
unsigned short GrCharRecodeToUCS2(long chr,int chrtype);
converts the chr
character of type chrtype
to a a UCS-2 character. Remember for UTF-8 you have to provide a char[4]
packed in a long.
long GrCharRecodeFromUCS2(long chr,int chrtype);
do the opposite, converts a chr
UCS-2 character to a
character of type chrtype
. Again, if UTF-8 is the chartype
required, it returns a char[4] packed in a long.
unsigned short *GrTextRecodeToUCS2(const void *text,int length,int chrtype); void *GrTextRecodeFromUCS2(const unsigned short *text,int length,int chrtype);
GrTextRecodeToUCS2
converts a string of any chrtype
to a UCS-2 string and GrTextRecodeFromUCS2
do the opposite. Both
functions allocate the necesary memory, so you must check the returned pointer
for NULL, and the memory must be freed when unneded.
To help internationalize programs, MGRX includes a catalog implementation. It doesn't depend of any other MGRX function and it is Chrtype agnostic (this is why (void *) is used to pass strings).
These are the functions:
int GrI18nInit(int nlg, int nstr, void *defstr); void GrI18nEnd(void); int GrI18nSetLabel(int lid, void *label); void * GrI18nGetLabel(int lid); int GrI18nSetLang(int lid); void GrI18nAddStrings(int lid, int fsid, int nums, void **str); void * GrI18nGetString(int sid);
For an example of use read the test program "test/i18ntest.c"
There is a second set of the graphics primitives which
operates in user coordinates. Every context has a user to screen coordinate
mapping associated with it. An application specifies the user window by
calling the GrSetUserWindow
function.
void GrSetUserWindow(int x1,int y1,int x2,int y2);
A call to this function in fact specifies the virtual coordinate limits which will be mapped onto the current context regardless of the size of the context. For example, the call:
GrSetUserWindow(0,0,11999,8999);
tells the library that the program will perform its drawing operations in a coordinate system X:0...11999 (width = 12000) and Y:0...8999 (height = 9000). This coordinate range will be mapped onto the total area of the current context. The virtual coordinate system can also be shifted. For example:
GrSetUserWindow(5000,2000,16999,10999);
The user coordinates can even be used to turn the usual left-handed coordinate system (0:0 corresponds to the upper left corner) to a right handed one (0:0 corresponds to the bottom left corner) by calling:
GrSetUserWindow(0,8999,11999,0);
The library also provides three utility functions for the query of the current user coordinate limits and for converting user coordinates to screen coordinates and vice versa.
void GrGetUserWindow(int *x1,int *y1,int *x2,int *y2); void GrGetScreenCoord(int *x,int *y); void GrGetUserCoord(int *x,int *y);
If an application wants to take advantage of the user to screen coordinate mapping it has to use the user coordinate version of the graphics primitives. These have exactly the same parameter passing conventions as their screen coordinate counterparts. NOTE: the user coordinate system is not initialized by the library! The application has to set up its coordinate mapping before calling any of the use coordinate drawing functions -- otherwise the program will almost certainly exit (in a quite ungraceful fashion) with a 'division by zero' error. The list of supported user coordinate drawing functions:
void GrUsrPlot(int x,int y,GrColor c); void GrUsrLine(int x1,int y1,int x2,int y2,GrColor c); void GrUsrHLine(int x1,int x2,int y,GrColor c); void GrUsrVLine(int x,int y1,int y2,GrColor c); void GrUsrBox(int x1,int y1,int x2,int y2,GrColor c); void GrUsrFilledBox(int x1,int y1,int x2,int y2,GrColor c); void GrUsrFramedBox(int x1,int y1,int x2,int y2,int wdt,GrFBoxColors *c); void GrUsrCircle(int xc,int yc,int r,GrColor c); void GrUsrEllipse(int xc,int yc,int xa,int ya,GrColor c); void GrUsrCircleArc(int xc,int yc,int r,int start,int end, int style,GrColor c); void GrUsrEllipseArc(int xc,int yc,int xa,int ya,int start,int end, int style,GrColor c); void GrUsrFilledCircle(int xc,int yc,int r,GrColor c); void GrUsrFilledEllipse(int xc,int yc,int xa,int ya,GrColor c); void GrUsrFilledCircleArc(int xc,int yc,int r,int start,int end, int style,GrColor c); void GrUsrFilledEllipseArc(int xc,int yc,int xa,int ya,int start,int end, int style,GrColor c); void GrUsrPolyLine(int numpts,int points[][2],GrColor c); void GrUsrPolygon(int numpts,int points[][2],GrColor c); void GrUsrFilledConvexPolygon(int numpts,int points[][2],GrColor c); void GrUsrFilledPolygon(int numpts,int points[][2],GrColor c); void GrUsrFloodFill(int x, int y, GrColor border, GrColor c); GrColor GrUsrPixel(int x,int y); GrColor GrUsrPixelC(GrContext *c,int x,int y); void GrUsrCustomLine(int x1,int y1,int x2,int y2,const GrLineOption *o); void GrUsrCustomBox(int x1,int y1,int x2,int y2,const GrLineOption *o); void GrUsrCustomCircle(int xc,int yc,int r,const GrLineOption *o); void GrUsrCustomEllipse(int xc,int yc,int xa,int ya,const GrLineOption *o); void GrUsrCustomCircleArc(int xc,int yc,int r,int start,int end, int style,const GrLineOption *o); void GrUsrCustomEllipseArc(int xc,int yc,int xa,int ya,int start,int end, int style,const GrLineOption *o); void GrUsrCustomPolyLine(int numpts,int points[][2],const GrLineOption *o); void GrUsrCustomPolygon(int numpts,int points[][2],const GrLineOption *o); void GrUsrPatternedLine(int x1,int y1,int x2,int y2,GrLinePattern *lp); void GrUsrPatternedBox(int x1,int y1,int x2,int y2,GrLinePattern *lp); void GrUsrPatternedCircle(int xc,int yc,int r,GrLinePattern *lp); void GrUsrPatternedEllipse(int xc,int yc,int xa,int ya,GrLinePattern *lp); void GrUsrPatternedCircleArc(int xc,int yc,int r,int start,int end, int style,GrLinePattern *lp); void GrUsrPatternedEllipseArc(int xc,int yc,int xa,int ya,int start,int end, int style,GrLinePattern *lp); void GrUsrPatternedPolyLine(int numpts,int points[][2],GrLinePattern *lp); void GrUsrPatternedPolygon(int numpts,int points[][2],GrLinePattern *lp); void GrUsrPatternFilledPlot(int x,int y,GrPattern *p); void GrUsrPatternFilledLine(int x1,int y1,int x2,int y2,GrPattern *p); void GrUsrPatternFilledBox(int x1,int y1,int x2,int y2,GrPattern *p); void GrUsrPatternFilledCircle(int xc,int yc,int r,GrPattern *p); void GrUsrPatternFilledEllipse(int xc,int yc,int xa,int ya,GrPattern *p); void GrUsrPatternFilledCircleArc(int xc,int yc,int r,int start,int end,int style,GrPattern *p); void GrUsrPatternFilledEllipseArc(int xc,int yc,int xa,int ya,int start,int end,int style,GrPattern *p); void GrUsrPatternFilledConvexPolygon(int numpts,int points[][2],GrPattern *p); void GrUsrPatternFilledPolygon(int numpts,int points[][2],GrPattern *p); void GrUsrPatternFloodFill(int x, int y, GrColor border, GrPattern *p); void GrUsrDrawChar(long chr,int x,int y,const GrTextOption *opt); void GrUsrDrawString(char *text,int length,int x,int y,const GrTextOption *opt); void GrUsrTextXY(int x,int y,char *text,GrColor fg,GrColor bg);
The library provides support for the creation and usage of an
unlimited number of graphics cursors. An application can use these cursors
for any purpose. Cursors always save the area they occupy before they are
drawn. When moved or erased they restore this area. As a general rule of
thumb, an application should erase a cursor before making changes to an
area it occupies and redraw the cursor after finishing the drawing. Cursors
are created with the GrBuildCursor
function:
GrCursor *GrBuildCursor(char *pixels,int pitch,int w,int h, int xo,int yo,const GrColorTableP c);
The pixels
, w
(=width), h
(=height) and c
(= color table) arguments are similar to the
arguments of the pixmap building library function GrBuildPixmap
(see that paragraph for a more detailed explanation.), but with two
differences. First, it is not assumed that the pixels data is w
x h
sized, the pitch
argument set the offset
between rows. Second, the pixmap data is interpreted slightly differently,
any pixel with value zero is taken as a "transparent" pixel, i.e. the
background will show through the cursor pattern at that pixel. A pixmap
data byte with value = 1 will refer to the first color in the table, and so
on.
The xo
(= X offset) and yo
(= Y
offset) arguments specify the position (from the top left corner of the
cursor pattern) of the cursor's "hot point".
The GrCursor
data structure:
typedef struct _GR_cursor { struct _GR_context work; /* work areas (4) */ int xcord,ycord; /* cursor position on screen */ int xsize,ysize; /* cursor size */ int xoffs,yoffs; /* LU corner to hot point offset */ int xwork,ywork; /* save/work area sizes */ int xwpos,ywpos; /* save/work area position on screen */ int displayed; /* set if displayed */ } GrCursor;
is typically not used (i.e. read or changed) by the application program, it should just pass pointers to these structures to the appropriate library functions. Other cursor manipulation functions:
void GrDisplayCursor(GrCursor *cursor); void GrEraseCursor(GrCursor *cursor); void GrMoveCursor(GrCursor *cursor,int x,int y); void GrDestroyCursor(GrCursor *cursor);
MGRX includes functions to load/save a context from/to a PNM file.
PNM is a group of simple graphics formats from the NetPbm distribution. NetPbm can convert from/to PNM lots of graphics formats, and apply some transformations to PNM files (Note. You don't need the NetPbm distribution to use the MGRX functions).
There are six PNM formats:
MGRX can handle the binary formats only (get the NetPbm distribution if you need to convert text to binary formats).
To save a context in a PNM file you have three functions:
int GrSaveContextToPbm( GrContext *grc, char *pbmfn, char *docn ); int GrSaveContextToPgm( GrContext *grc, char *pgmfn, char *docn ); int GrSaveContextToPpm( GrContext *grc, char *ppmfn, char *docn );they work both in RGB and palette modes,
grc
must be
a pointer to the context to be saved, if it is NULL the current context is
saved; p-mfn
is the file name to be created and
docn
is an optional text comment to be written in the file,
it can be NULL. The functions return 0 on succes or -1 on error.
GrSaveContextToPbm
dumps a context in a PBM file
(bitmap). If the pixel color isn't Black it asumes White.
GrSaveContextToPgm
dumps a context in a PGM file
(gray scale). The colors are quantized to gray scale using .299r + .587g +
.114b.
GrSaveContextToPpm
dumps a context in a PPM file
(real color).
To load a PNM file in a context you must use:
int GrLoadContextFromPnm( GrContext *grc, char *pnmfn );it support reading PBM, PGM and PPM binary files.
grc
must
be a pointer to the context to be written, if it is NULL the current context
is used; p-mfn
is the file name to be read. If context
dimensions are lesser than pnm dimensions, the function loads as much as it
can. If color mode is not in RGB mode, the routine allocates as much colors
as it can. The function returns 0 on succes or -1 on error.
To query the file format, width and height of a PNM file you can use:
int GrQueryPnm( char *pnmfn, int *width, int *height, int *maxval );
pnmfn
is the name of pnm file; width
returns the
pnm width; height
returns the pnm height; maxval
returns the max color component value. The function returns 1 to 6 on success
(the PNM format) or -1 on error.
The two next functions:
int GrLoadContextFromPnmBuffer( GrContext *grc, const char *pnmbuf ); int GrQueryPnmBuffer( const char *pnmbuf, int *width, int *height, int *maxval );work like
GrLoadContextFromPnm
and
GrQueryPnmBuffer
, but they get his input from a buffer instead
of a file. This way, pnm files can be embeded in a program (using the
src/utilprog/bin2c program by example).
MGRX includes functions to load/save a context from/to a png file. But note, for this purpose it needs the libpng library, and to enable the png support before make the MGRX lib.
Use next function to save a context in a PNG file:
int GrSaveContextToPng( GrContext *grc, char *pngfn );it works both in RGB and palette modes,
grc
must be
a pointer to the context to be saved, if it is NULL the current context is
saved; pngfn
is the file name to be created.
The function returns 0 on succes or -1 on error.
To load a PNG file in a context you must use:
int GrLoadContextFromPng( GrContext *grc, char *pngfn, int use_alpha );
grc
must be a pointer to the context to be written, if it
is NULL the current context is used; pngfn
is the file name
to be read; set use_alpha
to 1 if you want to use the image
alpha channel (if available). If context dimensions are lesser than png
dimensions, the function loads as much as it can. If color mode is not
in RGB mode, the routine allocates as much colors as it can. The function
returns 0 on succes or -1 on error.
To query the width and height of a PNG file you can use:
int GrQueryPng( char *pngfn, int *width, int *height );
pngfn
is the name of png file; width
returns the
png width; height
returns the png height.
The function returns 0 on success or -1 on error.
The function:
int GrPngSupport( void );returns 1 if there is png support in the library, 0 otherwise. If there is not support for png, dummy functions are added to the library, returning error (-1) ever.
MGRX includes functions to load/save a context from/to a jpeg file. But note, for this purpose it needs the libjpeg library, and to enable the jpeg support before make the MGRX lib.
Use next function to save a context in a JPEG file:
int GrSaveContextToJpeg( GrContext *grc, char *jpegfn, int quality );it works both in RGB and palette modes,
grc
must be
a pointer to the context to be saved, if it is NULL the current context is
saved; jpegfn
is the file name to be created;
quality
is a number between 1 and 100 to drive the compression
quality, use higher values for better quality (and bigger files), you can
use 75 as a standard value, normally a value between 50 and 95 is good.
The function returns 0 on succes or -1 on error.
This function saves a context in a grayscale JPEG file:
int GrSaveContextToGrayJpeg( GrContext *grc, char *jpegfn, int quality );parameters and return codes are like in
GrSaveContextToJpeg
.
The colors are quantized to gray scale using .299r + .587g + .114b.
To load a JPEG file in a context you must use:
int GrLoadContextFromJpeg( GrContext *grc, char *jpegfn, int scale );
grc
must be a pointer to the context to be written, if it
is NULL the current context is used; jpegfn
is the file name
to be read; set scale
to 1, 2, 4 or 8 to reduce the loaded
image to 1/1, 1/2, 1/4 or 1/8. If context dimensions are lesser than jpeg
dimensions, the function loads as much as it can. If color mode is not
in RGB mode, the routine allocates as much colors as it can. The function
returns 0 on succes or -1 on error.
To query the width and height of a JPEG file you can use:
int GrQueryJpeg( char *jpegfn, int *width, int *height );
jpegfn
is the name of jpeg file; width
returns the
jpeg width; height
returns the jpeg height.
The function returns 0 on success or -1 on error.
The function:
int GrJpegSupport( void );returns 1 if there is jpeg support in the library, 0 otherwise. If there is not support for jpeg, dummy functions are added to the library, returning error (-1) ever.
Here we will describe some miscellaneous functions.
unsigned GrGetLibraryVersion(void);
GrGetLibraryVersion
returns the MGRX
version API, like a hexadecimal coded number. By example 0x0090
means 0.9.0
Because mgrx.h defines the MGRX_VERSION_API
macro, you
can check if both, the library and the include file, are in the same version
using if( GrGetLibraryVersion() == MGRX_VERSION_API )
unsigned GrGetLibrarySystem(void);
This functions returns a unsigned integer identifing the system you are working in. mgrx.h defines some macros you can use:
/* these are the supported configurations: */ #define MGRX_VERSION_GCC_386_DJGPP 1 /* DJGPP v2 */ #define MGRX_VERSION_GCC_386_LINUX 2 /* console framebuffer i386 */ #define MGRX_VERSION_GCC_386_X11 3 /* X11 version i386 */ #define MGRX_VERSION_GCC_386_WIN32 4 /* WIN32 using Mingw32 */ #define MGRX_VERSION_GCC_X86_64_LINUX 5 /* console framebuffer x86_64 */ #define MGRX_VERSION_GCC_X86_64_X11 6 /* X11 version x86_64 */ #define MGRX_VERSION_GCC_ARM_LINUX 7 /* console framebuffer arm */ #define MGRX_VERSION_GCC_ARM_X11 8 /* X11 version arm */
void GrSetWindowTitle(char *title);
GrSetWindowTitle
sets the main window title
in the X11 an Win32 versions. It does nothing in the DOS and
Linux-Console versions.
void GrSleep(int msec);
This function stops the program execution for
msec
miliseconds.
GrContext *GrCreateFrameContext(GrFrameMode md,int w,int h, char *memory[4],GrContext *where);
This function is like GrCreateContext
, except
that you can specify any valid memory frame mode, not only the Screen
associated frame mode. It can be used for special purposes (see
GrBitBlt1bpp
for an example).
void GrBitBlt1bpp(GrContext *dst,int dx,int dy,GrContext *src, int x1,int y1,int x2,int y2,GrColor fg,GrColor bg);
This special function does a bitblt from a 1bpp context (a
bitmap really),
using fg
and bg
like the color+opcode when bit=1
and bit=0 respectively. Here is an example:
pContext = GrCreateFrameContext(GR_frameRAM1, sizex, sizey, NULL, NULL); /* draw something (black and white) into the bitmap */ GrSetContext(pContext); GrClearContext( GrBlack() ); GrLine(0, 0, sizex-1, sizey-1, GrWhite()); GrLine(0, sizey-1, sizex-1, 0, GrWhite()); /* Put the bitmap into the screen */ GrSetContext(NULL); fcolor = GrAllocColor( 255,0,0 ); bcolor = GrAllocColor( 0,0,255 ); GrBitBlt1bpp(NULL,x,y,pContext,0,0,sizex-1,sizey-1,fcolor,bcolor);
MGRX can handle platform independent input. The input API is based on events and is totally diferent from the GRX input API.
The input API must be inited after a graphics mode is set using this function:
int GrEventInit(void);
it returns true on success and init the keyboard and the mouse if one is found. The input API must be uninited before the program ends or before set another graphic mode whit this function:
void GrEventUnInit(void);
The basic function to get an event is:
void GrEventRead(GrEvent * ev);
the event structure is defined in mgrx.h
typedef struct { int type; /* event type */ long time; /* miliseconds */ int kbstat; /* kb status (count for GREV_EXPOSE) */ union { /* GREV_KEY GREV_MOUSE GREV_MMOVE GREV_EXPOSE GREV_WSZCHG */ long p1; /* key subevent but status x 0 */ unsigned char cp1[4]; /* for easy access to multibyte key (like UTF-8) */ }; long p2; /* type/nbytes x x y 0 */ long p3; /* -- y y width winwidth */ long p4; /* -- -- -- height winheight */ } GrEvent;
GrEventRead
returns inmediatelly with type=GREV_NULL if no event
is ready. The possible events are:
#define GREV_NULL 0 /* no event */ #define GREV_KEY 1 /* key pressed, p1=GRXkey (char or gr_keycode), p2=type or nbytes */ #define GREV_MOUSE 2 /* mouse event, p1=subevent, p2=x, p3=y */ #define GREV_MMOVE 3 /* mouse move event, p1=buttons status, p2=x, p3=y */ #define GREV_PREKEY 4 /* key event before be recoded, internal event, users don't see it */ #define GREV_EXPOSE 5 /* a window area must be redraw (generated only if user requested it) */ #define GREV_WMEND 6 /* window manager wants ending (generated only if user requested it) */ #define GREV_WSZCHG 7 /* window size changed (generated only if window resize supported) */ #define GREV_CBREPLY 8 /* clipboard reply p1=1 if ready to paste, p1=0 no data in clipboard */ #define GREV_USER 100 /* user event */
a programmer can define user type events with values >= GREV_USER. When the
event is GREV_KEY, p1
has the character or key and p2
the number of bytes used by the character or GRKEY_KEYCODE
if it
is a special keys. When the event is GREV_MOUSE, p1
has the subevent:
#define GRMOUSE_LB_PRESSED 1 /* Left button depressed */ #define GRMOUSE_MB_PRESSED 2 /* Middle button depressed */ #define GRMOUSE_RB_PRESSED 3 /* Right button depressed */ #define GRMOUSE_LB_RELEASED 4 /* Left button released */ #define GRMOUSE_MB_RELEASED 5 /* Middle button released */ #define GRMOUSE_RB_RELEASED 6 /* Rigth button released */ #define GRMOUSE_B4_PRESSED 7 /* Button 4 depressed (scroll wheel) */ #define GRMOUSE_B4_RELEASED 8 /* Button 4 released (scroll wheel) */ #define GRMOUSE_B5_PRESSED 9 /* Button 5 depressed (scroll wheel) */ #define GRMOUSE_B5_RELEASED 10 /* Button 5 released (scroll wheel) */
By default MGRX doesn't generate GREV_MMOVE events except if the programmer requests it with the function:
void GrEventGenMmove(int when);
when
can be one of these constants:
#define GR_GEN_MMOVE_NEVER 0 /* Doesn't gen GREV_MMOVE */ #define GR_GEN_MMOVE_IFBUT 1 /* Gen GREV_MMOVE if a button is pressed */ #define GR_GEN_MMOVE_ALWAYS 2 /* Gen GREV_MMOVE always */
for GREV_MMOVE p1
is filled with the mouse buttons status:
#define GRMOUSE_LB_STATUS 1 /* Status bit for left button */ #define GRMOUSE_MB_STATUS 4 /* Status bit for middle button */ #define GRMOUSE_RB_STATUS 2 /* Status bit for right button */
For GREV_KEY, GREV_MOUSE and GREV_MMOVE kbstat
is filled
wih the keyboard status word, or-ing it with the next defines it can be
known the status of some special keys:
#define GRKBS_RIGHTSHIFT 0x01 /* Keybd states: right shift key depressed */ #define GRKBS_LEFTSHIFT 0x02 /* left shift key depressed */ #define GRKBS_CTRL 0x04 /* CTRL depressed */ #define GRKBS_ALT 0x08 /* ALT depressed */ #define GRKBS_SCROLLOCK 0x10 /* SCROLL LOCK active */ #define GRKBS_NUMLOCK 0x20 /* NUM LOCK active */ #define GRKBS_CAPSLOCK 0x40 /* CAPS LOCK active */ #define GRKBS_INSERT 0x80 /* INSERT state active */ #define GRKBS_SHIFT (GRKBS_LEFTSHIFT | GRKBS_RIGHTSHIFT)
The file mgrxkeys.h defines the keys returned in p1
with
the GREV_KEY. This is an extract:
#define GrKey_Control_A 0x0001 #define GrKey_Control_B 0x0002 #define GrKey_Control_C 0x0003 ... #define GrKey_A 0x0041 #define GrKey_B 0x0042 #define GrKey_C 0x0043 ... #define GrKey_F1 0x013b #define GrKey_F2 0x013c #define GrKey_F3 0x013d ... #define GrKey_Alt_F1 0x0168 #define GrKey_Alt_F2 0x0169 #define GrKey_Alt_F3 0x016a
but you can be confident that the standard ASCII is right maped. Remenber, if the KbSys encoding is different from the user encoding, the input driver will recode key events to user encoding.
The GREV_EXPOSE event is only generated in X11 systems and only if the user requests it using this function:
void GrEventGenExpose(int when);
when
can be:
#define GR_GEN_EXPOSE_NO 0 /* Doesn't gen GREV_EXPOSE (default) */ #define GR_GEN_EXPOSE_YES 1 /* Gen GREV_EXPOSE */
When GREV_EXPOSE events are generated, the X11 video driver doesn't use backing store, so drawings can be faster, but the program must redraw the area exposed by itsel. Check the test program "life" for an example. For systems other than X11 the function does nothing. GREV_EXPOSE populates "count" in the "kbstat" field. If count is zero, no more Expose events follow. Simple applications that do not want to optimize redisplay can just ignore all Expose events with nonzero counts and perform full redisplays on events with zero counts.
The GREV_WMEND event is only generated in X11 and W32 systems and only if the user requests it using this function:
void GrEventGenWMEnd(int when);
when
can be:
#define GR_GEN_WMEND_NO 0 /* Doesn't gen GREV_WMEND (default) */ #define GR_GEN_WMEND_YES 1 /* Gen GREV_WMEND */
If GREV_WMEND generation is active it will be generated when the user click the close window button, then the program must handle it, normally asking the user if he wants to exit. If generation is not active the program will be aborted.
The GREV_WSZCHG is only generated by the X11 and W32 drivers when they are initialized with window resize support. See the specific chapter bellow.
These are the other functions of the input API:
void GrEventFlush(void); int GrEventCheck(void); void GrEventWait(GrEvent * ev); void GrEventWaitKeyOrClick(GrEvent * ev); int GrEventEnqueue(GrEvent * ev); int GrEventParEnqueue(int type, long p1, long p2, long p3, long p4); int GrEventEnqueueFirst(GrEvent * ev); int GrEventParEnqueueFirst(int type, long p1, long p2, long p3, long p4);
GrEventFlush
flush the event queue.
GrEventCheck
returns true if an event is waiting.
GrEventWait
waits until an event is ready.
GrEventWaitKeyOrClick
waits until a key or the left mouse
button is pressed.
GrEventEnqueue
and GrEventParEnqueue
enqueue an
user event, passing the whole structure or only the type and parameters.
GrEventEnqueueFirst
and GrEventParEnqueueFirst
enqueue an user event at the begining of the queue.
Starting wiht the 1.3.6 MGRX version the input driver can compose characters from hexadecimal input. It is disabled by default, to enable it call the function:
void GrSetComposeKey(int compkey);
after the input driver is initiated, e.g.
GrSetComposeKey(GrKey_Alt_U);
After that use the compose-key and
up to four hexadecimal digits for GRENC_UTF_8
and GRENC_UCS_2
User encodings, only two for the rest User encodings.
After the input API is initiated an application can test whether a mouse is available by calling the function:
int GrMouseDetect(void);
which will return zero if no mouse (or mouse driver) is present, non-zero otherwise.
The mouse can be controlled with the following functions:
void GrMouseSetSpeed(int spmult,int spdiv); void GrMouseSetAccel(int thresh,int accel); void GrMouseSetLimits(int x1,int y1,int x2,int y2); void GrMouseGetLimits(int *x1,int *y1,int *x2,int *y2); void GrMouseWarp(int x,int y);
For DOS and linux console the library calculates the mouse
position only from the mouse
mickey counters. (To avoid the limit and 'rounding to the next multiple of
eight' problem with some mouse driver when it finds itself in a graphics
mode unknown to it.) The parameters to the GrMouseSetSpeed
function specify how coordinate changes are obtained from mickey counter
changes, multipling by spmult
and dividing by spdiv
.
In high resolution graphics modes the value of one just works fine, in low
resolution modes (320x200 or similar) it is best set the spdiv
to two or three. (Of course, it also depends on the sensitivity the mouse.)
The GrMouseSetAccel
function is used to control the ballistic
effect: if a mouse coordinate changes between two samplings by more than
the thresh
parameter, the change is multiplied by the
accel
parameter. NOTE: some mouse drivers perform similar
calculations before reporting the coordinates in mickeys. In this case the
acceleration done by the library will be additional to the one already
performed by the mouse driver.
The limits of the mouse movement can be set
(passed limits will be clipped to the screen) with GrMouseSetLimits
(default is the whole screen) and the current limits can be obtained
with GrMouseGetLimits
. GrMouseWarp
sets the mouse
cursor to the specified position.
As typical mouse drivers do not know how to draw mouse cursors in high resolution graphics modes, the mouse cursor is drawn by the library. The mouse cursor can be set with:
void GrMouseSetCursor(GrCursor *cursor); void GrMouseSetInternalCursor(int type,GrColor fg,GrColor bg);
For the type
parameter in
GrMouseSetInternalCursor
you must use one of the available
internal cursors:
#define GR_MCUR_TYPE_ARROW 0 /* MOUSE CURSOR types: arrow cursor */ #define GR_MCUR_TYPE_CROSS 1 /* cross cursor */ #define GR_MCUR_TYPE_GLASS 2 /* hourglass cursor */
the color fg
will be used as the interior of it and bg
will be the border. The current mouse cursor can be obtained with:
GrCursor *GrMouseGetCursor(void);
The mouse cursor can be displayed/erased with:
void GrMouseDisplayCursor(void); void GrMouseEraseCursor(void);
The mouse cursor can be left permanently displayed. All graphics primitives except for the few non-clipping functions check for conflicts with the mouse cursor and erase it before the drawing if necessary. Of course, it may be more efficient to erase the cursor manually before a long drawing sequence and redraw it after completion. The library provides an alternative pair of calls for this purpose which will erase the cursor only if it interferes with the drawing:
int GrMouseBlock(GrContext *c,int x1,int y1,int x2,int y2); void GrMouseUnBlock(int return_value_from_GrMouseBlock);
GrMouseBlock
should be passed the context in
which the drawing will take place (the usual convention of NULL meaning the
current context is supported) and the limits of the affected area. It will
erase the cursor only if it interferes with the drawing. When the drawing
is finished GrMouseUnBlock
must be called with the argument
returned by GrMouseBlock
.
The status of the mouse cursor can be obtained with calling
GrMouseCursorIsDisplayed
. This function will return non-zero
if the cursor is displayed, zero if it is erased.
int GrMouseCursorIsDisplayed(void);
The library supports (beside the simple cursor drawing) three
types of "rubberband" attached to the mouse cursor. The
GrMouseSetCursorMode
function is used to select the cursor drawing
mode.
void GrMouseSetCursorMode(int mode,...);
The parameter mode
can have the following values:
#define GR_M_CUR_NORMAL 0 /* MOUSE CURSOR modes: just the cursor */ #define GR_M_CUR_RUBBER 1 /* rect. rubber band (XOR-d to the screen) */ #define GR_M_CUR_LINE 2 /* line attached to the cursor */ #define GR_M_CUR_BOX 3 /* rectangular box dragged by the cursor */
GrMouseSetCursorMode
takes different parameters
depending on the cursor drawing mode selected. The accepted call formats are:
GrMouseSetCursorMode(M_CUR_NORMAL); GrMouseSetCursorMode(M_CUR_RUBBER,xanchor,yanchor,GrColor); GrMouseSetCursorMode(M_CUR_LINE,xanchor,yanchor,GrColor); GrMouseSetCursorMode(M_CUR_BOX,dx1,dy1,dx2,dy2,GrColor);
The anchor parameters for the rubberband and rubberline modes
specify a fixed screen location to which the other corner of the primitive
is bound. The dx1
through dy2
parameters define
the offsets of the corners of the dragged box from the hotpoint of the mouse
cursor. The color value passed is always XOR-ed to the screen, i.e. if an
application wants the rubberband to appear in a given color on a given
background then it has to pass the XOR of these two colors to
GrMouseSetCursorMode
.
Starting wiht the 1.3.5 MGRX version the X11 and W32 drivers support window resize. To achieve that a program must:
GrSetDriverExt(NULL, "rszwin")
before GrSetMode
to request
window resize support to the default video driver.
GrSetMode
again with the dimensions provided by the event.
Note that if the graphics driver don't support window resize no events
will be generated, but the program will run without problems. So you can code your
program to support window resizes and they work with video drivers that don't support it,
like the DJGPP an Linux framebuffer ones. But if you want to know if there are window
resize support to run differently you can test for a flag after calling
GrSetDriverExt
using this:
if (GrCurrentVideoDriver()->drvflags & GR_DRIVERF_WINDOW_RESIZE) { ... window resize support } else { ... no window resize support }
At any time the program can change the video mode by its own but in that
case you must call GrSetMode(GR_default_text)
before calling
GrSetMode(GR_graphics_....)
, so the driver can know that the new video mode
is not related with a window resize.
In the next skeleton program you can see the process using two nested loops (there are other possible solutions):
// global dimensions int w = 640; int h = 480; int bpp = 8; ... some intitalizations GrSetDriverExt(NULL, "rszwin"); ... more initializations while (1) { int exitloop = 0; int szchgbyprog = 0; GrEvent ev; GrSetMode(GR_width_height_bpp_graphics, w, h, bpp); GrEventInit(); GrMouseDisplayCursor(); ... restore the program state ... do initial drawings while (1) { // this is the main loop really GrEventRead(&ev); if (((ev.type == GREV_KEY) && (ev.p1 == GrKey_Escape)) { // terminate exitloop = 1; break; } if (ev.type == GREV_WSZCHG) { // manage a window resize w = ev.p3; h = ev.p4; ...save the program state break; } ... manage other events if (...something...) { // set a window size by program w = ownw; h = ownh; szchgbyprog = 1; ...save the program state break; } ... manage other events } GrMouseEraseCursor(); GrEventUnInit(); if (szchgbyprog) { GrSetMode(GR_default_text); szchgbyprog = 0; } if (exitloop) break; } GrSetMode(GR_default_text);
You can check the test/wrsztest.c program for an example.
Starting wiht the 1.3.6 version MGRX provides a clipboard to copy and paste text. The clipboard is internal to the program for the DOS and linuxfb versions, but the X11 and W32 drivers interact with the system clipboard. Because the X11 clipboard is asynchronous a special procedure is nedeed, but you can use it with any platform.
MGRX maintains a copy of the last copied text, by default with a maximum of 32000 characters, but you can change this with:
void GrSetClipBoardMaxChars(int maxchars);
If you don't want to have a limit use GR_CB_NOLIMIT
To put text in the clipboard use:
int GrPutClipBoard(void *buf, int len, int chrtype);
it returns the number of characters really copied, it can be less than the required len if the clipboard limit is reached.
To get text from the clipboard you must first call:
int GrIsClipBoardReadyToGet(void);
it returns 1 if the text is ready to get, 0 if the clipboard is empty or -1 if a request to the system clipboard is issued. DOS, linuxfb and W32 platforms will never return -1. Anyway if -1 is returned you need to wait after a GREV_CBREPLY event with p1=1 is read. if 1 is returned or after the event is received yoy can call:
int GrGetClipBoardLen(int *partloaded);
to know the clipboard content len in characters. If the partloaded
parameter is not NULL it will be true if the last copy operation was partially
loaded, because the clipboard limit was reached. And now you can get the clipboard
content with:
void *GrGetClipBoard(int maxlen, int chrtype);
you must check for NULL and freeing the returned string when unneded.
At any time you can erase the internal copy of the last copied text with:
void GrClearClipBoard(void);
but note that in the X11 platform this prevent other clients to get the copied text from your program.
MGRX can be used to draw in memory using the memory driver, so a graphic screen is not nedeed. After the drawing, the result can be stored in a graphics file. This is the Hello MGRX example for the memory driver:
#include <string.h> #include <mgrx.h> int main() { char *message = "Hello, MGRX world"; int x, y; GrTextOption grt; GrSetDriver("memory gw 400 gh 400 nc 256"); GrSetMode(GR_default_graphics); grt.txo_font = &GrDefaultFont; grt.txo_fgcolor = GrWhite(); grt.txo_bgcolor = GrBlack(); grt.txo_direct = GR_TEXT_RIGHT; grt.txo_xalign = GR_ALIGN_CENTER; grt.txo_yalign = GR_ALIGN_CENTER; grt.txo_chrtype = GR_BYTE_TEXT; GrBox(0, 0, GrMaxX(), GrMaxY(), GrWhite()); GrBox(4, 4, GrMaxX()-4, GrMaxY()-4, GrWhite()); x = GrMaxX() / 2; y = GrMaxY() / 2; GrDrawString(message, strlen(message), x, y, &grt); GrSaveContextToPpm(NULL, "memtest.ppm", "GRX MemTest"); return 0; }
http://mgrx.fgrim.com | Official MGRX site |
http://grx.gnu.de | GRX site (MGRX is derived from GRX) |
http://netpbm.sourceforge.net | NetPbm distribution |
http://www.libpng.org/pub/png/libpng.html | Libpng library |
http://www.ijg.org | Libjpeg library |