Integrating Agar in an existing GL application

From Agar

Jump to: navigation, search
Background render

Contents

Overview

In this example, we will arrange for Agar to work in conjuction with a "black box". We want the ability to switch the "focus" between the Agar GUI and our black box. We'll also demonstrate how input events can be processed by our application first, and conditionally passed on to the Agar GUI using a custom event loop.

This is a typical scenario when Agar GUI elements are to be added to an existing OpenGL application relying on an existing event loop.

This example is limited to OpenGL-based "single-window" graphics drivers such as sdlgl, where Agar provides a built-in window manager.

Event processing

First of all we need a custom event loop, which we will call MyEventLoop. Our event loop will render the black box before rendering the Agar GUI.

We also want to "trap" input device events before passing them on to Agar. More specifically, we want to process:

  • AG_DRIVER_MOUSE_BUTTON_DOWN, for switching focus between the background and GUI elements.
  • AG_DRIVER_VIDEORESIZE, for resizing our backgrounds
  • AG_DRIVER_KEY_DOWN, for keyboard events unrelated to the GUI

Rendering

Before rendering we need to process window resizing events. BG_Resize() saves the GL matrices and sets up our own view matrices. BG_Draw() saves Agar's matrices and GL attributes, restores the matrices saved by BG_Resize() and renders to the display. This is similar to what the AG_GLView(3) widget does.

Code example

For the functions MyResizeFunction() and MyDrawFunction(), see Integrating Agar in an existing GL application/Support code. Note that the Uint32 type is used, so the program should be compiled with _USE_AGAR_TYPES.

#include <agar/core.h>
#include <agar/gui.h>
#include <agar/gui/opengl.h>
 
#include <string.h>
#include <math.h>
 
int showUI = 1;		/* Show Agar GUI */
int bgFocused = 0;	/* Background focus */
int fps = 60;           /* Frames per second */
 
/*
 * Trap for mouse events. If we return 0, the event is
 * passed on to Agar.
 */
static int
TrapMouseEvent(const AG_DriverEvent *ev)
{
    int rv = 0;
    int x,y;
 
    switch (ev->type) {
    case AG_DRIVER_MOUSE_BUTTON_DOWN:
	x = ev->data.button.x;
	y = ev->data.button.y;
 
	switch (ev->data.button.which) {
	case AG_MOUSE_WHEELUP:
	    vz -= 0.1;
	    break;
	case AG_MOUSE_WHEELDOWN:
	    vz += 0.1;
	    break;
	}
	return (1);
    }
    return (rv);
}
 
/* Our custom keypress callback routine. */
static int
MyKeyCallback(const AG_DriverEvent *ev)
{
	/* ... */
	return (0);
}
 
/* Our custom event processing routine */
int
MyEventProcessor(AG_Driver *drv, AG_DriverEvent *ev)
{
    int rv = 0;
    int x,y;
 
    switch (ev->type) {
    case AG_DRIVER_MOUSE_BUTTON_DOWN:
	x = ev->data.button.x;
	y = ev->data.button.y;
 
	if (showUI && AG_WindowFocusAtPos(AGDRIVER_SW(drv), x,y)){
	    if (bgFocused) {
                bgFocused = 0;
                vz -= 1.0;     /* Move shape back */ 
	    }
	    return AG_ProcessEvent(drv, ev);
	} else {
	    if (bgFocused) {
		return TrapMouseEvent(ev);
	    } else {
                bgFocused = 1;
                vz += 1.0;    /* Move shape closer */
	    }
	}
	break;
    case AG_DRIVER_VIDEORESIZE:
	MyResizeFunction(ev); 
	rv = AG_ProcessEvent(drv, ev);
	break;
    case AG_DRIVER_KEY_DOWN:
	if (MyKeyCallback(ev)) {
	    return (1);
        }
    default:
	if (!bgFocused && showUI){
	    rv = AG_ProcessEvent(drv, ev);
	} else {
	    if (TrapMouseEvent(ev) != 1) {
		rv = AG_ProcessEvent(drv, ev);
            } else {
                return (1);
            }
	}
    }
    return (rv);
}
 
/*
 * Our custom event loop
 */
