SimpleGL example

(reorganized and commented the code)
Line 1: Line 1:
-
  /* Created by exoticorn (http://talk.maemo.org/showthread.php?t=37356 */
+
  /* Created by exoticorn ( http://talk.maemo.org/showthread.php?t=37356 )
-
#include <stdio.h>
+
  * edited and commented by André Bergner [endboss]
-
#include <stdlib.h>
+
  *
-
#include <X11/Xatom.h>
+
  * librariries needed:  libx11-dev, libgles2-dev
-
  #include <X11/Xlib.h>
+
  *
-
  #include <X11/Xutil.h>
+
  * compile with:  g++ -lX11 -lEGL -lGLESv2 egl-example.cpp
-
#include <GLES2/gl2.h>
+
  */
-
#include <EGL/egl.h>
+
-
#include <math.h>
+
-
#include <sys/time.h>
+
-
#include <unistd.h>
+
-
#include <string.h>
+
   
   
-
  const char* vertexSrc = "attribute vec4 position; varying mediump vec2 pos; uniform vec4 offset; void main() { gl_Position = position + offset; pos = position.xy; }";
+
  #include  <iostream>
-
  const char* fragmentSrc = "varying mediump vec2 pos; uniform mediump float phase; void main() { gl_FragColor = vec4(1, 1, 1, 1) * sin((pos.x * pos.x + pos.y * pos.y) * 40.0 + phase); }";
+
  using namespace std;
   
   
-
  void printShaderInfoLog(GLuint shader) {
+
  #include  <cmath>
-
        GLint length;
+
#include  <sys/time.h>
-
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
+
-
        if(length) {
+
#include  <X11/Xlib.h>
-
                char* buffer = new char[length];
+
#include  <X11/Xatom.h>
-
                glGetShaderInfoLog(shader, length, NULL, buffer);
+
-
                printf("%s", buffer);
+
#include  <GLES2/gl2.h>
-
                delete [] buffer;
+
#include  <EGL/egl.h>
-
                GLint success;
+
-
                glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
+
-
                if(success != GL_TRUE) {
+
-
                        exit(1);
+
const char vertex_src [] =
-
                }
+
"                                        \
-
        }
+
    attribute vec4        position;      \
 +
    varying mediump vec2  pos;            \
 +
    uniform vec4          offset;        \
 +
                                          \
 +
    void main()                          \
 +
    {                                    \
 +
      gl_Position = position + offset;  \
 +
      pos = position.xy;                \
 +
    }                                    \
 +
";
 +
 +
 +
const char fragment_src [] =
 +
"                                                      \
 +
    varying mediump vec2    pos;                        \
 +
    uniform mediump float  phase;                      \
 +
                                                        \
 +
    void  main()                                        \
 +
    {                                                  \
 +
      gl_FragColor  =  vec4( 1., 0.9, 0.7, 1.0 ) *    \
 +
        cos( 30.*sqrt(pos.x*pos.x + 1.5*pos.y*pos.y)  \
 +
              + atan(pos.y,pos.x) - phase );            \
 +
    }                                                  \
 +
";
 +
//  some more formulas to play with...
 +
//      cos( 20.*(pos.x*pos.x + pos.y*pos.y) - phase );
 +
//      cos( 20.*sqrt(pos.x*pos.x + pos.y*pos.y) + atan(pos.y,pos.x) - phase );
 +
//      cos( 30.*sqrt(pos.x*pos.x + 1.5*pos.y*pos.y - 1.8*pos.x*pos.y*pos.y)
 +
//            + atan(pos.y,pos.x) - phase );
 +
 +
 +
void
 +
print_shader_info_log (
 +
    GLuint shader     // handle to the shader
 +
)
 +
{
 +
    GLint length;
 +
 +
    glGetShaderiv ( shader , GL_INFO_LOG_LENGTH , &length );
 +
 +
    if ( length ) {
 +
      char* buffer = new char [ length ];
 +
      glGetShaderInfoLog ( shader , length , NULL , buffer );
 +
      cout << "shader info: " <<  buffer << flush;
 +
      delete [] buffer;
 +
 +
      GLint success;
 +
      glGetShaderiv( shader, GL_COMPILE_STATUS, &success );
 +
      if ( success != GL_TRUE )   exit ( 1 );
 +
    }
  }
  }
   
   
-
  GLuint createShader(GLenum type, const char* pSource) {
+
-
        GLuint shader = glCreateShader(type);
+
  GLuint
-
        glShaderSource(shader, 1, &pSource, NULL);
+
load_shader (
-
        glCompileShader(shader);
+
    const char *shader_source,
-
        printShaderInfoLog(shader);
+
    GLenum      type
-
        return shader;
+
)
 +
{
 +
    GLuint shader = glCreateShader( type );
 +
 +
    glShaderSource ( shader , 1 , &shader_source , NULL );
 +
    glCompileShader ( shader );
 +
 +
    print_shader_info_log ( shader );
 +
 +
    return shader;
  }
  }
   
   
