2. Reference manual

Sources: ez-draw.h, ez-draw.c.

2.1. Main loop

int ez_init()

Initialization.

Return 0 on success, -1 on failure.

void ez_main_loop()

Main loop.

This function displays the existing windows, then waits for events; for each incoming event the function calls the corresponding window event function (the callback).

To stop the main loop, call ez_quit() in a callback. Once returned from ez_main_loop(), no more graphic call should be done.

void ez_quit()

Exit ez_main_loop().

void ez_auto_quit(int val)

Modify the effect of the “Close” button in the title bar of a window, for each window of the program.

By default (val = 1), if you click on the “Close” button of any window of the program, it ends immediately.

You can change this behavior by invoking ez_auto_quit() with val = 0 : then, if the user clicks on the “Close” button of a window, the program (instead of ending) will receive the event WindowClose for this window, so as to decide what to do:

Note: when all windows are destroyed, the program stops.

2.2. Windows

Each window has a unique identifier, of type Ez_window:

Ez_window

Identifier of a window.

The following functions allow to create or manipulate windows:

Ez_window ez_window_create(int w, int h, const char *name, Ez_func on_event)

Create and display a window, having width w and height h, a title name, and a function on_event (the callback) called for each event (on_event might be NULL).

Return the identifier of the window, of type Ez_window.

Any callback has type Ez_func :

Ez_func

The type of a callback, that is to say, the prototype of an event handler, the function called for each event. This type is defined as:

typedef void (*Ez_func)(Ez_event *ev);

In other words, the function on_event given to ez_create_window() has to be declared as:

void on_event (Ez_event *ev);
int ez_window_get_id(Ez_window win)

Return the window id as an int.

void ez_window_destroy(Ez_window win)

Destroy window win.

void ez_window_show(Ez_window win, int val)

Show (val = 1) or hide (val = 0) the window win.

void ez_window_set_size(Ez_window win, int w, int h)

Change the size of the window.

void ez_window_get_size(Ez_window win, int *w, int *h)

Retrieve the window size.

void ez_window_clear(Ez_window win)

Empty the window (with a white background) and initialize the drawing parameters (color, width, font) to the default values.

void ez_send_expose(Ez_window win)

Send an Expose event to the window, so as to empty the window and to force to redraw.

2.3. Events

Each event is described by a struct of type Ez_event:

Ez_event

Store an event.

This type is defined in ez-draw.h as follows:

typedef struct {
    int type;                       /* Expose, ButtonPress, etc                */
    Ez_window win;                  /* Identifier of the window                */
    int mx, my;                     /* Mouse coordinates                       */
    int mb;                         /* Mouse button, 0 = none                  */
    int width, height;              /* Width and height                        */
    KeySym key_sym;                 /* Key symbol: XK_Space, XK_q, etc         */
    char   key_name[80];            /* For tracing: "XK_Space", "XK_q", ..     */
    char   key_string[80];          /* Corresponding string: " ", "q", etc     */
    int    key_count;               /* String length                           */
    /* Other fields private */
} Ez_event;

The first field gives the event type. The possible values are:

Expose The whole window must be redrawn.
ButtonPress Mouse button pressed.
ButtonRelease Mouse button released.
MotionNotify Mouse moved.
KeyPress Key pressed.
KeyRelease Key released.
ConfigureNotify The window size has changed.
WindowClose The button “Close” was pressed.
TimerNotify The timer has expired.

2.4. Colors

Each color is denoted by an integer of type Ez_uint32.

void ez_set_color(Ez_uint32 color)

Store the color color for the next drawings, as well as for text displaying.

The following colors are predefined: ez_black, ez_white, ez_grey, ez_red, ez_green, ez_blue, ez_yellow, ez_cyan, ez_magenta.

Other colors can be obtained with these functions:

Ez_uint32 ez_get_RGB(Ez_uint8 r, Ez_uint8 g, Ez_uint8 b)

Return a color computed according to the levels r,g,b given between 0 and 255.

Ez_uint32 ez_get_grey(Ez_uint8 g)

Return a grey color computed according to the level g given between 0 and 255.

Ez_uint32 ez_get_HSV(double h, double s, double v)

Return a color defined in space Hue, Saturation, Value.

h is an angle between 0 and 360 degrees which arbitrary represents pure colors; s is saturation, between 0 and 1 ; v is the luminosity value, between 0 and 1. For more information, see Hue Saturation Value in Wikipedia.