void
MyEventLoop(AG_Driver *drv)
{
    AG_Window *win;
    Uint32 Tr1, Tr2 = 0;
 
    Tr1 = AG_GetTicks();
    for (;;){
	Tr2 = AG_GetTicks();
	if (Tr2-Tr1 >= 1000/fps) {
            /*
             * Render a frame
             */
	    AG_BeginRendering(drv);
 
	    /* Draw our background */
	    MyDrawFunction();
 
	    /* Draw Agar's windows */
	    if (showUI){
                AG_LockVFS(drv);
		AG_FOREACH_WINDOW(win, drv) {
		    AG_ObjectLock(win);
		    AG_WindowDraw(win);
		    AG_ObjectUnlock(win);
		}
                AG_UnlockVFS(drv);
	    }
	    AG_EndRendering(drv);
	    Tr1 = AG_GetTicks();
	} else if (AG_PendingEvents(drv) != 0) {
            /*
             * Process pending events
             */
            AG_DriverEvent ev;
            do {
                if (AG_GetNextEvent(drv, &ev)) {
	            if (MyEventProcessor(drv, &ev) == -1)
		        return;
                }
            } while (AG_PendingEvents(drv) != 0);
	} else if (AG_TIMEOUTS_QUEUED()) {
            /*
             * Process expired timers
             */
	    AG_ProcessTimeouts(Tr2);
	} else {
            /* Idle */
	    AG_Delay(1);
	}
    }
}
 
int
main(int argc, char *argv[])
{
    AG_Window *win;
    AG_GLView *glv;
    AG_Box *hb;
    AG_HSVPal *pal;
    int i;
 
    if (AG_InitCore("agar-background-demo", 0) == -1) {
        fprintf(stderr, "%s\n", AG_GetError());
        exit(1);
    }
 
    /*
     * Use AG_InitVideo() instead of AG_InitGraphics(), because we do not want to interface
     * with an existing window manager. This will likely select a driver such as "sdlgl".
     */
    if (AG_InitVideo(640, 480, 32, AG_VIDEO_OPENGL|AG_VIDEO_RESIZABLE) == -1) {
        fprintf(stderr, "%s\n", AG_GetError());
        exit(1);
    }
 
    /* Create a settings window. */
    win = AG_WindowNew(0);
    hb = AG_BoxNewHoriz(win, 0);
    AG_Expand(hb);
    {
    	AG_Notebook *nb;
    	AG_NotebookTab *ntab;
 
    	nb = AG_NotebookNew(hb, AG_NOTEBOOK_VFILL);
	AG_Expand(nb);
	{
    		ntab = AG_NotebookAddTab(nb, "Amb", AG_BOX_VERT);
    		pal = AG_HSVPalNew(ntab, AG_HSVPAL_VFILL);
    		AG_BindFloat(pal, "RGBAv", ambient);
 
    		ntab = AG_NotebookAddTab(nb, "Dif", AG_BOX_VERT);
    		pal = AG_HSVPalNew(ntab, AG_HSVPAL_VFILL);
    		AG_BindFloat(pal, "RGBAv", diffuse);
 
    		ntab = AG_NotebookAddTab(nb, "Spe", AG_BOX_VERT);
    		pal = AG_HSVPalNew(ntab, AG_HSVPAL_VFILL);
    		AG_BindFloat(pal, "RGBAv", specular);
	}
 
	AG_ButtonNewInt(hb, AG_BUTTON_STICKY,
	    "Wireframe Mode", &wireframe);
    }
    AG_WindowShow(win);
 
    /* Create a bunch of test windows */
    for (i = 0; i < 5; i++) {
        win = AG_WindowNew(0);
        AG_WindowSetCaption(win, "TL%d", i);
        AG_LabelNew(win, 0, "Top Left %d", i);
        AG_WindowSetPosition(win, AG_WINDOW_TL, 1);
        AG_WindowShow(win);
    }
 
    /*
     * Enter our custom event loop; agDriverSw is a pointer to the (single-window)
     * driver instance which was created AG_InitVideo().
     */
    MyEventLoop(AGDRIVER(agDriverSw));
 
    AG_Destroy();
    return (0);
}

See also

Personal tools