-
Display* dpy;
 
-
Window win;
 
-
EGLDisplay edpy;
 
-
EGLContext ectxt;
 
-
int phaseLocation;
 
-
GLfloat norm_x;
 
-
GLfloat norm_y;
 
-
GLfloat offset_x = 0.0;
 
-
GLfloat offset_y = 0.0;
 
-
GLfloat p1_pos_x;
 
-
GLfloat p1_pos_y;
 
   
   
-
  GLint offset;
+
Display    *x_display;
-
  EGLSurface esfc;
+
Window      win;
-
  bool update_pos = false;
+
EGLDisplay  egl_display;
 +
EGLContext  egl_context;
 +
 +
GLfloat
 +
    norm_x    =  0.0,
 +
    norm_y    =  0.0,
 +
    offset_x  =  0.0,
 +
    offset_y  =  0.0,
 +
    p1_pos_x  =  0.0,
 +
    p1_pos_y  =  0.0;
 +
 +
  GLint
 +
    phase_loc,
 +
    offset_loc,
 +
    position_loc;
 +
 +
 +
  EGLSurface egl_surface;
 +
  bool       update_pos = false;
   
   
  const float vertexArray[] = {
  const float vertexArray[] = {
-
        -0.85, -1, 0, 1,
+
    0.0, 0.5,  0.0,
-
        -1, -0.7, 0, 1,
+
  -0.5, 0.0, 0.0,
-
        -0.7, -0.7, 0, 1
+
    0.0, -0.5, 0.0,
 +
    0.5, 0.0, 0.0,
 +
    0.0,  0.5,  0.0
  };
  };
   
   
-
void render() {
 
-
                static float offset_blah = 0;
 
-
                static int donesetup=0;
 
-
                static XWindowAttributes gwa;
 
   
   
-
                // draw
+
void  render()
 +
{
 +
    static float  phase = 0;
 +
    static int    donesetup = 0;
   
   
-
                if (!donesetup) {
+
    static XWindowAttributes gwa;
-
                        XWindowAttributes gwa;
+
-
                        XGetWindowAttributes(dpy, win, &gwa);
+
-
                        glViewport(0, 0, gwa.width, gwa.height);
+
-
                        glClearColor(0, 1, 0, 1);
+
-
                        donesetup = 1;
+
-
                }
+
-
                glClear(GL_COLOR_BUFFER_BIT);
+
   
   
-
                glUniform1f(phaseLocation, offset_blah);
+
    //// draw
   
   
-
                if (update_pos) {
+
    if ( !donesetup ) {
-
                        GLfloat old_offset_x = offset_x;
+
      XWindowAttributes  gwa;
-
                        GLfloat old_offset_y = offset_y;
+
      XGetWindowAttributes ( x_display , win , &gwa );
 +
      glViewport ( 0 , 0 , gwa.width , gwa.height );
 +
      glClearColor ( 0.08 , 0.06 , 0.07 , 1.);    // background color
 +
      donesetup = 1;
 +
    }
 +
    glClear ( GL_COLOR_BUFFER_BIT );
   
   
-
                offset_x = norm_x - p1_pos_x;
+
    glUniform1f ( phase_loc , phase ); // write the value of phase to the shaders phase
-
                offset_y = norm_y - p1_pos_y;
+
    phase  = fmodf ( phase + 0.5f , 2.f * 3.141f );   // and update the local variable
   
   
-
                        p1_pos_x = norm_x;
+
    if ( update_pos ) {  // if the position of the texture has changed due to user action
-
                        p1_pos_y = norm_y;
+
      GLfloat old_offset_x  = offset_x;
 +
      GLfloat old_offset_y  = offset_y;
   
   
-
                        offset_x += old_offset_x;
+
      offset_x = norm_x - p1_pos_x;
-
                        offset_y += old_offset_y;
+
      offset_y = norm_y - p1_pos_y;
   
   
-
                        update_pos = false;
+
      p1_pos_x  = norm_x;
-
                }
+
      p1_pos_y  =  norm_y;
   
   
-
                glUniform4f(offset, offset_x, offset_y, 0, 0);
+
      offset_x +=  old_offset_x;
 +
      offset_y +=  old_offset_y;
   
   
-
                glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, vertexArray);
+
      update_pos = false;
-
                glEnableVertexAttribArray(0);
+
    }
-
                glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+
   
   
-
                eglSwapBuffers(edpy, esfc);
+
    glUniform4f ( offset_loc  , offset_x , offset_y , 0.0 , 0.0 );
   
   
-
                offset_blah = fmodf(offset_blah + 0.5, 2*3.141f);
+
    glVertexAttribPointer ( position_loc, 3, GL_FLOAT, false, 0, vertexArray );
 +
    glEnableVertexAttribArray ( position_loc );
 +
    glDrawArrays ( GL_TRIANGLE_STRIP, 0, 5 );
 +
 +
    eglSwapBuffers ( egl_display, egl_surface ); // get the rendered buffer to the screen
  }
  }
   
   