void ez_HSV_to_RGB(double h, double s, double v, Ez_uint8 *r, Ez_uint8 *g, Ez_uint8 *b)

Convert a color from HSV to RGB.

The ranges are: h between 0 and 360, s and v between 0 and 1, *r, *g, *b between 0 and 255.

As examples, see demo-11.c and demo-12.c.

These windows are obtained:

demo-11 demo-12

2.5. Drawings

The coordinates are relative to the Origin, which is the top left point inside the window; x goes to the right and y goes down.

For rectangles and circles, x1,y1 and y2,y2 are the top left and bottom right coordinates of the bounding box. For points, line segments and triangles, the vertex coordinates are expected.

The default color is black; it can be changed with ez_set_color().

void ez_draw_point(Ez_window win, int x1, int y1)

Draw a point.

void ez_draw_line(Ez_window win, int x1, int y1, int x2, int y2)

Draw a line segment.

void ez_draw_rectangle(Ez_window win, int x1, int y1, int x2, int y2)

Draw a rectangle.

void ez_fill_rectangle(Ez_window win, int x1, int y1, int x2, int y2)

Fill a rectangle.

void ez_draw_triangle(Ez_window win, int x1, int y1, int x2, int y2, int x3, int y3)

Draw a triangle.

void ez_fill_triangle(Ez_window win, int x1, int y1, int x2, int y2, int x3, int y3)

Fill a triangle.

void ez_draw_circle(Ez_window win, int x1, int y1, int x2, int y2)

Draw a circle.

void ez_fill_circle(Ez_window win, int x1, int y1, int x2, int y2)

Fill a circle.

Drawings with ez_draw_point(), ez_draw_line(), ez_draw_rectangle(), ez_draw_triangle(), ez_draw_circle() have a default thickness of 1 pixel. It can be changed with:

void ez_set_thick(int thick)

Set thickness thick (in pixels) for the next drawings.

2.6. Text and fonts

int ez_font_load(int num, const char *name)

Load the font name (e.g. "6x13") and store it as the font number num.

Return 0 on success, -1 on error.

The font number must be less than EZ_FONT_MAX. Some fixed fonts are preloaded by default:

  • Font number 0: "6x13"
  • Font number 1: "8x16"
  • Font number 2: "10x20"
  • Font number 3: "12x24"
Note:
On X11, the name can be in any fashion but must correspond to an existing font. On Windows, the name must be in the form widthxheight (a matching font of fixed size is obtained).
void ez_set_nfont(int num)

Set the font number num for the next text drawings.

void ez_draw_text(Ez_window win, Ez_Align align, int x1, int y1, const char *format, ...)

Display text; same usage as printf.

Example:

ez_draw_text (win, EZ_TL, 10, 10, "Width = %d\nHeight = %d", w, h);

The coordinates x1,y1 are relative to align, which takes for values:

EZ_TL (Top Left) EZ_TC (Top Center) EZ_TR (Top Right)
EZ_ML (Middle Left) EZ_MC (Middle Center) EZ_MR (Middle Right)
EZ_BL (Bottom Left) EZ_BC (Bottom Center) EZ_BR (Bottom Right)

The text is drawn over the current content of the window; you can also delete the background at the same time (with white) using these values for align:

EZ_TLF (Top Left Filled) EZ_TCF (Top Center Filled) EZ_TRF (Top Right Filled)
EZ_MLF (Middle Left Filled) EZ_MCF (Middle Center Filled) EZ_MRF (Middle Right Filled)
EZ_BLF (Bottom Left Filled) EZ_BCF (Bottom Center Filled) EZ_BRF (Bottom Right Filled)
By default:
  • the text is displayed using font number 0 (6x13); it can be changed by ez_set_nfont().
  • the text is displayed in black; the color can be changed with ez_set_color().

2.7. Double buffering

Displaying with a double buffer prevents the window flashes while it is refreshed. The idea is to draw in the double buffer, then swap it with the window content when all the drawings are finished. Everything is handled automatically by EZ-Draw.

void ez_window_dbuf(Ez_window win, int val)

Enable or disable the double buffer display for the window win.

By default, the double buffering is disabled (val = 0).

If the double buffering is enabled (val = 1) for a window, every drawings in this window must be made during Expose events only. If the double buffering is disabled, it is no longer a requirement, but it is strongly advised.

As an example, see in game jeu-nim.c the functions gui_init(), win1_onKeyPress(), win1_onExpose().

