AG_DRIVER(3)

NAME
AG_Driver - agar low-level driver interface

SYNOPSIS

    #include <agar/core.h>
    #include <agar/gui.h>

DESCRIPTION
In Agar, low-level graphics rendering, event processing and window management is handled by modular "drivers". A simple class registration interface allows Agar to be "ported" to new platforms, environments and graphics systems. In a manner similar to Agar widgets, new Agar "drivers" may be implemented as part of an application, without need for changing the Agar source code itself.

For the list of drivers included in the Agar distribution, see the AG_InitGraphics(3) manual page, under "AVAILABLE DRIVERS".

The interface differs based on whether an underlying window system is available. All drivers are a subclass of AG_Driver. The AG_DriverSw subclass (for "single-window") is used by drivers that do not interface with an underlying window system. For example, the "sdlfb" and "sdlgl" drivers use the SDL 1.x API, and are therefore limited to a single window as far as the native window system is concerned). A dumb framebuffer used in an embedded device would also use the AG_DriverSw subclass.

The AG_DriverMw subclass (for "multiple-window") is used by drivers that do interface with an underlying window system. In a multiple-window environment, each Agar window (e.g., each window created by AG_WindowNew(3)) is associated with a "native" window. For example, the "glx" driver uses the GLX API to create an accelerated rendering context, and also uses the Xlib API to manage windows.

The part of the AG_Driver API that deals with low-level event processing is of particular importance to applications using custom event loops (see AG_CustomEventLoop(3) for an example). It is possible, in a driver-independent fashion, for an application to catch and process low-level events (see below).

DRIVER INTERFACE
AG_Driver * AG_DriverOpen(AG_DriverClass *dc)

void AG_DriverClose(AG_Driver *d)

void AG_ListDriverNames(char *buf, AG_Size buf_len)

int AG_UsingGL(AG_Driver *d)

int AG_UsingSDL(AG_Driver *d)

int AG_GetDisplaySize(AG_Driver *d, Uint *w, Uint *h)

The AG_DriverOpen() function creates a new instance of a driver class, as described by dc (see section below). AG_DriverClose() destroys a driver instance. These two functions are seldom used directly, since they are called internally from either AG_InitGraphics(3) or AG_WindowNew(3) in the case of multiple-window drivers (which use one driver instance per window).

The AG_ListDriverNames() returns a space-separated list of available drivers for the current platform, into the specified buffer buf of size buf_len.

The AG_UsingGL() and AG_UsingSDL() functions return 1 if Agar is using OpenGL or SDL, respectively. d is a pointer to the driver instance (or if NULL, use the default driver instance).

The AG_GetDisplaySize() function obtains the maximum available display area in pixels. On success, the dimensions are returned into the w and h arguments, and the function returns 0. d is a pointer to the driver instance (or if NULL, use the default driver instance).