-
int main() {
 
-
        dpy = XOpenDisplay(NULL);
 
-
        if(dpy == NULL) {
 
-
                printf("cannot connect to X server\n");
 
-
                return 1;
 
-
        }
 
   
   
-
        Window root = DefaultRootWindow(dpy);
+
////////////////////////////////////////////////////////////////////////////////////////////
   
   
-
        XSetWindowAttributes swa;
 
-
        swa.event_mask = ExposureMask | PointerMotionMask;
 
   
   
-
        win = XCreateWindow(dpy, root, 0, 0, 600, 400, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask, &swa);
+
int  main()
 +
{
 +
    ///////  the X11 part  //////////////////////////////////////////////////////////////////
 +
    // in the first part the program opens a connection to the X11 window manager
 +
    //
   
   
-
        XSetWindowAttributes xattr;
+
    x_display = XOpenDisplay ( NULL );   // open the standard display (the primary screen)
-
        Atom atom;
+
    if ( x_display == NULL ) {
-
        int one = 1;
+
      cerr << "cannot connect to X server" << endl;
 +
      return 1;
 +
    }
   
   
-
        xattr.override_redirect = False;
+
    Window root  = DefaultRootWindow( x_display );   // get the root window (usually the whole screen)
-
        XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &xattr);
+
   
   
-
        atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", True);
+
    XSetWindowAttributes  swa;
-
        XChangeProperty(dpy, win, XInternAtom(dpy, "_NET_WM_STATE", True),
+
    swa.event_mask  =  ExposureMask | PointerMotionMask;
-
                XA_ATOM, 32, PropModeReplace,
+
-
                (unsigned char *) &atom, 1);
+
   
   
-
        XChangeProperty(dpy, win, XInternAtom(dpy, "_HILDON_NON_COMPOSITED_WINDOW", True),
+
    win  =  XCreateWindow (         // create a window with the provided parameters
-
                XA_INTEGER, 32, PropModeReplace,
+
              x_display, root,
-
                (unsigned char *) &one, 1);
+
              0, 0, 800, 480,  0,
 +
              CopyFromParent, InputOutput,
 +
              CopyFromParent, CWEventMask,
 +
              &swa );
   
   
-
        XMapWindow(dpy, win);
+
    XSetWindowAttributes  xattr;
 +
    Atom  atom;
 +
    int  one = 1;
   
   
-
        XStoreName(dpy, win, "GL test");
+
    xattr.override_redirect = False;
 +
    XChangeWindowAttributes ( x_display, win, CWOverrideRedirect, &xattr );
   
   
-
        Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
+
    atom = XInternAtom ( x_display, "_NET_WM_STATE_FULLSCREEN", True );
-
        Atom fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+
    XChangeProperty (
 +
      x_display, win,
 +
      XInternAtom ( x_display, "_NET_WM_STATE", True ),
 +
      XA_ATOM,  32,  PropModeReplace,
 +
      (unsigned char*) &atom,  1 );
   
   
-
        XEvent xev;
+
    XChangeProperty (
-
        memset(&xev, 0, sizeof(xev));
+
      x_display, win,
-
        xev.type = ClientMessage;
+
      XInternAtom ( x_display, "_HILDON_NON_COMPOSITED_WINDOW", True ),
-
        xev.xclient.window = win;
+
      XA_INTEGER,  32,  PropModeReplace,
-
        xev.xclient.message_type = wm_state;
+
      (unsigned char*) &one, 1);
-
        xev.xclient.format = 32;
+
-
        xev.xclient.data.l[0] = 1;
+
-
        xev.xclient.data.l[1] = fullscreen;
+
-
        XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask, &xev);
+
   
   
-
        edpy = eglGetDisplay((EGLNativeDisplayType)dpy);
+
    XMapWindow ( x_display , win );             // make the window visible on the screen
-
        if(edpy == EGL_NO_DISPLAY) {
+
    XStoreName ( x_display , win , "GL test" ); // give the window a name
-
                printf("Got no EGL display\n");
+
-
                return 1;
+
-
        }