In this game, you can test the display with or without the double buffer (press key d to switch between one and the other):

jeu-nim-2

2.8. Timers

Starting a timer means storing a date in the future, which is the current date plus a certain delay. When we arrive at this date in the future, we say that the timer has expired.

Each window can be associated with a timer. Upon expiration of the timer, the program receives a unique event TimerNotify for the window, then the timer is deleted.

void ez_start_timer(Ez_window win, int delay)

Start a timer for the window win with the delay delay expressed in milliseconds.

Any recall of this function before timer expiration will cancel and replace the timer with the new delay. Moreover, if delay is -1 then the timer is deleted. (Note: this is not an error to delete a timer already deleted or non-existent).

An an example, see demo-09.c.

2.9. Client-data

Each window can store an arbitrary data of the program, for instance a string or a struct address. You can then recover the data at any time in the program. This mechanism aims to avoid global variables.

void ez_set_data(Ez_window win, void *data)

Store the data data in the window win

void *ez_get_data(Ez_window win)

Return the data stored in the window win.

Here is an example of program that draws a circle, whose coordinates are stored into a global variable md:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "ez-draw.h"

typedef struct {
    int x, y, r;
} My_data;

My_data md;  /* 1. Global variable */


void win1_on_expose (Ez_event *ev)
{
    /* 3. Use */
    ez_draw_circle (ev->win, md.x-md.r, md.y-md.r, md.x+md.r, md.y+md.r);
}


void win1_on_event (Ez_event *ev)
{
   switch (ev->type) {
        case Expose : win1_on_expose (ev); break;
    }
}


int main ()
{
    if (ez_init() < 0) exit(1);

    /* 2. Initialization */
    md.x = 200; md.y = 100; md.r = 50;

    ez_window_create (400, 300, "Demo client-data 1", win1_on_event);

    ez_main_loop ();
    exit(0);
}

Here is now the same program but without using global variable; the data are stored in the window:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "ez-draw.h"

typedef struct {
    int x, y, r;
} My_data;


void win1_on_expose (Ez_event *ev)
{
    /* 4. We retrieve the data stored in the window */
    My_data *md = ez_get_data (ev->win);

    /* 5. Use */
    ez_draw_circle (ev->win, md->x-md->r, md->y-md->r, md->x+md->r, md->y+md->r);
}


void win1_on_event (Ez_event *ev)
{
   switch (ev->type) {
        case Expose : win1_on_expose (ev); break;
    }
}


int main ()
{
    Ez_window win1;
    My_data md;  /* 1. Local variable to main() */

    if (ez_init() < 0) exit(1);

    /* 2. Initialization */
    md.x = 200; md.y = 100; md.r = 50;

    win1 = ez_window_create (400, 300, "Demo client-data 2", win1_on_event);

    /* 3. We store the data in the window */
    ez_set_data (win1, &md);

    ez_main_loop ();
    exit(0);
}

As another example, see demo-10.c.

2.10. The image type

EZ-Draw allows to display or to manipulate images, thanks to the type:

Ez_image

Main struct type to store an image.

This type is defined in ez-image.h as follows:

typedef struct {
    int width, height;
    Ez_uint8 *pixels_rgba;
    int has_alpha;
    int opacity;
} Ez_image;

Guess what: the image width in pixels is width and its height is height.

The pixels are stored in the table pixels_rgba as R,G,B,A (for red, green, blue and alpha, that is to say transparency) each having a value between 0 and 255 (255 is the maximum intensity or opacity).

The R,G,B,A values of a pixel having coordinates x,y in the image are stored in pixels_rgba[(y*width+x)*4 + 0..3].

The has_alpha field indicates if the alpha channel is used (has_alpha = 1) or ignored (has_alpha = 0) when displaying. If the channel is ignored, all pixels are displayed; if used, just the opaque pixels are displayed.

The opaque pixels are those for which the alpha channel is greater or equal to the opacity threshold, specified by the opacity field; by default, the opacity threshold is 128.

Warning:
do not modified the fields width, height, pixels_rgba of an image, since they describe the allocated memory. However, you can change the fields has_alpha, opacity, as well as the pixel values in pixels_rgba[]. You may also use the following functions.
void ez_image_set_alpha(Ez_image *img, int has_alpha)
int ez_image_has_alpha(Ez_image *img)
void ez_image_set_opacity(Ez_image *img, int opacity)
int ez_image_get_opacity(Ez_image *img)

