/* Created by exoticorn ( http://talk.maemo.org/showthread.php?t=37356 ) * edited and commented by Andre Bergner [endboss] * * libraries needed: libx11-dev, libgles2-dev * * compile with: g++ cygwin-llvm.cpp -lX11 -lEGL -lGLESv2 */ #include #include #include using namespace std; #include #include #include #include #include #include #include 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; \ \ lowp mat2 octave_m= mat2(1.6,1.2,-1.2,1.6);\ \ lowp float sea_octave(lowp vec2 uv) {\ uv += uv.x;\ lowp vec2 wv = 1.0-abs(sin(uv));\ lowp vec2 swv = abs(cos(uv)); \ wv = mix(wv,swv,wv);\ return pow(1.0-pow(wv.x * wv.y,0.65),4.0);\ }\ \ lowp float map(lowp vec3 p) {\ lowp float freq = 0.16;\ lowp float amp = 0.6;\ lowp float choppy = 4.0;\ lowp vec2 uv = p.xz;\ \ lowp float d, h = 0.0; \ for(int i = 0; i < 20; i++) { \ d = sea_octave((uv+1.0)*0.16);\ d += sea_octave((uv-1.0)*0.16);\ h += d * amp + 1.0; \ uv *= octave_m; freq *= 1.9; amp *= 0.22;\ }\ return p.y - h;\ }\ \ lowp float heightMapTracing(){\ return map(vec3(1.0,1.0,1.0));\ }\ \ void mainImage( out lowp vec4 fragColor, in lowp vec2 fragCoord ) {\ lowp vec2 uv = fragCoord.xy / 5.0;\ lowp vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.15;\ heightMapTracing();\ lowp vec3 color = mix(\ dir,dir,\ pow(smoothstep(0.0,-0.05,dir.y),0.3));\ fragColor = vec4(pow(color,vec3(0.75)), 1.0);\ }\ \ void main() \ { \ lowp vec4 color = vec4(0.0,0.0,0.0,1.0);\ mainImage( color, gl_FragCoord.xy );\ gl_FragColor = color;\ } \ "; 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; EGLSurface egl_surface; 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; 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 // long xx[32], yy, zz; for (yy = zz = 0; yy < 48; yy++) { if ( yy % 2 ) xx[zz++] = yy; } 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 | KeyPressMask; 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", False ), XA_INTEGER, 32, PropModeReplace, (unsigned char*) &one, 1); XWMHints hints; hints.input = True; hints.flags = InputHint; XSetWMHints(x_display, win, &hints); 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, 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" ); if ( position_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; } 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; }