+
   
   
-
        if(!eglInitialize(edpy, NULL, NULL)) {
+
    //// get identifiers for the provided atom name strings
-
                printf("Unable to initialize EGL\n");
+
    Atom wm_state  = XInternAtom ( x_display, "_NET_WM_STATE", False );
-
                return 1;
+
    Atom fullscreen = XInternAtom ( x_display, "_NET_WM_STATE_FULLSCREEN", False );
-
        }
+
   
   
-
        EGLint attr[] = {
+
    XEvent xev;
-
                EGL_BUFFER_SIZE, 16,
+
    memset ( &xev, 0, sizeof(xev) );
-
                EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+
-
                EGL_NONE
+
-
        };
+
   
   
-
        EGLConfig ecfg;
+
    xev.type                = ClientMessage;
-
        EGLint num_config;
+
    xev.xclient.window      = win;
-
        if(!eglChooseConfig(edpy, attr, &ecfg, 1, &num_config)) {
+
    xev.xclient.message_type = wm_state;
-
                printf("Failed to choose config (%x)\n", eglGetError());
+
    xev.xclient.format      = 32;
-
                return 1;
+
    xev.xclient.data.l[0]    = 1;
-
        }
+
    xev.xclient.data.l[1]    = fullscreen;
-
        if(num_config != 1) {
+
    XSendEvent (               // send an event mask to the X-server
-
                printf("Didn't get exactly one config, but %d\n", num_config);
+
      x_display,
-
                return 1;
+
      DefaultRootWindow ( x_display ),
-
        }
+
      False,
 +
      SubstructureNotifyMask,
 +
      &xev );
   
   
-
        esfc = eglCreateWindowSurface(edpy, ecfg, (void*)win, NULL);
 
-
        if(esfc == EGL_NO_SURFACE) {
 
-
                printf("Unable to create EGL surface (%x)\n", eglGetError());
 
-
                return 1;
 
-
        }
 
   
   
-
        EGLint ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+
    ///////  the egl part  //////////////////////////////////////////////////////////////////
-
        ectxt = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, ctxattr);
+
    //  egl provides an interface to connect the graphics related functionality of openGL ES
-
        if(ectxt == EGL_NO_CONTEXT) {
+
    //  with the windowing interface and functionality of the native operation system (X11
-
                printf("Unable to create EGL context (%x)\n", eglGetError());
+
    //  in our case.
-
                return 1;
+
-
        }
+
-
        eglMakeCurrent(edpy, esfc, esfc, ectxt);
+
   
   
-
        GLuint shaderProgram = glCreateProgram();
+
    egl_display  = eglGetDisplay( (EGLNativeDisplayType) x_display );
-
        GLuint vertexShader = createShader(GL_VERTEX_SHADER, vertexSrc);
+
    if ( egl_display == EGL_NO_DISPLAY ) {
-
        GLuint fragmentShader = createShader(GL_FRAGMENT_SHADER, fragmentSrc);
+
      cerr << "Got no EGL display." << endl;
 +
      return 1;
 +
    }
   
   
-
        glAttachShader(shaderProgram, vertexShader);
+
    if ( !eglInitialize( egl_display, NULL, NULL ) ) {
-
        glAttachShader(shaderProgram, fragmentShader);
+
      cerr << "Unable to initialize EGL" << endl;
 +
      return 1;
 +
    }
   
   
-
        glLinkProgram(shaderProgram);
+
    EGLint attr[] = {      // some attributes to set up our egl-interface
 +
      EGL_BUFFER_SIZE, 16,
 +
      EGL_RENDERABLE_TYPE,
 +
      EGL_OPENGL_ES2_BIT,
 +
      EGL_NONE
 +
    };
   
   
-
        glUseProgram(shaderProgram);
+
    EGLConfig  ecfg;
 +
    EGLint    num_config;
 +
    if ( !eglChooseConfig( egl_display, attr, &ecfg, 1, &num_config ) ) {
 +
      cerr << "Failed to choose config (eglError: " << eglGetError() << ")" << endl;
 +
      return 1;
 +
    }
   
   
-
        phaseLocation = glGetUniformLocation(shaderProgram, "phase");
+
    if ( num_config != 1 ) {
-
        offset = glGetUniformLocation(shaderProgram, "offset");
+
      cerr << "Didn't get exactly one config, but " << num_config << endl;
-
        if(phaseLocation < 0) {
+
      return 1;
-
                printf("Unable to get uniform location\n");
+
    }
-
                return 1;
+
-
        }
+
   
   
-
        bool quit = false;