Get back or change the fields has_alpha and opacity.

These functions simply do nothing if img is NULL.

2.11. Managing images

To use the following functions you must include ez-image.h.

Ez_image *ez_image_create(int w, int h)

Create an image having width w and height h, in pixels.

Return the created image, or NULL on error.

Ez_image *ez_image_load(const char *filename)

Load an image from the file filename. The file must be in PNG, JPEG, GIF or BMP format.

Transparency is supported for PNG, GIF and BMP format: if the file contains an alpha channel, then the field has_alpha of the image is set to 1.

Return the created image, or NULL on error.

Ez_image *ez_image_dup(Ez_image *img)

Create a deep copy of the image img.

Return the created image, or NULL on error.

void ez_image_destroy(Ez_image *img)

Destroy an image in memory.

All images created by ez_image_... should be destroyed using this function.

void ez_image_paint(Ez_window win, Ez_image *img, int x, int y)

Display an image in the window win, with the upper left corner of the image at the x,y coordinates in the window. If img->has_alpha is true, apply transparency, that is to say, only display opaque pixels.

void ez_image_paint_sub(Ez_window win, Ez_image *img, int x, int y, int src_x, int src_y, int w, int h)

Display a rectangular region of an image in the window win.

The image region is bounded by coordinates src_x, src_y (top left corner) and src_x+w-1, src_y+h-1 (bottom right corner) in the image. If the coordinates go beyond the image, just the region which actually fits in the image is displayed.

The top left corner of the region is displayed at the x,y coordinate in the window. If img->has_alpha is true, apply transparency.

void ez_image_print(Ez_image *img, int src_x, int src_y, int w, int h)

Display a rectangular region of an image in the terminal.

The image region is bounded by coordinates src_x, src_y (top left corner) and src_x+w-1, src_y+h-1 (bottom right corner) in the image. If the coordinates go beyond the image, just the region which actually fits in the image is displayed.

2.12. Operations on images

This section presents some operations which are available by including ez-image.h. These operations are done on colors and on the alpha channel.

void ez_image_fill_rgba(Ez_image *img, Ez_uint8 r, Ez_uint8 g, Ez_uint8 b, Ez_uint8 a)

Fill an image with color r,g,b,a.

The values are between 0 and 255.

void ez_image_blend(Ez_image *dst, Ez_image *src, int dst_x, int dst_y)
void ez_image_blend_sub(Ez_image *dst, Ez_image *src, int dst_x, int dst_y, int src_x, int src_y, int w, int h)

Superimpose a region of image src into the image dst.

The region of source image src is bounded by coordinates src_x, src_y (top left corner) and src_x+w-1, src_y+h-1 (bottom right corner). The function superimposes this region into the destination image dst at coordinates dst_x, dst_y (top left corner) and dst_x+w-1, dst_y+h-1 (bottom right corner).

If the coordinates go beyond the images src or dst, just the common region is superimposed. If the source image has no alpha channel (src->has_alpha is false), then the pixel values from the src region overwrite those of dst. Otherwise, the regions are melted by transparency (alpha blending) using formulas of Porter and Duff.

Ez_image *ez_image_extract(Ez_image *img, int src_x, int src_y, int w, int h)

Create an image containing a copy of a rectangular region of the source image img.

The region of the image is bounded by coordinates src_x, src_y (top left corner) and src_x+w-1, src_y+h-1 (bottom right corner) in img. If the coordinates go beyond the image, just the region fitting in the image is extracted.

Return NULL on memory error or if intersection is empty.

Ez_image *ez_image_sym_ver(Ez_image *img)
Ez_image *ez_image_sym_hor(Ez_image *img)

Create an image of same size and properties as the source image img, containing the symmetrical image with respect to the vertical or horizontal axis.

Return the new image, or NULL on error.

Ez_image *ez_image_scale(Ez_image *img, double factor)

Create an image whose size is scaled by the factor with respect to the source image img, containing the rescaled image. The scale factor factor must be strictly positive.

Return the new image, or NULL on error.

Ez_image *ez_image_rotate(Ez_image *img, double theta, int quality)

Compute a rotation of the source image img for angle theta, in degrees. Return a new image whose size is adjusted to contain the result, or NULL on error.

In the resulting image, the field has_alpha is set to 1, and the parts not coming from the source image are transparent, in such a manner that they will not appear when displaying.

