diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 446 |
1 files changed, 446 insertions, 0 deletions
@@ -0,0 +1,446 @@ +/**************************************************************************** +** 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 <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <EGL/egl.h> +#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 <VG/openvg.h> +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; +} |