+
    egl_surface = eglCreateWindowSurface ( egl_display, ecfg, (void*)win, NULL );
 +
    if ( egl_surface == EGL_NO_SURFACE ) {
 +
      cerr << "Unable to create EGL surface (eglError: " << eglGetError() << ")" << endl;
 +
      return 1;
 +
    }
   
   
-
        timeval startTime;
+
    //// egl-contexts collect all state descriptions needed required for operation
-
        timezone tz;
+
    EGLint ctxattr[] = {
-
        gettimeofday(&startTime, &tz);
+
      EGL_CONTEXT_CLIENT_VERSION, 2,
-
        int numFrames = 0;
+
      EGL_NONE
 +
    };
 +
    egl_context = eglCreateContext ( egl_display, ecfg, EGL_NO_CONTEXT, ctxattr );
 +
    if ( egl_context == EGL_NO_CONTEXT ) {
 +
      cerr << "Unable to create EGL context (eglError: " << eglGetError() << ")" << endl;
 +
      return 1;
 +
    }
   
   
-
        float window_width = 800.0;
+
    //// associate the egl-context with the egl-surface
-
        float window_height = 480.0;
+
    eglMakeCurrent( egl_display, egl_surface, egl_surface, egl_context );
   
   
-
        norm_x = -0.85;
 
-
        norm_y = -1;
 
-
        p1_pos_x = -0.85;
 
-
        p1_pos_y = -1;
 
   
   
 +
    ///////  the openGL part  ///////////////////////////////////////////////////////////////
   
   
 +
    GLuint vertexShader  = load_shader ( vertex_src , GL_VERTEX_SHADER  );    // load vertex shader
 +
    GLuint fragmentShader = load_shader ( fragment_src , GL_FRAGMENT_SHADER );  // load fragment shader
   
   
-
        while(!quit) {
+
    GLuint shaderProgram  = glCreateProgram ();                // create program object
 +
    glAttachShader ( shaderProgram, vertexShader );            // and attach both...
 +
    glAttachShader ( shaderProgram, fragmentShader );          // ... shaders to it
   
   
-
                while(XPending(dpy)) {
+
    glLinkProgram ( shaderProgram );   // link the program
-
                        XEvent xev;
+
    glUseProgram  ( shaderProgram );   // and select it for usage
-
                        XNextEvent(dpy, &xev);
+
   
   
-
                        if(xev.type == MotionNotify) {
+
    //// now get the locations (kind of handle) of the shaders variables
-
                                //printf("move to: (%d,%d)\n", xev.xmotion.x, xev.xmotion.y);
+
    position_loc  = glGetAttribLocation  ( shaderProgram , "position" );
-
                            GLfloat window_y = (window_height - xev.xmotion.y) - window_height / 2.0;
+
    phase_loc    = glGetUniformLocation ( shaderProgram , "phase"    );
-
                            norm_y = window_y / (window_height / 2.0);
+
    offset_loc    = glGetUniformLocation ( shaderProgram , "offset"  );
-
                            GLfloat window_x = xev.xmotion.x - window_width / 2.0;
+
    if ( position_loc < 0  ||  phase_loc < 0  ||  offset_loc < 0 ) {
-
                            norm_x = window_x / (window_width / 2.0);
+
      cerr << "Unable to get uniform location" << endl;
-
                                update_pos = true;
+
      return 1;
-
                                //quit = true;
+
    }
-
                        }
+
-
                }
+
-
                                render();
+
-
                                numFrames++;
+
-
                                if(numFrames % 100 == 0) {
+
-
                                        timeval now;
+
-
                                        gettimeofday(&now, &tz);
+
-
                                        float delta = now.tv_sec - startTime.tv_sec + (now.tv_usec - startTime.tv_usec) * 0.000001f;
+
-
                                        printf("fps: %f\n", numFrames / delta);
+
-
                                }
+
   
   
-
                                usleep(1000*30);
 
-
        }
 
   
   
-
        eglDestroyContext(edpy, ectxt);
+
    const float
-
        eglDestroySurface(edpy, esfc);
+
      window_width  = 800.0,
-
        eglTerminate(edpy);
+
      window_height = 480.0;
-
        XDestroyWindow(dpy, win);
+
-
        XCloseDisplay(dpy);
+
   
   
-
        return 0;