If quality = 1, the function smooths the result (with a bi-linear interpolation); if quality = 0, the function focuses on speed (using a closest neighbour computation), which saves a factor about 3.

Note :
the result being independent from the rotation center, it is not required as a parameter; however you can separately choose a rotation center and compute its coordinates in the destination image, thanks to the following function:
void ez_image_rotate_point(Ez_image *img, double theta, int src_x, int src_y, int *dst_x, int *dst_y)

Compute for a point having coordinates src_x,src_y in the source image, the corresponding coordinates dst_x,dst_y of the point in the destination image.

The example demo-16.c illustrates rotations, with or without transparency. The rotation center (red cross) is movable with the arrow keys. You can even modify quality.

These windows are obtained:

demo-16-1 demo-16-2 demo-16-3

2.13. Speed up image display

We have seen in the previous sections the type Ez_image defined in ez-image.h.

This type is convenient for loading, transforming and displaying images. However, displaying an image takes a few milliseconds to a few tens of milliseconds, this duration varying with the image size and computer power.

The reason is that for each display, ez_image_paint() computes again the whole conversion from the type Ez_image, to an intermediate image in memory, applies the transparency if needed, sends the result to the graphic card, which finally displays it.

We can trace the duration of operations in the terminal, by setting an environment variable then running one of the demonstration programs: on Unix, type

export EZ_IMAGE_DEBUG=1

or on Windows, type:

set EZ_IMAGE_DEBUG=1

We obtain this for instance on Unix:

$ ./demo-14
ez_image_load  file "images/paper1.jpg"  in 8.725 ms  w = 640  h = 480  n = 3  has_alpha = 0
ez_image_load  file "images/tux1.png"  in 1.946 ms  w = 210  h = 214  n = 4  has_alpha = 1
ez_xi_create  w = 640  h = 480  depth = 24  bpp = 32
ez_xi_fill_24 2.875 ms
ez_xi_create  w = 210  h = 214  depth = 24  bpp = 32
ez_xi_fill_24 0.132 ms
ez_xmask_create   fill 0.119 ms   bitmap 5.610 ms

To cancel this environment variable on Unix, type:

unset EZ_IMAGE_DEBUG

or on Windows, type:

set EZ_IMAGE_DEBUG=

In an animation, all these times add up, and when there are a lot of images, the animation may be jerky. The solution is simple: convert the image of type Ez_image as a pixmap of type Ez_pixmap, then display the pixmap.

typedef struct Ez_pixmap

A pixmap is an image already converted and stored in the graphic card. Its display is way faster, and also relieves the processor of the machine.

Once created, a pixmap is immutable.

This solution is also interesting to display a background image (which size is often large). In this case, we can also gain efficiency by using an image without alpha channel.

The type Ez_pixmap is defined as:

typedef struct {
    int width, height;
    /* other fields private */
} Ez_pixmap

The following functions handle pixmaps:

Ez_pixmap *ez_pixmap_create_from_image(Ez_image *img)

Create a pixmap from an image img. The pixmap keeps the image transparency. The image can then be freed if no longer needed.

Return the new pixmap, or NULL on error.

void ez_pixmap_destroy(Ez_pixmap *pix)

Delete the pixmap pix.

All pixmaps must be freed by this function.

void ez_pixmap_paint(Ez_window win, Ez_pixmap *pix, int x, int y)

Display the pixmap pix in the window win.

The top left corner of the pixmap is displayed at the x,y coordinates in the window.

void ez_pixmap_tile(Ez_window win, Ez_pixmap *pix, int x, int y, int w, int h)

Display the pixmap pix repeatedly in the window win.

The pixmap is displayed as a wallpaper in the window region bounded by coordinates x,y (top left corner) and x+w-1,y+h-1 (bottom right corner).

The example demo-17.c allows to check the display speed, measured in fps (frame per second) in an animation. Use keys + and - to change the number of balls, and key p to enable or disable the use of pixmaps.

This window is obtained:

demo-17

2.14. Miscellaneous

int ez_random(int n)

Return a random integer between 0 and n-1.

Note: the random generator is initialized by ez_init().

double ez_get_time()

Return the time elapsed since the Epoch (1970, january the 1st at 0:00:00) in seconds, with a precision in microseconds.

This function is usefull for measuring the duration of computations: just call ez_get_time() before and after the computation, and then display the difference:

double t1, t2;
t1 = ez_get_time ();
my_computation ();
t2 = ez_get_time ();
printf ("Duration: %.6f s\n", t2-t1)