DRIVER CLASS STRUCTURE
The AG_DriverClass structure inherits from the base AG_Object(3) class, and is defined as follows:

    typedef struct ag_driver_class {
        struct ag_object_class _inherit;
        const char *name;          /* Short name */
        enum ag_driver_type type;  /* Driver type */
        enum ag_driver_wm_type wm; /* Window manager type */
        Uint flags;                /* Driver class options */
        /*
         * Initialization
         */
        int  (*open)(void *d, const char *spec);
        void (*close)(void *d);
        int  (*getDisplaySize)(Uint *w, Uint *h);
        /*
         * Event processing
         */
        void (*beginEventProcessing)(void *d);
        int  (*pendingEvents)(void *d);
        int  (*getNextEvent)(void *d, AG_DriverEvent *dev);
        int  (*processEvent)(void *d, AG_DriverEvent *dev);
        void (*genericEventLoop)(void *d);
        void (*endEventProcessing)(void *d);
        void (*terminate)(void);
        /*
         * Rendering and texture management
         */
        void (*beginRendering)(void *d);
        void (*renderWindow)(AG_Window *w);
        void (*endRendering)(void *d);
        void (*fillRect)(void *d, const AG_Rect *r, const AG_Color *c);
        void (*updateRegion)(void *d, const AG_Rect *r);
        void (*uploadTexture)(void *d, Uint *id,AG_Surface *s, AG_TexCoord *c);
        void (*updateTexture)(void *d, Uint id, AG_Surface *s, AG_TexCoord *c);
        void (*deleteTexture)(void *d, Uint id);
        int (*setRefreshRate)(void *d, int fps);
        /*
         * Clipping and blending control (rendering context)
         */
        void (*pushClipRect)(void *d, const AG_Rect *r);
        void (*popClipRect)(void *d);
        void (*pushBlendingMode)(void *d, AG_AlphaFn s, AG_AlphaFn d);
        void (*popBlendingMode)(void *d);
        /*
         * Hardware cursor interface
         */
        AG_Cursor *(*createCursor)(void *d, Uint w, Uint h,
                                   const Uint8 *data, const Uint8 *mask,
                                   int xHot, int yHot);
        void (*freeCursor)(void *d, AG_Cursor *curs);
        int  (*setCursor)(void *d, AG_Cursor *curs);
        void (*unsetCursor)(void *d);
        int  (*getCursorVisibility)(void *d);
        void (*setCursorVisibility)(void *d, int flag);
        /*
         * Widget surface operations (rendering context)
         */
        void (*blitSurface)(void *d, AG_Widget *wid, AG_Surface *s,
                            int x, int y);
        void (*blitSurfaceFrom)(void *d, AG_Widget *wid, int s,
                                const AG_Rect *r, int x, int y);
    #ifdef HAVE_OPENGL
        void (*blitSurfaceGL)(void *d, AG_Widget *wid, AG_Surface *s,
                              float w, float h);
        void (*blitSurfaceFromGL)(void *d, AG_Widget *wid, int s,
                                  float w, float h);
        void (*blitSurfaceFlippedGL)(void *d, AG_Widget *wid, int s,
                                     float w, float h);
    #endif
        void (*backupSurfaces)(void *d, AG_Widget *wid);
        void (*restoreSurfaces)(void *d, AG_Widget *wid);
        int  (*renderToSurface)(void *d, AG_Widget *wid, AG_Surface **s);
        /*
         * Rendering operations (rendering context)
         */
        void (*putPixel)(void *d, int x, int y, const AG_Color *c);
        void (*putPixel32)(void *d, int x, int y, Uint32 px);
        void (*putPixelRGB8)(void *d, int x, int y, Uint8 r, Uint8 g, Uint8 b);
    #if AG_MODEL == AG_LARGE
        void (*putPixel64)(void *d, int x, int y, Uint64 px);
        void (*putPixelRGB16)(void *d, int x, int y,
                              Uint16 r, Uint16 g, Uint16 b);
    #endif
        void (*blendPixel)(void *d, int x, int y, const AG_Color *c,
                           AG_AlphaFn fnSrc, AG_AlphaFn fnDst);
        void (*drawLine)(void *d, int x1, int y1, int x2, int y2,
                         const AG_Color *c);
        void (*drawLineH)(void *d, int x1, int x2, int y, const AG_Color *c);
        void (*drawLineV)(void *d, int x, int y1, int y2, const AG_Color *c);
        void (*drawLineBlended)(void *d, int x1, int y1, int x2, int y2,
                                const AG_Color *c,
                                AG_AlphaFn fnSrc, AG_AlphaFn fnDst);
        void (*drawLineW)(void *d, int x1, int y1, int x2, int y2,
                          const AG_Color *c, float width);
        void (*drawLineW_Sti16)(void *d, int x1, int y1, int x2, int y2,
                                const AG_Color *c, float width, Uint16 mask);
        void (*_Nonnull drawTriangle)(void *_Nonnull, const AG_Pt *_Nonnull,
                                      const AG_Pt *_Nonnull, const AG_Pt *_Nonnull,
                                      const AG_Color *_Nonnull);
        void (*_Nonnull drawPolygon)(void *_Nonnull, const AG_Pt *_Nonnull, Uint,
                                     const AG_Color *_Nonnull);
        void (*_Nonnull drawPolygonSti32)(void *_Nonnull, const AG_Pt *_Nonnull,
                                          Uint, const AG_Color *_Nonnull,
                                          const Uint8 *_Nonnull);
        void (*drawArrow)(void *d, float angle, int x, int y, int h,
                          const AG_Color *c1, const AG_Color *c2);
        void (*drawBoxRounded)(void *d, const AG_Rect *r, int z, int rad,
                               const AG_Color *c1, const AG_Color *c2);
        void (*drawBoxRoundedTop)(void *d, const AG_Rect *r, int z, int rad,
                                  const AG_Color *c1, const AG_Color *c2,
                                  const AG_Color *c3);
        void (*drawCircle)(void *d, int x, int y, int r, const AG_Color *c);
        void (*drawCircleFilled)(void *d, int x, int y, int r, const AG_Color *c);
        void (*drawRectFilled)(void *d, const AG_Rect *r, const AG_Color *c);
        void (*drawRectBlended)(void *d, const AG_Rect *r, const AG_Color *c,
                                AG_AlphaFn fnSrc, AG_AlphaFn fnDst);
        void (*drawRectDithered)(void *d, const AG_Rect *r, const AG_Color *c);
        /* Typography */
        void (*updateGlyph)(void *d, AG_Glyph *gl);
        void (*drawGlyph)(void *d, const AG_Glyph *gl, int x, int y);
        /* Display list management (GL driver specific) */
        void (*deleteList)(void *d, Uint listID);
        /* Clipboard access */
        char *(*getClipboardText)(void *);
        int   (*setClipboardText)(void *, const char *);
    } AG_DriverClass;