+
    //// this is needed for time measuring  -->  frames per second
 +
    struct  timezone  tz;
 +
    timeval  t1, t2;
 +
    gettimeofday ( &t1 , &tz );
 +
    int  num_frames = 0;
 +
 +
    bool quit = false;
 +
    while ( !quit ) {    // the main loop
 +
 +
      while ( XPending ( x_display ) ) {  // check for events from the x-server
 +
 +
          XEvent  xev;
 +
          XNextEvent( x_display, &xev );
 +
 +
          if ( xev.type == MotionNotify ) {  // if mouse has moved
 +
//            cout << "move to: << xev.xmotion.x << "," << xev.xmotion.y << endl;
 +
            GLfloat window_y  =  (window_height - xev.xmotion.y) - window_height / 2.0;
 +
            norm_y            =  window_y / (window_height / 2.0);
 +
            GLfloat window_x  =  xev.xmotion.x - window_width / 2.0;
 +
            norm_x            =  window_x / (window_width / 2.0);
 +
            update_pos = true;
 +
          }
 +
 +
//        if ( xev.type == KeyPress )  quit = true;  // doesn't work ???
 +
      }
 +
 +
      render();  // now we finally put something on the screen
 +
 +
      if ( ++num_frames % 100 == 0 ) {
 +
          gettimeofday( &t2, &tz );
 +
          float dt  =  t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6;
 +
          cout << "fps: " << num_frames / dt << endl;
 +
          num_frames = 0;
 +
          t1 = t2;
 +
      }
 +
//      usleep( 1000*10 );
 +
    }
 +
 +
 +
    ////  cleaning up...
 +
    eglDestroyContext ( egl_display, egl_context );
 +
    eglDestroySurface ( egl_display, egl_surface );
 +
    eglTerminate      ( egl_display );
 +
    XDestroyWindow    ( x_display, win );
 +
    XCloseDisplay    ( x_display );
 +
 +
    return 0;
  }
  }
-
 
+
[[Category:Development]]
[[Category:Development]]
[[Category:Fremantle]]
[[Category:Fremantle]]

Revision as of 11:53, 17 February 2010

/* Created by exoticorn ( http://talk.maemo.org/showthread.php?t=37356 )
 * edited and commented by André Bergner [endboss]
 *
 * librariries needed:   libx11-dev, libgles2-dev
 *
 * compile with:   g++  -lX11 -lEGL -lGLESv2  egl-example.cpp
 */

#include  <iostream>
using namespace std;

#include  <cmath>
#include  <sys/time.h>

#include  <X11/Xlib.h>
#include  <X11/Xatom.h>

#include  <GLES2/gl2.h>
#include  <EGL/egl.h>



const char vertex_src [] =
"                                        \
   attribute vec4        position;       \
   varying mediump vec2  pos;            \
   uniform vec4          offset;         \
                                         \
   void main()                           \
   {                                     \
      gl_Position = position + offset;   \
      pos = position.xy;                 \
   }                                     \
";


const char fragment_src [] =
"                                                      \
   varying mediump vec2    pos;                        \
   uniform mediump float   phase;                      \
                                                       \
   void  main()                                        \
   {                                                   \
      gl_FragColor  =  vec4( 1., 0.9, 0.7, 1.0 ) *     \
        cos( 30.*sqrt(pos.x*pos.x + 1.5*pos.y*pos.y)   \
             + atan(pos.y,pos.x) - phase );            \
   }                                                   \
";
//  some more formulas to play with...
//      cos( 20.*(pos.x*pos.x + pos.y*pos.y) - phase );
//      cos( 20.*sqrt(pos.x*pos.x + pos.y*pos.y) + atan(pos.y,pos.x) - phase );
//      cos( 30.*sqrt(pos.x*pos.x + 1.5*pos.y*pos.y - 1.8*pos.x*pos.y*pos.y)
//            + atan(pos.y,pos.x) - phase );


void
print_shader_info_log (
   GLuint  shader      // handle to the shader
)
{
   GLint  length;

   glGetShaderiv ( shader , GL_INFO_LOG_LENGTH , &length );

   if ( length ) {
      char* buffer  =  new char [ length ];
      glGetShaderInfoLog ( shader , length , NULL , buffer );
      cout << "shader info: " <<  buffer << flush;
      delete [] buffer;

      GLint success;
      glGetShaderiv( shader, GL_COMPILE_STATUS, &success );
      if ( success != GL_TRUE )   exit ( 1 );
   }
}


GLuint
load_shader (
   const char  *shader_source,
   GLenum       type
)
{
   GLuint  shader = glCreateShader( type );

   glShaderSource  ( shader , 1 , &shader_source , NULL );
   glCompileShader ( shader );

   print_shader_info_log ( shader );

   return shader;
}


Display    *x_display;
Window      win;
EGLDisplay  egl_display;
EGLContext  egl_context;

GLfloat
   norm_x    =  0.0,
   norm_y    =  0.0,
   offset_x  =  0.0,
   offset_y  =  0.0,
   p1_pos_x  =  0.0,
   p1_pos_y  =  0.0;

GLint
   phase_loc,
   offset_loc,
   position_loc;


EGLSurface  egl_surface;
bool        update_pos = false;

