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
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).
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
AG_DriverClass structure inherits from the base
AG_Object(3) class, and is defined as follows:
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:
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).
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:
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.
The following code fragment implements a basic event loop.
It retrieves pending events, examines them, and forwards them to Agar
|AG_GL(3), AG_InitGraphics(3), AG_Intro(3), AG_Widget(3), AG_Window(3)|
|The AG_Driver interface first appeared in Agar 1.4.0.|