Integrating Agar in an existing GL application
From Agar
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); }