const float vertexArray[] = {
   0.0,  0.5,  0.0,
  -0.5,  0.0,  0.0,
   0.0, -0.5,  0.0,
   0.5,  0.0,  0.0,
   0.0,  0.5,  0.0 
};


void  render()
{
   static float  phase = 0;
   static int    donesetup = 0;

   static XWindowAttributes gwa;

   //// draw

   if ( !donesetup ) {
      XWindowAttributes  gwa;
      XGetWindowAttributes ( x_display , win , &gwa );
      glViewport ( 0 , 0 , gwa.width , gwa.height );
      glClearColor ( 0.08 , 0.06 , 0.07 , 1.);    // background color
      donesetup = 1;
   }
   glClear ( GL_COLOR_BUFFER_BIT );

   glUniform1f ( phase_loc , phase );  // write the value of phase to the shaders phase
   phase  =  fmodf ( phase + 0.5f , 2.f * 3.141f );    // and update the local variable

   if ( update_pos ) {  // if the position of the texture has changed due to user action
      GLfloat old_offset_x  =  offset_x;
      GLfloat old_offset_y  =  offset_y;

      offset_x  =  norm_x - p1_pos_x;
      offset_y  =  norm_y - p1_pos_y;

      p1_pos_x  =  norm_x;
      p1_pos_y  =  norm_y;

      offset_x  +=  old_offset_x;
      offset_y  +=  old_offset_y;

      update_pos = false;
   }

   glUniform4f ( offset_loc  ,  offset_x , offset_y , 0.0 , 0.0 );

   glVertexAttribPointer ( position_loc, 3, GL_FLOAT, false, 0, vertexArray );
   glEnableVertexAttribArray ( position_loc );
   glDrawArrays ( GL_TRIANGLE_STRIP, 0, 5 );

   eglSwapBuffers ( egl_display, egl_surface );  // get the rendered buffer to the screen
}


////////////////////////////////////////////////////////////////////////////////////////////


