/**************************************************************************** ** Authors: Matteo Muratori, Michele Fabbri. ** ** Official website: http://www.amanithvg.com ** ** Copyright (C) 2004-2009 Mazatech S.r.l. All rights reserved. ** ** This file is part of AmanithVG library. ** Khronos and OpenVG are trademarks of The Khronos Group Inc. ** OpenGL is a registered trademark and OpenGL ES is a trademark of ** Silicon Graphics, Inc. ** ** This file is distributed under the terms of Mazatech End-User License ** Agreement for Evaluation Purposes only as defined by Mazatech S.r.l. of ** Italy and appearing in the file LICENSE.TXT included in the packaging ** of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** For any informations, please contact info@mazatech.com ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include "tiger.h" //#define RENDERING_ON_VGIMAGE // X11 variables static Display *display; static Window window; static Atom atom_DELWIN; static Atom atom_PROTOCOLS; // EGL variables static EGLDisplay eglDisplay = EGL_NO_DISPLAY; static EGLConfig eglConfigWindow = 0; static EGLSurface eglWindowSurface = EGL_NO_SURFACE; static EGLContext eglContext = EGL_NO_CONTEXT; #if defined(RENDERING_ON_VGIMAGE) #include static EGLSurface eglPbufferSurface = EGL_NO_SURFACE; static EGLConfig eglConfigPbuffer = 0; static VGImage destImg = VG_INVALID_HANDLE; #endif // user input variables static unsigned int time0, time1, framesCount; static unsigned int done; static struct app *App = NULL; #define xy_method(name) static void name(int x, int y) { App->name(x,y); } #define void_method(name) static void name(void) { App->name(); } xy_method(initApp) void_method(killApp) xy_method(drawScene) xy_method(mouseLeftButtonDown) xy_method(mouseLeftButtonUp) xy_method(mouseRightButtonDown) xy_method(mouseRightButtonUp) xy_method(mouseMove) void_method(changeQuality) void_method(toggleAnimation) void_method(resetParameters) static void keyFunction(Display *dpy, Window wnd, const KeySym key) { (void)dpy; (void)wnd; if (key == XK_b) toggleAnimation(); else if (key == XK_q) changeQuality(); else if (key == XK_r) resetParameters(); else if (key == XK_F1) { } else if (key == XK_F2) { } else if (key == XK_Escape) done = 1; } static void processEvent(Display *dpy, Window wnd, XEvent *ev) { switch (ev->type) { case KeyPress: keyFunction(dpy, wnd, XLookupKeysym(&ev->xkey, 0)); break; case ButtonPress: if (ev->xbutton.button == Button1) mouseLeftButtonDown(ev->xbutton.x, ev->xbutton.y); else if (ev->xbutton.button == Button2 || ev->xbutton.button == Button3) mouseRightButtonDown(ev->xbutton.x, ev->xbutton.y); break; case ButtonRelease: if (ev->xbutton.button == Button1) mouseLeftButtonUp(ev->xbutton.x, ev->xbutton.y); else if (ev->xbutton.button == Button2 || ev->xbutton.button == Button3) mouseRightButtonUp(ev->xbutton.x, ev->xbutton.y); break; case MotionNotify: mouseMove(ev->xmotion.x, ev->xmotion.y); break; case ConfigureNotify: resetParameters(); break; case ClientMessage: if ((((XClientMessageEvent *)ev)->message_type == atom_PROTOCOLS) && (((XClientMessageEvent *)ev)->data.l[0] == (long)atom_DELWIN)) done = 1; break; } } static void processEvents(Display *dpy, Window wnd) { XEvent event; int i; // check for incoming events XFlush(dpy); i = XPending(dpy); if (i > 0) { // get the next event in queue XNextEvent(dpy, &event); processEvent(dpy, wnd, &event); i--; for (; i > 0; --i) XNextEvent(dpy, &event); } } static Window createWindow(Display *dpy, const char *title, const unsigned int width, const unsigned int height) { Window wnd; int screen, screenDepth, screenWidth, screenHeight; Visual *screenVisual; XSetWindowAttributes windowAttributes; XSizeHints windowSizeHints; // get the default screen associated with the previously opened display screen = DefaultScreen(display); // get the default visual screenVisual = DefaultVisual(display, screen); // get screen bitdepth screenDepth = DefaultDepth(display, screen); // run only on a 32bpp display if (screenDepth != 24 && screenDepth != 32) return None; // initialize window's attribute structure windowAttributes.border_pixel = BlackPixel(display, screen); windowAttributes.background_pixel = 0xCCCCCCCC; windowAttributes.backing_store = NotUseful; // get screen dimensions screenWidth = DisplayWidth(display, screen); screenHeight = DisplayHeight(display, screen); // create the window centered on the screen if (width == 0 || height == 0) wnd = XCreateWindow(dpy, DefaultRootWindow(dpy), screenWidth / 4, screenHeight / 4, screenWidth / 2, screenHeight / 2, 0, screenDepth, InputOutput, screenVisual, CWBackPixel | CWBorderPixel | CWBackingStore, &windowAttributes); else wnd = XCreateWindow(dpy, DefaultRootWindow(dpy), (screenWidth - width) / 2, (screenHeight - height) / 2, width, height, 0, screenDepth, InputOutput, screenVisual, CWBackPixel | CWBorderPixel | CWBackingStore, &windowAttributes); // check for errors if (wnd == None) return None; // set the window's name XStoreName(dpy, wnd, title); // tell the server to report mouse and key-related events XSelectInput(dpy, wnd, KeyPressMask | KeyReleaseMask | ButtonPressMask | Button1MotionMask | Button2MotionMask | Button3MotionMask | StructureNotifyMask); // initialize window's sizehint definition structure windowSizeHints.flags = PPosition | PMinSize | PMaxSize; windowSizeHints.x = 0; windowSizeHints.y = 0; windowSizeHints.min_width = 1; windowSizeHints.max_width = screenWidth; windowSizeHints.min_height = 1; windowSizeHints.max_height = screenHeight; // set the window's sizehint XSetWMNormalHints(dpy, wnd, &windowSizeHints); // clear the window XClearWindow(dpy, wnd); // put the window on top of the others XMapRaised(dpy, wnd); // clear event queue XFlush(dpy); atom_DELWIN = XInternAtom(dpy, "WM_DELETE_WINDOW", False); atom_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False); XChangeProperty(dpy, wnd, atom_PROTOCOLS, XA_ATOM, 32, PropModeReplace, (unsigned char *)&atom_DELWIN, 1); return wnd; } static void killWindow(Display *dpy, Window wnd) { // close the window XDestroyWindow(dpy, wnd); // close the display XCloseDisplay(dpy); } static unsigned int getTimeMS(void) { struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); return (unsigned int)((tp.tv_sec * 1000) + (tp.tv_usec / 1000)); } static void updateTitle(Display *dpy, Window wnd) { // print frame rate every second time1 = getTimeMS(); if (time1 - time0 > 1000) { char title[64]; float fps = ((float)framesCount * 1000.0f / (float)(time1 - time0)); sprintf(title, "AmanithVG tiger - Press F1 for help - FPS: %6.2f", fps); XStoreName(dpy, wnd, title); framesCount = 0; time0 = time1; } } static void messageDialog(const char *title, const char *message) { fprintf(stderr, "%s: %s\n", title, message); } static unsigned int testEGLError(const char *msg) { EGLint err = eglGetError(); if (err != EGL_SUCCESS) { char errStr[64]; sprintf(errStr, "%s failed (%d)", msg, err); messageDialog("EGL error", errStr); return 0; } return 1; } static void destroyEGL(void) { eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (eglWindowSurface != EGL_NO_SURFACE) eglDestroySurface(eglDisplay, eglWindowSurface); #if defined(RENDERING_ON_VGIMAGE) if (eglPbufferSurface != EGL_NO_SURFACE) eglDestroySurface(eglDisplay, eglPbufferSurface); #endif if (eglContext != EGL_NO_CONTEXT) eglDestroyContext(eglDisplay, eglContext); eglTerminate(eglDisplay); } static unsigned int initEGL(Display *dpy, Window wnd) { EGLint iMajorVersion, iMinorVersion; int iConfigs; EGLint attribListWindow[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0, EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT, EGL_NONE }; #if defined(RENDERING_ON_VGIMAGE) EGLint attribListPbuffer[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT, EGL_NONE }; #endif // get the default display eglDisplay = eglGetDisplay((NativeDisplayType)dpy); if (eglDisplay == EGL_NO_DISPLAY) goto cleanup; // initialize EGL if (!eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion)) { messageDialog("EGL error", "eglInitialize failed."); goto cleanup; } // make OpenVG the current API eglBindAPI(EGL_OPENVG_API); // find a config that matches all requirements for the window surface if (!eglChooseConfig(eglDisplay, attribListWindow, &eglConfigWindow, 1, &iConfigs) || (iConfigs != 1)) { messageDialog("EGL error", "eglChooseConfig failed for window."); goto cleanup; } #if defined(RENDERING_ON_VGIMAGE) // find a config that matches all requirements for the pbuffer surface if (!eglChooseConfig(eglDisplay, attribListPbuffer, &eglConfigPbuffer, 1, &iConfigs) || (iConfigs != 1)) { messageDialog("EGL error", "eglChooseConfig failed for pbuffer."); goto cleanup; } #endif // create a window surface eglWindowSurface = eglCreateWindowSurface(eglDisplay, eglConfigWindow, (NativeWindowType)wnd, NULL); if (!testEGLError("eglCreateWindowSurface")) goto cleanup; // create a context eglContext = eglCreateContext(eglDisplay, eglConfigWindow, EGL_NO_CONTEXT, NULL); if (!testEGLError("eglCreateContext")) goto cleanup; // bind the context to the current thread and use our window surface for drawing and reading eglMakeCurrent(eglDisplay, eglWindowSurface, eglWindowSurface, eglContext); if (!testEGLError("eglMakeCurrent")) goto cleanup; #if defined(RENDERING_ON_VGIMAGE) { EGLint surfaceWidth, surfaceHeight; eglQuerySurface(eglDisplay, eglWindowSurface, EGL_WIDTH, &surfaceWidth); eglQuerySurface(eglDisplay, eglWindowSurface, EGL_HEIGHT, &surfaceHeight); destImg = vgCreateImage(VG_sARGB_8888_PRE, surfaceWidth, surfaceHeight, VG_IMAGE_QUALITY_BETTER); eglPbufferSurface = eglCreatePbufferFromClientBuffer(eglDisplay, EGL_OPENVG_IMAGE, (EGLClientBuffer)destImg, eglConfigPbuffer, NULL); if (!testEGLError("eglCreatePbufferFromClientBuffer")) goto cleanup; } #endif return 1; cleanup: destroyEGL(); return 0; } int main(void) { EGLint surfaceWidth, surfaceHeight; App = &vg_tiger_app; if (getenv("USECAIRO")) App = &cairo_tiger_app; // open the default display display = XOpenDisplay(NULL); if (display == NULL) { messageDialog("Error", "Unable to open display.\n"); return EXIT_FAILURE; } // create the window window = createWindow(display, "AmanithVG tiger - Press F1 for help - FPS: ", 480, 640); if (window == None) { messageDialog("Error", "Unable to create the main window"); XCloseDisplay(display); return EXIT_FAILURE; } // initialize EGL if (!initEGL(display, window)) { killWindow(display, window); return EXIT_FAILURE; } // init application eglQuerySurface(eglDisplay, eglWindowSurface, EGL_WIDTH, &surfaceWidth); eglQuerySurface(eglDisplay, eglWindowSurface, EGL_HEIGHT, &surfaceHeight); initApp(surfaceWidth, surfaceHeight); // start frame counter time0 = getTimeMS(); framesCount = 0; done = 0; while (!done) { processEvents(display, window); #if defined(RENDERING_ON_VGIMAGE) // get pbuffer surface dimensions eglQuerySurface(eglDisplay, eglPbufferSurface, EGL_WIDTH, &surfaceWidth); eglQuerySurface(eglDisplay, eglPbufferSurface, EGL_HEIGHT, &surfaceHeight); // make the pbuffer surface current eglMakeCurrent(eglDisplay, eglPbufferSurface, eglPbufferSurface, eglContext); drawScene(surfaceWidth, surfaceHeight); // make the window surface current eglMakeCurrent(eglDisplay, eglWindowSurface, eglWindowSurface, eglContext); // put the image vgSetPixels(0, 0, destImg, 0, 0, surfaceWidth, surfaceHeight); #else // get window surface dimensions eglQuerySurface(eglDisplay, eglWindowSurface, EGL_WIDTH, &surfaceWidth); eglQuerySurface(eglDisplay, eglWindowSurface, EGL_HEIGHT, &surfaceHeight); drawScene(surfaceWidth, surfaceHeight); #endif //eglSwapBuffers(eglDisplay, eglWindowSurface); // advance frames counter and update windiw title framesCount++; updateTitle(display, window); } killApp(); destroyEGL(); killWindow(display, window); return EXIT_SUCCESS; }