The type field should be set to AG_FRAMEBUFFER for dumb-framebuffer drawing, or AG_VECTOR for vector-based drawing such as OpenGL.

The wm field may be set to AG_WM_SINGLE for single-window drivers, or AG_WM_MULTIPLE for multiple-window drivers.

Acceptable values for the flags field include:
AG_DRIVER_OPENGL
    OpenGL calls are supported.
AG_DRIVER_SDL
    SDL 1.x calls are supported.
AG_DRIVER_TEXTURES
    Texture management operations are supported.

The open() method is invoked to initialize a new driver instance. open() is expected to initialize the mouse and kbd fields of AG_Driver (see AG_MouseNew(3), AG_KeyboardNew(3)). Return 0 on success and -1 on failure.

The close() method is invoked to destroy a driver instance. It is expected to destroy the mouse and kbd fields of AG_Driver.

The getDisplaySize() operation should return the total display size available, in pixels, into w and h. For single-window drivers, this is the size of the display available to Agar. For multiple-window drivers, this is the total size of the desktop (if multiple workspaces are supported, it should be limited to the size of a single workspace in pixels). This operation should return 0 on success and -1 on failure.

The beginEventProcessing() callback is invoked before event processing begins. Most drivers will not need to do anything here.

pendingEvents() returns a non-zero value if there are events waiting to be processed (see AG_PendingEvents()).

getNextEvent() retrieves and remove the next event from the queue (see AG_GetNextEvent()).

processEvent() processes the event described by dev (see AG_ProcessEvent()).

The genericEventLoop() method is obsolete as of Agar-1.5 (see AG_EventLoop(3)).

The endEventProcessing() callback is invoked after event processing is done. For most drivers, there is nothing to do here.

The terminate() operation is obsolete as of Agar-1.5 (see AG_Terminate(3)).

The beginRendering() and endRendering() operations are invoked by AG_BeginRendering(3) and AG_EndRendering(3) to prepare for rendering of GUI elements.

The renderWindow() operation renders an Agar window. Usually, it will simply invoke AG_WidgetDraw(3) on win. Framebuffer drivers may also want to update video regions from here.

The fillRect() operation is expected to fill a rectangle r with color c.

The updateRegion() operation, usually specific to framebuffer drivers, is expected to update a region of video memory represented by r.

uploadTexture(), updateTexture() and deleteTexture() are specific to drivers with texture management facilities. uploadTexture() creates a texture from an AG_Surface(3), returning the computed texture coordinates. updateTexture() is expected to update an existing texture from a recently modified surface. deleteTexture() arranges for the specified texture to be deleted as soon as possible.

The setRefreshRate() operation is invoked by AG_SetRefreshRate(3), to configure a fixed refresh rate, as a driver-specific hint that can be ignored.

pushClipRect() should create a clipping rectangle over r. If a clipping rectangle is already in effect, it should be saved on a stack. popClipRect() pops the last clipping rectangle off the stack.