int  main()
{
   ///////  the X11 part  //////////////////////////////////////////////////////////////////
   // in the first part the program opens a connection to the X11 window manager
   //

   x_display = XOpenDisplay ( NULL );   // open the standard display (the primary screen)
   if ( x_display == NULL ) {
      cerr << "cannot connect to X server" << endl;
      return 1;
   }

   Window root  =  DefaultRootWindow( x_display );   // get the root window (usually the whole screen)

   XSetWindowAttributes  swa;
   swa.event_mask  =  ExposureMask | PointerMotionMask;

   win  =  XCreateWindow (          // create a window with the provided parameters
              x_display, root,
              0, 0, 800, 480,   0,
              CopyFromParent, InputOutput,
              CopyFromParent, CWEventMask,
              &swa );

   XSetWindowAttributes  xattr;
   Atom  atom;
   int   one = 1;

   xattr.override_redirect = False;
   XChangeWindowAttributes ( x_display, win, CWOverrideRedirect, &xattr );

   atom = XInternAtom ( x_display, "_NET_WM_STATE_FULLSCREEN", True );
   XChangeProperty (
      x_display, win,
      XInternAtom ( x_display, "_NET_WM_STATE", True ),
      XA_ATOM,  32,  PropModeReplace,
      (unsigned char*) &atom,  1 );

   XChangeProperty (
      x_display, win,
      XInternAtom ( x_display, "_HILDON_NON_COMPOSITED_WINDOW", True ),
      XA_INTEGER,  32,  PropModeReplace,
      (unsigned char*) &one,  1);

   XMapWindow ( x_display , win );             // make the window visible on the screen
   XStoreName ( x_display , win , "GL test" ); // give the window a name

   //// get identifiers for the provided atom name strings
   Atom wm_state   = XInternAtom ( x_display, "_NET_WM_STATE", False );
   Atom fullscreen = XInternAtom ( x_display, "_NET_WM_STATE_FULLSCREEN", False );

   XEvent xev;
   memset ( &xev, 0, sizeof(xev) );

   xev.type                 = ClientMessage;
   xev.xclient.window       = win;
   xev.xclient.message_type = wm_state;
   xev.xclient.format       = 32;
   xev.xclient.data.l[0]    = 1;
   xev.xclient.data.l[1]    = fullscreen;
   XSendEvent (                // send an event mask to the X-server
      x_display,
      DefaultRootWindow ( x_display ),
      False,
      SubstructureNotifyMask,
      &xev );


   ///////  the egl part  //////////////////////////////////////////////////////////////////
   //  egl provides an interface to connect the graphics related functionality of openGL ES
   //  with the windowing interface and functionality of the native operation system (X11
   //  in our case.

   egl_display  =  eglGetDisplay( (EGLNativeDisplayType) x_display );
   if ( egl_display == EGL_NO_DISPLAY ) {
      cerr << "Got no EGL display." << endl;
      return 1;
   }

   if ( !eglInitialize( egl_display, NULL, NULL ) ) {
      cerr << "Unable to initialize EGL" << endl;
      return 1;
   }

   EGLint attr[] = {       // some attributes to set up our egl-interface
      EGL_BUFFER_SIZE, 16,
      EGL_RENDERABLE_TYPE,
      EGL_OPENGL_ES2_BIT,
      EGL_NONE
   };

   EGLConfig  ecfg;
   EGLint     num_config;
   if ( !eglChooseConfig( egl_display, attr, &ecfg, 1, &num_config ) ) {
      cerr << "Failed to choose config (eglError: " << eglGetError() << ")" << endl;
      return 1;
   }

   if ( num_config != 1 ) {
      cerr << "Didn't get exactly one config, but " << num_config << endl;
      return 1;
   }

   egl_surface = eglCreateWindowSurface ( egl_display, ecfg, (void*)win, NULL );
   if ( egl_surface == EGL_NO_SURFACE ) {
      cerr << "Unable to create EGL surface (eglError: " << eglGetError() << ")" << endl;
      return 1;
   }

   //// egl-contexts collect all state descriptions needed required for operation
   EGLint ctxattr[] = {
      EGL_CONTEXT_CLIENT_VERSION, 2,
      EGL_NONE
   };
   egl_context = eglCreateContext ( egl_display, ecfg, EGL_NO_CONTEXT, ctxattr );
   if ( egl_context == EGL_NO_CONTEXT ) {
      cerr << "Unable to create EGL context (eglError: " << eglGetError() << ")" << endl;
      return 1;
   }

   //// associate the egl-context with the egl-surface
   eglMakeCurrent( egl_display, egl_surface, egl_surface, egl_context );


   ///////  the openGL part  ///////////////////////////////////////////////////////////////

   GLuint vertexShader   = load_shader ( vertex_src , GL_VERTEX_SHADER  );     // load vertex shader
   GLuint fragmentShader = load_shader ( fragment_src , GL_FRAGMENT_SHADER );  // load fragment shader

   GLuint shaderProgram  = glCreateProgram ();                 // create program object
   glAttachShader ( shaderProgram, vertexShader );             // and attach both...
   glAttachShader ( shaderProgram, fragmentShader );           // ... shaders to it

   glLinkProgram ( shaderProgram );    // link the program
   glUseProgram  ( shaderProgram );    // and select it for usage

   //// now get the locations (kind of handle) of the shaders variables
   position_loc  = glGetAttribLocation  ( shaderProgram , "position" );
   phase_loc     = glGetUniformLocation ( shaderProgram , "phase"    );
   offset_loc    = glGetUniformLocation ( shaderProgram , "offset"   );
   if ( position_loc < 0  ||  phase_loc < 0  ||  offset_loc < 0 ) {
      cerr << "Unable to get uniform location" << endl;
      return 1;
   }


   const float
      window_width  = 800.0,
      window_height = 480.0;

   //// this is needed for time measuring  -->  frames per second
   struct  timezone  tz;
   timeval  t1, t2;
   gettimeofday ( &t1 , &tz );
   int  num_frames = 0;

   bool quit = false;
   while ( !quit ) {    // the main loop

      while ( XPending ( x_display ) ) {   // check for events from the x-server

         XEvent  xev;
         XNextEvent( x_display, &xev );

         if ( xev.type == MotionNotify ) {  // if mouse has moved
//            cout << "move to: << xev.xmotion.x << "," << xev.xmotion.y << endl;
            GLfloat window_y  =  (window_height - xev.xmotion.y) - window_height / 2.0;
            norm_y            =  window_y / (window_height / 2.0);
            GLfloat window_x  =  xev.xmotion.x - window_width / 2.0;
            norm_x            =  window_x / (window_width / 2.0);
            update_pos = true;
         }

//         if ( xev.type == KeyPress )   quit = true;  // doesn't work ???
      }

      render();   // now we finally put something on the screen

      if ( ++num_frames % 100 == 0 ) {
         gettimeofday( &t2, &tz );
         float dt  =  t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6;
         cout << "fps: " << num_frames / dt << endl;
         num_frames = 0;
         t1 = t2;
      }
//      usleep( 1000*10 );
   }


   ////  cleaning up...
   eglDestroyContext ( egl_display, egl_context );
   eglDestroySurface ( egl_display, egl_surface );
   eglTerminate      ( egl_display );
   XDestroyWindow    ( x_display, win );
   XCloseDisplay     ( x_display );

   return 0;
}