AG_DRIVER(3)

NAME
AG_Driver - agar low-level driver interface

SYNOPSIS

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

DESCRIPTION
Agar implements low-level access to the graphics hardware, event processing and window management using a modular driver interface. The class registration interface allows Agar to be "ported" to new platforms, environments and graphics systems. New drivers can be implemented as part of an application or third-party library, without need for changes in the Agar 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 (at least not directly) 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 native window. Another example would be a simple framebuffer in an embedded device, which might also use AG_DriverSw. When a single-window driver is used, Agar provides an internal window manager.

The AG_DriverMw subclass (for "multiple-window") is used by drivers that talk to some underlying window system. In a multiple-window environment, each AG_Window(3) is associated with a "native" window on the system. For example, the "glx" driver uses the Xlib API to manage windows and the GLX extension to create accelerated rendering contexts.

The event processing functions of AG_Driver are important to applications which use custom event loops (see AG_CustomEventLoop(3) for an example). They make it possible for Agar applications to catch and process low-level events in a driver-independent way (see EVENTS below).

DRIVER INTERFACE
AG_Driver * AG_DriverOpen(AG_DriverClass *dc, const char *spec)

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 AG_InitGraphics(3) (or AG_WindowNew(3) in the case of multiple-window drivers). The optional spec argument may include a colon-separated list of driver options.

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 controls */
        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 */
        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 surface,
                                  float w, float h);
        void (*blitSurfaceFlippedGL)(void *d, AG_Widget *wid,
                                     int surface,
                                     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 */
        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 (*drawTriangle)(void *d, const AG_Pt *v1,
                                      const AG_Pt *v2,
                                      const AG_Pt *v3,
                                      const AG_Color *c);
        void (*drawPolygon)(void *d, const AG_Pt *pts,
                            Uint nPts, const AG_Color *c);
        void (*drawPolygonSti32)(void *d, const AG_Pt *pts,
                                 Uint nPts, const AG_Color *c,
                                 const Uint8 *stipple);
        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 radius,
                               const AG_Color *c1,
                               const AG_Color *c2);
        void (*drawBoxRoundedTop)(void *d, const AG_Rect *r,
                                  int z, int radius,
                                  const AG_Color *c1,
                                  const AG_Color *c2,
                                  const AG_Color *c3);
        void (*drawCircle)(void *d, int x, int y,
                           int radius,
                           const AG_Color *c);
        void (*drawCircleFilled)(void *d, int x, int y,
                                 int radius,
                                 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 */
        void (*deleteList)(void *d, Uint listID);
        /* Clipboard integration */
        char *(*getClipboardText)(void *d);
        int   (*setClipboardText)(void *d, const char *text);
        /* Mouse auto-capture control */
        void (*setMouseAutoCapture)(void *d, int state);
    } AG_DriverClass;

The type field should be set to AG_FRAMEBUFFER if this driver renders directly to video memory or a framebuffer, or AG_VECTOR if this driver uses OpenGL for rendering.

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_SDL1
    SDL 1.x calls are supported.
AG_DRIVER_SDL2
    SDL 2.x calls are supported.
AG_DRIVER_SDL
    SDL (1.x or 2.x) calls are supported.
AG_DRIVER_TEXTURES
    Texture management operations are supported.

The open() method initializes a new driver instance. It is expected to initialize the mouse, kbd and joys members of AG_Driver (see AG_MouseNew(3), AG_KeyboardNew(3) and AG_JoystickNew(3)). open() should return 0 on success or -1 on failure.

The close() method is invoked to destroy a driver instance. It is expected to destroy all attached input devices.

The getDisplaySize() method writes the total available display size in pixels to w and h and returns 0 on success or -1 on failure. 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 the size of one workspace).

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.

The optional setMouseAutoCapture() operation enables (1), disables (0) or resets (-1) mouse auto-capture behavior due to mouse button events. When mouse auto-capture is enabled, the mouse is automatically captured on Mouse Button Down and released on Mouse Button Up.

EVENTS
int AG_PendingEvents(AG_Driver *d)

int AG_GetNextEvent(AG_Driver *d, AG_DriverEvent *dev)

int AG_ProcessEvent(AG_Driver *d, AG_DriverEvent *dev)

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
    Cursor has moved to motion.{x,y}.
AG_DRIVER_MOUSE_BUTTON_DOWN
    Mouse button button.which has been pressed at coordinates button.{x,y}.
AG_DRIVER_MOUSE_BUTTON_UP
    Mouse button has been released.
AG_DRIVER_MOUSE_ENTER
    Cursor has entered the window area.
AG_DRIVER_MOUSE_LEAVE
    Cursor has left the window area.
AG_DRIVER_FOCUS_IN
    Application focus has been gained.
AG_DRIVER_FOCUS_OUT
    Application focus has been lost.
AG_DRIVER_KEY_DOWN
    A key with keysym key.ks has been pressed. See: AG_KeySym(3). key.ucs is the matching Unicode character (if any).
AG_DRIVER_KEY_UP
    A key has been released.
AG_DRIVER_EXPOSE
    The WM requests the window to be redrawn.
AG_DRIVER_VIDEORESIZE
    The video display has been resized to videoresize.w x videoresize.h.
AG_DRIVER_CLOSE
    The user is closing the window. The default action is to post a ‘window-close’ event to the corresponding Agar window.
AG_DRIVER_MOVED
    The window has been moved to desktop coordinates moved.x and moved.y.
AG_DRIVER_MINIMIZED
    The window has been minimized.
AG_DRIVER_MAXIMIZED
    The window has been maximized.
AG_DRIVER_RESTORED
    Window has been restored following a previous minimize or maximize operation.
AG_DRIVER_SHOWN
    The window is now visible to the user.
AG_DRIVER_HIDDEN
    The window is now hidden from view.
AG_DRIVER_JOY_DEVICE_ADDED
    Joystick device has been attached.
AG_DRIVER_JOY_DEVICE_REMOVED
    Joystick device has been detached.
AG_DRIVER_JOY_AXIS_MOTION
    Joystick axis has moved (continuous).
AG_DRIVER_JOY_HAT_MOTION
    Joystick hat has moved (discrete).
AG_DRIVER_JOY_BALL_MOTION
    Joystick ball has moved (relative).
AG_DRIVER_JOY_BUTTON_DOWN
    Joystick button has been pressed.
AG_DRIVER_JOY_BUTTON_UP
    Joystick button has been released.

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.button.x,
    			    dev.button.y);
    			break;
    		case AG_DRIVER_KEY_DOWN:
    			printf("Key pressed: %d\n",
    			    (int)dev.key.ks);
    			break;
    		default:
    			break;
    		}
    		if (AG_ProcessEvent(NULL, &ev) == -1)
    			break;
    	}
    }

SEE ALSO
AG_DriverSw(3), AG_DriverMw(3), 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(). Joystick and touch events appeared in Agar 1.7.0. setMouseAutoCapture() appeared in Agar 1.7.0.