pushBlendingMode() should configure an alpha blending mode (see AG_AlphaFn(3)). If a blending mode is already set, it should be saved on a stack. popBlendingMode() pops the last blending mode off the stack.

The following operations are optional and provide Agar with access over hardware cursors. See AG_Cursor(3) for details on the Agar cursor control interface.

The createCursor() operation creates a hardware cursor from the bitmap data data and transparency mask mask. The hotspot coordinates are given in xHot, yHot. If a hardware cursor cannot be allocated, the call should return NULL. freeCursor() destroys any hardware cursor corresponding to the given AG_Cursor structure.

The setCursor() operation changes the current cursor to the specified cursor, returning 0 on success or -1 on failure. unsetCursor() reverts to the default cursor.

The getCursorVisibility() and setCursorVisibility() routines retrieve and set the cursor visibility flag.

The following operations form the backend of the AG_Widget(3) surface operations such as AG_WidgetBlitFrom(3). They all accept a AG_Widget argument, and coordinate arguments are always with respect to the widget's local coordinate system.

blitSurface() implements AG_WidgetBlit(3), which performs an unaccelerated (software) blit from any AG_Surface(3), to target coordinates x, y. Note: Efficient code should use blitSurfaceFrom() instead.

blitSurfaceFrom() implements AG_WidgetBlitFrom(3), which uses a widget-mapped surface as source. If a texture unit is available then the previously uploaded hardware texture is used as source. If texture hardware is not available, a software blit is done.

The blitSurfaceGL() and blitSurfaceFromGL() variants are specific to OpenGL drivers. Instead of accepting an explicit source or destination rectangle parameter, they rely on the current transformation matrix being set accordingly. blitSurfaceFlippedGL() reverses the order of the rows in the image.

The backupSurfaces() operation should create a software backup of all surfaces registered under the given widget. restoreSurfaces() restores a widget's surfaces from backup. These operations are needed with OpenGL on some platforms, where a window resize may result in a loss of OpenGL context data.

The renderToSurface() operation renders a widget to a newly allocated AG_Surface(3), returned into the su argument. The function should return 0 on success or -1 on failure.

putPixel(), putPixel32(), putPixel64(), putPixelRGB8() and putPixelRGB16() write a packed pixel of specified color at coordinates x, y. If the display surface uses 8-bit precision components, putPixel64() and putPixelRGB16() should compress component ranges to the best 8-bit approximation.

blendPixel() blends the pixel at x, y against the specified AG_Color using the source and destination blending factors fnSrc and fnDst.

drawLine() renders a line of color C from endpoint x1, y1 to endpoint x2, y2. The drawLineH() operation renders a horizontal line, and drawLineV() renders a vertical line. drawLineBlended() renders a line with transparency (see AG_AlphaFn(3)).

drawArrow() renders an arrow of length h at coordinates x, y and clockwise rotation angle (0=up, 90=right, 180=down, 270=left).

drawBoxRounded() renders a 3D-style box of depth z, with corners rounded to radius rad. The drawBoxRoundedTop() variant only rounds the two top corners.

The drawCircle() operation renders a circle of radius r, centered around x, y. The drawCircle2() variant adds a 3D-style effect.

The drawRectFilled() operation fills the target rectangle r with the given color drawRectBlended() renders a filled rectangle with transparency (see AG_AlphaFn(3)). drawRectDithered() renders a filled rectangle with ditering effect (commonly used to illustrate "disabled" GUI controls).

The updateGlyph() operation ensures that the specified font glyph (see AG_Text(3)) is ready to be rendered. OpenGL drivers, for example, can use this operation to upload a rendered version of the glyph to the texture hardware. The drawGlyph() operation renders a given font glyph at target coordinates x, y. The target point will correspond to the top left corner of the rendered glyph.

The deleteList() operation arranges for the specified display list to be deleted as soon as possible (typically in the endRendering() routine).

The optional getClipboardText() operation returns a newly-allocated string with the clipboard contents (in UTF-8). The returned string is freeable by the caller.

The optional setClipboardText() operation sets the clipboard contents to a copy of the given UTF-8 string and returns 0 on success or -1 on failure.

EVENT PROCESSING
int AG_PendingEvents(AG_Driver *d)

int AG_GetNextEvent(AG_Driver *d, AG_DriverEvent *dev)

int AG_ProcessEvent(AG_Driver *d, AG_DriverEvent *dev)

    /* Requires Agar compiled --with-sdl */

int AG_SDL_TranslateEvent(AG_Driver *d, const SDL_Event *ev, AG_DriverEvent *dev)

void AG_WindowProcessQueued(void)

Low-level driver events are represented by the AG_DriverEvent structure, which provides the public members type and win. The win member is a pointer to the corresponding AG_Window(3) (for single-window drivers, win is always NULL). The type field is an enum that can take on the values:

AG_DRIVER_MOUSE_MOTION
    Mouse cursor has moved to coordinates data.motion.{x,y}.
AG_DRIVER_MOUSE_BUTTON_DOWN
AG_DRIVER_MOUSE_BUTTON_UP
    Mouse button has been pressed or released at coordinates data.button.{x,y}. The button index is passed as data.button.which.
AG_DRIVER_MOUSE_ENTER
AG_DRIVER_MOUSE_LEAVE
    The mouse cursor has entered or left the window area. These events are specific to multiple-window drivers.
AG_DRIVER_FOCUS_IN
AG_DRIVER_FOCUS_OUT
    Application focus has been gained or lost. These events are specific to multiple-window drivers.
AG_DRIVER_KEY_DOWN
AG_DRIVER_KEY_UP
    A key has been pressed or released. The keysym (see AG_KeySym(3)) is passed as data.key.ks. A 32-bit Unicode (UCS-4) representation of the corresponding character, if any, is passed as data.key.ucs.
AG_DRIVER_EXPOSE
    The underlying graphics system is requesting a refresh of the video display.
AG_DRIVER_VIDEORESIZE
    The application window has been resized to data.videoresize.{w,h}. Some drivers may also raise this event when the window is moved.
AG_DRIVER_CLOSE
    The user has requested that a window be closed. For multiple-window drivers, the default behavior is to post a ‘window-close’ event to the corresponding Agar window. For single-window drivers, the application is usually terminated as a result.

The AG_PendingEvents() function returns 1 if there are events waiting to be processed, or 0 if the event queue is empty.

AG_GetNextEvent() retrieves and removes the next event on the queue, initializing the structure pointed by dev with its contents. AG_GetNextEvent() returns 1 if the event has been successfully retrieved into dev. The function returns 0 if the event was dequeued (and no further processing is required), or -1 if an error has occurred.

AG_ProcessEvent() processes the event pointed to by dev in the default manner. The call returns 1 if the event was successfully, 0 if Agar has ignored the event entirely, or -1 if an error has occurred.

The AG_SDL_TranslateEvent() function translates a SDL_Event(3) structure to an Agar AG_DriverEvent(). This function is only available if Agar was compiled with SDL support. Agar supports more than one driver instance per application. The d argument of AG_PendingEvents(), AG_GetNextEvent(), AG_ProcessEvent() and AG_SDL_TranslateEvent() can be set to NULL, in which case the default driver instance will be used.

EXAMPLES
The following code fragment implements a basic event loop. It retrieves pending events, examines them, and forwards them to Agar for processing:

    AG_DriverEvent ev;
    while (AG_PendingEvents(NULL) > 0) {
    	if (AG_GetNextEvent(NULL, &ev)) {
    		switch (ev.type) {
    		case AG_DRIVER_MOUSE_BUTTON_DOWN:
    			printf("Click at %d,%d\n",
    			    dev.data.button.x,
    			    dev.data.button.y);
    			break;
    		case AG_DRIVER_KEY_DOWN:
    			printf("Key pressed: %d\n",
    			    (int)dev.data.key.ks);
    			break;
    		default:
    			break;
    		}
    		if (AG_ProcessEvent(NULL, &ev) == -1)
    			break;
    	}
    }

SEE ALSO
AG_GL(3), AG_InitGraphics(3), AG_Intro(3), AG_Widget(3), AG_Window(3)

HISTORY
The AG_Driver interface first appeared in Agar 1.4.0. Agar 1.6.0 added the driver operations putPixel64(), putPixelRGB16(), drawTriangle(), drawPolygon(), drawPolygonSti32(), drawLineW(), drawLineW_Sti16(), getClipboardText() and setClipboardText().